3 * Routines for marshaling complex types in P/Invoke methods.
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #include "metadata/marshal.h"
24 #include "metadata/marshal-internals.h"
25 #include "metadata/marshal-ilgen.h"
26 #include "metadata/method-builder.h"
27 #include "metadata/method-builder-internals.h"
28 #include "metadata/tabledefs.h"
29 #include "metadata/exception.h"
30 #include "metadata/appdomain.h"
31 #include "mono/metadata/abi-details.h"
32 #include "mono/metadata/class-abi-details.h"
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/threads.h"
35 #include "mono/metadata/monitor.h"
36 #include "mono/metadata/class-init.h"
37 #include "mono/metadata/class-internals.h"
38 #include "mono/metadata/metadata-internals.h"
39 #include "mono/metadata/domain-internals.h"
40 #include "mono/metadata/gc-internals.h"
41 #include "mono/metadata/threads-types.h"
42 #include "mono/metadata/string-icalls.h"
43 #include "mono/metadata/attrdefs.h"
44 #include "mono/metadata/cominterop.h"
45 #include "mono/metadata/remoting.h"
46 #include "mono/metadata/reflection-internals.h"
47 #include "mono/metadata/threadpool.h"
48 #include "mono/metadata/handle.h"
49 #include "mono/metadata/object-internals.h"
50 #include "mono/metadata/custom-attrs-internals.h"
51 #include "mono/metadata/abi-details.h"
52 #include "mono/metadata/custom-attrs-internals.h"
53 #include "mono/metadata/loader-internals.h"
54 #include "mono/utils/mono-counters.h"
55 #include "mono/utils/mono-tls.h"
56 #include "mono/utils/mono-memory-model.h"
57 #include "mono/utils/atomic.h"
58 #include <mono/utils/mono-threads.h>
59 #include <mono/utils/mono-threads-coop.h>
60 #include <mono/utils/mono-error-internals.h>
63 #include "icall-decl.h"
64 #include "icall-signatures.h"
67 mono_string_utf16len_to_builder (MonoStringBuilderHandle sb
, const gunichar2
*text
, gsize len
, MonoError
*error
);
69 /* #define DEBUG_RUNTIME_CODE */
71 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
75 #include "mono/cil/opcode.def"
81 * This mutex protects the various marshalling related caches in MonoImage
82 * and a few other data structures static to this file.
84 * The marshal lock is a non-recursive complex lock that sits below the domain lock in the
85 * runtime locking latice. Which means it can take simple locks suck as the image lock.
87 #define mono_marshal_lock() mono_locks_coop_acquire (&marshal_mutex, MarshalLock)
88 #define mono_marshal_unlock() mono_locks_coop_release (&marshal_mutex, MarshalLock)
89 static MonoCoopMutex marshal_mutex
;
90 static gboolean marshal_mutex_initialized
;
92 static MonoNativeTlsKey last_error_tls_id
;
94 static MonoNativeTlsKey load_type_info_tls_id
;
96 static gboolean use_aot_wrappers
;
98 static int class_marshal_info_count
;
100 static MonoMarshalCallbacks
*
101 get_marshal_cb (void);
104 delegate_hash_table_add (MonoDelegateHandle d
);
107 delegate_hash_table_remove (MonoDelegate
*d
);
109 /* Lazy class loading functions */
110 //used by marshal-ilgen.c
111 GENERATE_TRY_GET_CLASS_WITH_CACHE (stringbuilder
, "System.Text", "StringBuilder");
112 static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
114 #ifdef ENABLE_NETCORE
115 static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute
, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute")
119 get_method_image (MonoMethod
*method
)
121 return m_class_get_image (method
->klass
);
124 // func is an identifier, that names a function, and is also in jit-icall-reg.h,
125 // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
127 // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
128 // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
129 // must be extern "C".
130 #define register_icall(func, sig, no_wrapper) \
131 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (no_wrapper), #func))
134 mono_signature_no_pinvoke (MonoMethod
*method
)
136 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
138 sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
139 sig
->pinvoke
= FALSE
;
146 mono_marshal_init_tls (void)
148 mono_native_tls_alloc (&last_error_tls_id
, NULL
);
149 mono_native_tls_alloc (&load_type_info_tls_id
, NULL
);
153 mono_object_isinst_icall_impl (MonoObjectHandle obj
, MonoClass
* klass
, MonoError
*error
)
158 /* This is called from stelemref so it is expected to succeed */
160 if (mono_class_is_interface (klass
)) {
161 MonoVTable
*vt
= mono_handle_vtable (obj
);
163 if (!m_class_is_inited (klass
))
164 mono_class_init_internal (klass
);
166 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, m_class_get_interface_id (klass
)))
170 return mono_object_handle_isinst (obj
, klass
, error
);
174 ves_icall_mono_string_from_utf16_impl (const gunichar2
*data
, MonoError
*error
)
176 MonoString
*s
= mono_string_from_utf16_checked (data
, error
);
177 return_val_if_nok (error
, NULL_HANDLE_STRING
);
178 return MONO_HANDLE_NEW (MonoString
, s
);
182 ves_icall_mono_string_to_utf8_impl (MonoStringHandle str
, MonoError
*error
)
184 return mono_string_handle_to_utf8 (str
, error
);
188 ves_icall_string_new_wrapper_impl (const char *text
, MonoError
*error
)
190 return text
? mono_string_new_handle (mono_domain_get (), text
, error
) : NULL_HANDLE_STRING
;
194 mono_marshal_init (void)
196 static gboolean module_initialized
= FALSE
;
198 if (!module_initialized
) {
199 module_initialized
= TRUE
;
200 mono_coop_mutex_init_recursive (&marshal_mutex
);
201 marshal_mutex_initialized
= TRUE
;
203 register_icall (mono_marshal_string_to_utf16
, mono_icall_sig_ptr_obj
, FALSE
);
204 register_icall (mono_marshal_string_to_utf16_copy
, mono_icall_sig_ptr_obj
, FALSE
);
205 register_icall (mono_string_to_utf16_internal
, mono_icall_sig_ptr_obj
, FALSE
);
206 register_icall (ves_icall_mono_string_from_utf16
, mono_icall_sig_obj_ptr
, FALSE
);
207 register_icall (mono_string_from_byvalstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
208 register_icall (mono_string_from_byvalwstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
209 register_icall (mono_string_new_wrapper_internal
, mono_icall_sig_obj_ptr
, FALSE
);
210 register_icall (ves_icall_string_new_wrapper
, mono_icall_sig_obj_ptr
, FALSE
);
211 register_icall (mono_string_new_len_wrapper
, mono_icall_sig_obj_ptr_int
, FALSE
);
212 register_icall (ves_icall_mono_string_to_utf8
, mono_icall_sig_ptr_obj
, FALSE
);
213 register_icall (mono_string_to_utf8str
, mono_icall_sig_ptr_obj
, FALSE
);
214 register_icall (mono_string_to_ansibstr
, mono_icall_sig_ptr_object
, FALSE
);
215 register_icall (mono_string_builder_to_utf8
, mono_icall_sig_ptr_object
, FALSE
);
216 register_icall (mono_string_builder_to_utf16
, mono_icall_sig_ptr_object
, FALSE
);
217 register_icall (mono_array_to_savearray
, mono_icall_sig_ptr_object
, FALSE
);
218 register_icall (mono_array_to_lparray
, mono_icall_sig_ptr_object
, FALSE
);
219 register_icall (mono_free_lparray
, mono_icall_sig_void_object_ptr
, FALSE
);
220 register_icall (mono_byvalarray_to_byte_array
, mono_icall_sig_void_object_ptr_int32
, FALSE
);
221 register_icall (mono_array_to_byte_byvalarray
, mono_icall_sig_void_ptr_object_int32
, FALSE
);
222 register_icall (mono_delegate_to_ftnptr
, mono_icall_sig_ptr_object
, FALSE
);
223 register_icall (mono_ftnptr_to_delegate
, mono_icall_sig_object_ptr_ptr
, FALSE
);
224 register_icall (mono_marshal_asany
, mono_icall_sig_ptr_object_int32_int32
, FALSE
);
225 register_icall (mono_marshal_free_asany
, mono_icall_sig_void_object_ptr_int32_int32
, FALSE
);
226 register_icall (ves_icall_marshal_alloc
, mono_icall_sig_ptr_ptr
, FALSE
);
227 register_icall (mono_marshal_free
, mono_icall_sig_void_ptr
, FALSE
);
228 register_icall (mono_marshal_set_last_error
, mono_icall_sig_void
, TRUE
);
229 register_icall (mono_marshal_set_last_error_windows
, mono_icall_sig_void_int32
, TRUE
);
230 register_icall (mono_marshal_clear_last_error
, mono_icall_sig_void
, TRUE
);
231 register_icall (mono_string_utf8_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
232 register_icall (mono_string_utf8_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
233 register_icall (mono_string_utf16_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
234 register_icall (mono_string_utf16_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
235 register_icall (mono_marshal_free_array
, mono_icall_sig_void_ptr_int32
, FALSE
);
236 register_icall (mono_string_to_byvalstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
237 register_icall (mono_string_to_byvalwstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
238 // Because #define g_free monoeg_g_free.
239 register_icall (monoeg_g_free
, mono_icall_sig_void_ptr
, FALSE
);
240 register_icall (mono_object_isinst_icall
, mono_icall_sig_object_object_ptr
, TRUE
);
241 register_icall (mono_struct_delete_old
, mono_icall_sig_void_ptr_ptr
, FALSE
);
242 register_icall (mono_delegate_begin_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
243 register_icall (mono_delegate_end_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
244 register_icall (mono_gc_wbarrier_generic_nostore_internal
, mono_icall_sig_void_ptr
, FALSE
);
245 register_icall (mono_gchandle_get_target_internal
, mono_icall_sig_object_int32
, TRUE
);
246 register_icall (mono_marshal_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
247 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
248 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
249 register_icall (mono_threads_enter_gc_unsafe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
250 register_icall (mono_threads_exit_gc_unsafe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
251 register_icall (mono_threads_attach_coop
, mono_icall_sig_ptr_ptr_ptr
, TRUE
);
252 register_icall (mono_threads_detach_coop
, mono_icall_sig_void_ptr_ptr
, TRUE
);
253 register_icall (mono_marshal_get_type_object
, mono_icall_sig_object_ptr
, TRUE
);
255 mono_cominterop_init ();
256 mono_remoting_init ();
258 mono_counters_register ("MonoClass::class_marshal_info_count count",
259 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_marshal_info_count
);
264 mono_marshal_cleanup (void)
266 mono_cominterop_cleanup ();
268 mono_native_tls_free (load_type_info_tls_id
);
269 mono_native_tls_free (last_error_tls_id
);
270 mono_coop_mutex_destroy (&marshal_mutex
);
271 marshal_mutex_initialized
= FALSE
;
275 mono_marshal_lock_internal (void)
277 mono_marshal_lock ();
281 mono_marshal_unlock_internal (void)
283 mono_marshal_unlock ();
286 // This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error.
288 mono_delegate_to_ftnptr_impl (MonoDelegateHandle delegate
, MonoError
*error
)
290 gpointer result
= NULL
;
291 MonoMethod
*method
, *wrapper
;
293 uint32_t target_handle
= 0;
295 if (MONO_HANDLE_IS_NULL (delegate
))
298 if (MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
)) {
299 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
303 klass
= mono_handle_class (delegate
);
304 g_assert (m_class_is_delegate (klass
));
306 method
= MONO_HANDLE_GETVAL (delegate
, method
);
307 if (MONO_HANDLE_GETVAL (delegate
, method_is_virtual
)) {
308 MonoObjectHandle delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
309 method
= mono_object_handle_get_virtual_method (delegate_target
, method
, error
);
310 goto_if_nok (error
, leave
);
313 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
316 ftnptr
= mono_lookup_pinvoke_call_internal (method
, error
);
318 g_assert (!is_ok (error
));
325 MonoObjectHandle delegate_target
;
326 delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
327 if (!MONO_HANDLE_IS_NULL (delegate_target
)) {
328 /* Produce a location which can be embedded in JITted code */
329 target_handle
= mono_gchandle_new_weakref_from_handle (delegate_target
);
332 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
, error
);
333 goto_if_nok (error
, leave
);
335 MONO_HANDLE_SETVAL (delegate
, delegate_trampoline
, gpointer
, mono_compile_method_checked (wrapper
, error
));
336 goto_if_nok (error
, leave
);
338 // Add the delegate to the delegate hash table
339 delegate_hash_table_add (delegate
);
341 /* when the object is collected, collect the dynamic method, too */
342 mono_object_register_finalizer ((MonoObject
*) MONO_HANDLE_RAW (delegate
));
344 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
347 if (!is_ok (error
) && target_handle
!= 0)
348 mono_gchandle_free_internal (target_handle
);
353 * this hash table maps from a delegate trampoline object to a weak reference
354 * of the delegate. As an optimizations with a non-moving GC we store the
355 * object pointer itself, otherwise we use a GC handle.
357 static GHashTable
*delegate_hash_table
;
360 delegate_hash_table_new (void) {
361 return g_hash_table_new (NULL
, NULL
);
365 delegate_hash_table_remove (MonoDelegate
*d
)
367 guint32 gchandle
= 0;
372 mono_marshal_lock ();
373 if (delegate_hash_table
== NULL
)
374 delegate_hash_table
= delegate_hash_table_new ();
375 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
376 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
377 mono_marshal_unlock ();
379 mono_gchandle_free_internal (gchandle
);
383 delegate_hash_table_add (MonoDelegateHandle d
)
385 mono_marshal_lock ();
386 if (delegate_hash_table
== NULL
)
387 delegate_hash_table
= delegate_hash_table_new ();
388 gpointer delegate_trampoline
= MONO_HANDLE_GETVAL (d
, delegate_trampoline
);
389 gboolean has_target
= MONO_HANDLE_GETVAL (d
, target
) != NULL
;
391 // If the delegate has an instance method there is 1 to 1 mapping between
392 // the delegate object and the delegate_trampoline
393 guint32 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
));
395 // Somehow, some other thread beat us to it ?
396 g_assert (mono_gchandle_target_equal (gchandle
, MONO_HANDLE_CAST (MonoObject
, d
)));
398 gchandle
= mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, d
));
399 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
402 if (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
) == NULL
) {
403 guint32 gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, d
), FALSE
);
404 // This delegate will always be associated with its delegate_trampoline in the table.
405 // We don't free this delegate object because it is too expensive to keep track of these
406 // pairs and avoid races with the delegate finalization.
407 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
410 mono_marshal_unlock ();
414 * mono_marshal_use_aot_wrappers:
416 * Instructs this module to use AOT compatible wrappers.
419 mono_marshal_use_aot_wrappers (gboolean use
)
421 use_aot_wrappers
= use
;
425 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
428 MonoCustomAttrInfo
*cinfo
;
429 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
431 /* The attribute is only available in Net 2.0 */
432 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
434 * The pinvoke attributes are stored in a real custom attribute so we have to
437 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
438 if (!is_ok (error
)) {
439 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
440 mono_error_cleanup (error
);
442 if (cinfo
&& !mono_runtime_get_no_exec ()) {
443 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), error
);
445 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
447 if (!is_ok (error
)) {
448 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
449 mono_error_cleanup (error
);
453 mono_custom_attrs_free (cinfo
);
458 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
460 mono_ftnptr_to_delegate_impl (MonoClass
*klass
, gpointer ftn
, MonoError
*error
)
463 MonoDelegateHandle d
= MONO_HANDLE_NEW (MonoDelegate
, NULL
);
468 mono_marshal_lock ();
469 if (delegate_hash_table
== NULL
)
470 delegate_hash_table
= delegate_hash_table_new ();
471 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
472 mono_marshal_unlock ();
474 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_CAST (MonoDelegate
, mono_gchandle_get_target_handle (gchandle
)));
476 if (MONO_HANDLE_IS_NULL (d
)) {
477 /* This is a native function, so construct a delegate for it */
478 MonoMethodSignature
*sig
;
480 MonoMarshalSpec
**mspecs
;
481 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
482 MonoMethodPInvoke piinfo
;
483 MonoObjectHandle this_obj
;
486 if (use_aot_wrappers
) {
487 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
488 this_obj
= MONO_HANDLE_NEW (MonoObject
, mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, error
));
489 goto_if_nok (error
, leave
);
491 memset (&piinfo
, 0, sizeof (piinfo
));
492 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
494 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
495 mono_method_get_marshal_info (invoke
, mspecs
);
496 /* Freed below so don't alloc from mempool */
497 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
500 wrapper
= mono_marshal_get_native_func_wrapper (m_class_get_image (klass
), sig
, &piinfo
, mspecs
, ftn
);
501 this_obj
= MONO_HANDLE_NEW (MonoObject
, NULL
);
503 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
505 mono_metadata_free_marshal_spec (mspecs
[i
]);
510 MONO_HANDLE_ASSIGN (d
, mono_object_new_handle (mono_domain_get (), klass
, error
));
511 goto_if_nok (error
, leave
);
512 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, error
);
513 goto_if_nok (error
, leave
);
515 mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject
, d
), this_obj
, compiled_ptr
, wrapper
, error
);
516 goto_if_nok (error
, leave
);
519 g_assert (!MONO_HANDLE_IS_NULL (d
));
520 if (MONO_HANDLE_DOMAIN (d
) != mono_domain_get ())
521 mono_error_set_not_supported (error
, "Delegates cannot be marshalled from native code into a domain other than their home domain");
527 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
532 delegate_hash_table_remove (delegate
);
534 ptr
= (gpointer
)mono_atomic_xchg_ptr (&delegate
->delegate_trampoline
, NULL
);
536 if (!delegate
->target
) {
537 /* The wrapper method is shared between delegates -> no need to free it */
546 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
547 /* FIXME we leak wrapper with the interpreter */
551 method
= mono_jit_info_get_method (ji
);
552 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
554 /*the target gchandle is the first entry after size and the wrapper itself.*/
555 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
558 mono_gchandle_free_internal (gchandle
);
560 mono_runtime_free_method (mono_object_domain (delegate
), method
);
564 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
566 mono_string_from_byvalstr_impl (const char *data
, int max_len
, MonoError
*error
)
568 // FIXME This optimization ok to miss before wrapper? Or null is rare?
570 return NULL_HANDLE_STRING
;
573 while (len
< max_len
- 1 && data
[len
])
577 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), data
, len
, error
);
578 return_val_if_nok (error
, NULL_HANDLE_STRING
);
579 return MONO_HANDLE_NEW (MonoString
, s
);
582 /* This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error */
584 mono_string_from_byvalwstr_impl (const gunichar2
*data
, int max_len
, MonoError
*error
)
586 // FIXME This optimization ok to miss before wrapper? Or null is rare?
588 return NULL_HANDLE_STRING
;
590 // FIXME Check max_len while scanning data? mono_string_from_byvalstr does.
591 const int len
= g_utf16_len (data
);
593 return mono_string_new_utf16_handle (mono_domain_get (), data
, MIN (len
, max_len
), error
);
597 mono_array_to_savearray_impl (MonoArrayHandle array
, MonoError
*error
)
599 if (!MONO_HANDLE_BOOL (array
))
602 g_assert_not_reached ();
607 mono_array_to_lparray_impl (MonoArrayHandle array_handle
, MonoError
*error
)
609 if (!MONO_HANDLE_BOOL (array_handle
))
612 MonoArray
*array
= MONO_HANDLE_RAW (array_handle
); // FIXMEcoop
615 gpointer
*nativeArray
= NULL
;
616 int nativeArraySize
= 0;
618 MonoClass
*klass
= array
->obj
.vtable
->klass
;
619 MonoClass
*klass_element_class
= m_class_get_element_class (klass
);
621 switch (m_class_get_byval_arg (klass_element_class
)->type
) {
623 g_assert_not_reached ();
625 case MONO_TYPE_CLASS
:
626 nativeArraySize
= array
->max_length
;
627 nativeArray
= g_new (gpointer
, nativeArraySize
);
628 for (i
= 0; i
< nativeArraySize
; ++i
) {
629 nativeArray
[i
] = mono_cominterop_get_com_interface (((MonoObject
**)array
->vector
)[i
], klass_element_class
, error
);
630 if (!is_ok (error
)) {
631 // FIXME? Returns uninitialized.
637 case MONO_TYPE_BOOLEAN
:
650 case MONO_TYPE_VALUETYPE
:
654 case MONO_TYPE_GENERICINST
:
655 case MONO_TYPE_OBJECT
:
656 case MONO_TYPE_ARRAY
:
657 case MONO_TYPE_SZARRAY
:
658 case MONO_TYPE_STRING
:
660 g_warning ("type 0x%x not handled", m_class_get_byval_arg (klass_element_class
)->type
);
661 g_assert_not_reached ();
664 return array
->vector
;
668 mono_free_lparray_impl (MonoArrayHandle array
, gpointer
* nativeArray
, MonoError
*error
)
671 if (!nativeArray
|| MONO_HANDLE_IS_NULL (array
))
674 MonoClass
* const klass
= mono_handle_class (array
);
676 if (m_class_get_byval_arg (m_class_get_element_class (klass
))->type
== MONO_TYPE_CLASS
)
677 g_free (nativeArray
);
681 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
683 mono_byvalarray_to_byte_array_impl (MonoArrayHandle arr
, const char *native_arr
, guint32 elnum
, MonoError
*error
)
685 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
687 GError
*gerror
= NULL
;
689 gunichar2
*ut
= g_utf8_to_utf16 (native_arr
, elnum
, NULL
, &items_written
, &gerror
);
692 g_error_free (gerror
);
695 gchandle_t gchandle
= 0;
696 memcpy (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), ut
, items_written
* sizeof (gunichar2
));
697 mono_gchandle_free_internal (gchandle
);
701 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
703 mono_array_to_byte_byvalarray_impl (gpointer native_arr
, MonoArrayHandle arr
, guint32 elnum
, MonoError
*error
)
705 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
707 GError
*gerror
= NULL
;
709 gchandle_t gchandle
= 0;
710 char *as
= g_utf16_to_utf8 (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), mono_array_handle_length (arr
), NULL
, NULL
, &gerror
);
711 mono_gchandle_free_internal (gchandle
);
713 mono_error_set_argument (error
, "string", gerror
->message
);
714 g_error_free (gerror
);
717 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
721 static MonoStringBuilderHandle
722 mono_string_builder_new (int starting_string_length
, MonoError
*error
)
724 static MonoClass
*string_builder_class
;
725 static MonoMethod
*sb_ctor
;
728 int initial_len
= starting_string_length
;
734 MonoMethodDesc
*desc
;
737 string_builder_class
= mono_class_try_get_stringbuilder_class ();
738 g_assert (string_builder_class
); //TODO don't swallow the error
739 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
740 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
742 mono_method_desc_free (desc
);
743 mono_memory_barrier ();
747 // We make a new array in the _to_builder function, so this
748 // array will always be garbage collected.
749 args
[0] = &initial_len
;
751 MonoStringBuilderHandle sb
= MONO_HANDLE_CAST (MonoStringBuilder
, mono_object_new_handle (mono_domain_get (), string_builder_class
, error
));
752 mono_error_assert_ok (error
);
754 mono_runtime_try_invoke_handle (sb_ctor
, MONO_HANDLE_CAST (MonoObject
, sb
), args
, error
);
755 mono_error_assert_ok (error
);
757 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW_GET (MonoArray
, sb
, chunkChars
);
758 g_assert (MONO_HANDLE_GETVAL (chunkChars
, max_length
) >= initial_len
);
764 mono_string_utf16_to_builder_copy (MonoStringBuilderHandle sb
, const gunichar2
*text
, size_t string_len
, MonoError
*error
)
766 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
767 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
769 guint capacity
= mono_string_builder_capacity (sb
);
771 g_assert (capacity
>= string_len
);
773 MONO_ENTER_NO_SAFEPOINTS
;
776 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
777 const int maxLength
= MONO_HANDLE_GETVAL (chunkChars
, max_length
);
778 g_assert (maxLength
>= 0);
779 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
780 g_assert (chunkOffset
>= 0);
781 if (maxLength
> 0 && chunkOffset
< string_len
) {
782 // Check that we will not overrun our boundaries.
783 int charsToCopy
= MIN (string_len
- chunkOffset
, maxLength
);
784 memcpy (MONO_HANDLE_RAW (chunkChars
)->vector
, text
+ chunkOffset
, charsToCopy
* sizeof (gunichar2
));
785 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, charsToCopy
);
787 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, 0);
789 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
790 } while (MONO_HANDLE_BOOL (chunk
));
792 MONO_EXIT_NO_SAFEPOINTS
;
795 MonoStringBuilderHandle
796 mono_string_utf16_to_builder2_impl (const gunichar2
*text
, MonoError
*error
)
799 return NULL_HANDLE_STRING_BUILDER
;
801 const gsize len
= g_utf16_len (text
);
803 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
804 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
806 mono_string_utf16len_to_builder (sb
, text
, len
, error
);
807 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
813 mono_string_utf8len_to_builder (MonoStringBuilderHandle sb
, const char *text
, gsize len
, MonoError
*error
)
815 if (!MONO_HANDLE_BOOL (sb
) || !text
)
818 GError
*gerror
= NULL
;
820 gunichar2
* ut
= g_utf8_to_utf16 (text
, len
, NULL
, &copied
, &gerror
);
821 int capacity
= mono_string_builder_capacity (sb
);
823 if (copied
> capacity
)
827 MONO_HANDLE_SETRAW (sb
, chunkPrevious
, NULL
);
828 mono_string_utf16_to_builder_copy (sb
, ut
, copied
, error
);
831 g_error_free (gerror
);
838 mono_string_utf8_to_builder_impl (MonoStringBuilderHandle sb
, const char *text
, MonoError
*error
)
840 mono_string_utf8len_to_builder (sb
, text
, text
? strlen (text
) : 0, error
);
843 MonoStringBuilderHandle
844 mono_string_utf8_to_builder2_impl (const char *text
, MonoError
*error
)
847 return NULL_HANDLE_STRING_BUILDER
;
849 const gsize len
= strlen (text
);
851 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
852 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
854 mono_string_utf8len_to_builder (sb
, text
, len
, error
);
855 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
861 mono_string_utf16len_to_builder (MonoStringBuilderHandle sb
, const gunichar2
*text
, gsize len
, MonoError
*error
)
863 if (!MONO_HANDLE_BOOL (sb
) || !text
)
865 len
= MIN (len
, mono_string_builder_capacity (sb
));
866 mono_string_utf16_to_builder_copy (sb
, text
, len
, error
);
870 mono_string_utf16_to_builder_impl (MonoStringBuilderHandle sb
, const gunichar2
*text
, MonoError
*error
)
872 mono_string_utf16len_to_builder (sb
, text
, text
? g_utf16_len (text
) : 0, error
);
876 * mono_string_builder_to_utf8:
877 * \param sb the string builder
879 * Converts to utf8 the contents of the \c MonoStringBuilder .
881 * \returns a utf8 string with the contents of the \c StringBuilder .
883 * The return value must be released with mono_marshal_free.
885 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
888 mono_string_builder_to_utf8_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
891 GError
*gerror
= NULL
;
893 gunichar2
*str_utf16
= NULL
;
897 if (!MONO_HANDLE_BOOL (sb
))
900 str_utf16
= mono_string_builder_to_utf16_impl (sb
, error
);
901 goto_if_nok (error
, exit
);
903 tmp
= g_utf16_to_utf8 (str_utf16
, mono_string_builder_string_length (sb
), NULL
, &byte_count
, &gerror
);
905 mono_error_set_execution_engine (error
, "Failed to convert StringBuilder from utf16 to utf8");
909 len
= mono_string_builder_capacity (sb
) + 1;
910 res
= (char *)mono_marshal_alloc (MAX (byte_count
+ 1, len
), error
);
911 if (!is_ok (error
)) {
916 memcpy (res
, tmp
, byte_count
);
917 res
[byte_count
] = 0;
919 g_error_free (gerror
);
920 mono_marshal_free (str_utf16
);
926 * mono_string_builder_to_utf16:
927 * \param sb the string builder
929 * Converts to utf16 the contents of the \c MonoStringBuilder .
931 * Returns: a utf16 string with the contents of the \c StringBuilder .
933 * The return value must be released with mono_marshal_free.
935 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
938 mono_string_builder_to_utf16_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
940 if (!MONO_HANDLE_BOOL (sb
))
943 g_assert (MONO_HANDLE_GET_BOOL (sb
, chunkChars
));
945 guint capacity
= mono_string_builder_capacity (sb
);
946 guint length
= mono_string_builder_string_length (sb
);
948 // Follow CoreCLR and double NULL terminate the buffer so we have more protection
949 // against native code putting garbage in there.
951 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((capacity
+ 2) * sizeof (gunichar2
), error
);
952 return_val_if_nok (error
, NULL
);
955 str
[capacity
+ 1] = 0;
957 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
958 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
960 MONO_ENTER_NO_SAFEPOINTS
;
963 const int chunkLength
= MONO_HANDLE_GETVAL (chunk
, chunkLength
);
964 g_assert (chunkLength
>= 0);
965 if (chunkLength
> 0) {
966 // Check that we will not overrun our boundaries.
967 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
968 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
969 g_assert (chunkOffset
>= 0);
970 g_assertf ((chunkOffset
+ chunkLength
) >= chunkLength
, "integer overflow");
971 g_assertf ((chunkOffset
+ chunkLength
) <= capacity
, "A chunk in the StringBuilder had a length longer than expected from the offset.");
972 memcpy (str
+ chunkOffset
, MONO_HANDLE_RAW (chunkChars
)->vector
, chunkLength
* sizeof (gunichar2
));
974 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
975 } while (MONO_HANDLE_BOOL (chunk
));
979 MONO_EXIT_NO_SAFEPOINTS
;
986 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
988 mono_string_to_utf8str_impl (MonoStringHandle s
, MonoError
*error
)
990 return mono_string_handle_to_utf8 (s
, error
);
996 mono_string_to_ansibstr_impl (MonoStringHandle string_obj
, MonoError
*error
)
998 g_error ("UnmanagedMarshal.BStr is not implemented.");
1003 * mono_string_to_byvalstr:
1004 * \param dst Where to store the null-terminated utf8 decoded string.
1005 * \param src the \c MonoString to copy.
1006 * \param size the maximum number of bytes to copy.
1008 * Copies the \c MonoString pointed to by \p src as a utf8 string
1009 * into \p dst, it copies at most \p size bytes into the destination.
1012 mono_string_to_byvalstr_impl (char *dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1014 g_assert (dst
!= NULL
);
1015 g_assert (size
> 0);
1017 memset (dst
, 0, size
);
1018 if (!MONO_HANDLE_BOOL (src
))
1021 // FIXME convert right into dst instead of the double copy.
1023 char *s
= mono_string_handle_to_utf8 (src
, error
);
1024 return_if_nok (error
);
1025 int len
= MIN (size
, strlen (s
));
1026 len
-= (len
>= size
);
1027 memcpy (dst
, s
, len
);
1033 * mono_string_to_byvalwstr:
1034 * \param dst Where to store the null-terminated utf16 decoded string.
1035 * \param src the \c MonoString to copy.
1036 * \param size the maximum number of wide characters to copy (each consumes 2 bytes)
1038 * Copies the \c MonoString pointed to by \p src as a utf16 string into
1039 * \p dst, it copies at most \p size gunichar2s into the destination (including
1040 * a terminating 16-bit zero terminator).
1043 mono_string_to_byvalwstr_impl (gunichar2
*dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1046 g_assert (size
> 0);
1048 if (!MONO_HANDLE_BOOL (src
)) {
1049 memset (dst
, 0, size
* sizeof (gunichar2
));
1053 gchandle_t gchandle
= 0;
1054 int len
= MIN (size
, mono_string_handle_length (src
));
1055 memcpy (dst
, mono_string_handle_pin_chars (src
, &gchandle
), len
* sizeof (gunichar2
));
1056 mono_gchandle_free_internal (gchandle
);
1057 len
-= (size
<= mono_string_handle_length (src
));
1061 /* this is an icall, it sets the pending exception and returns NULL on error */
1063 mono_string_new_len_wrapper_impl (const char *text
, guint length
, MonoError
*error
)
1065 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), text
, length
, error
);
1066 return_val_if_nok (error
, NULL_HANDLE_STRING
);
1067 return MONO_HANDLE_NEW (MonoString
, s
);
1071 mono_type_to_ldind (MonoType
*type
)
1077 switch (type
->type
) {
1079 return CEE_LDIND_I1
;
1081 case MONO_TYPE_BOOLEAN
:
1082 return CEE_LDIND_U1
;
1084 return CEE_LDIND_I2
;
1086 case MONO_TYPE_CHAR
:
1087 return CEE_LDIND_U2
;
1089 return CEE_LDIND_I4
;
1091 return CEE_LDIND_U4
;
1095 case MONO_TYPE_FNPTR
:
1097 case MONO_TYPE_CLASS
:
1098 case MONO_TYPE_STRING
:
1099 case MONO_TYPE_OBJECT
:
1100 case MONO_TYPE_SZARRAY
:
1101 case MONO_TYPE_ARRAY
:
1102 return CEE_LDIND_REF
;
1105 return CEE_LDIND_I8
;
1107 return CEE_LDIND_R4
;
1109 return CEE_LDIND_R8
;
1110 case MONO_TYPE_VALUETYPE
:
1111 if (m_class_is_enumtype (type
->data
.klass
)) {
1112 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1116 case MONO_TYPE_TYPEDBYREF
:
1118 case MONO_TYPE_GENERICINST
:
1119 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1122 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1128 mono_type_to_stind (MonoType
*type
)
1131 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1134 switch (type
->type
) {
1137 case MONO_TYPE_BOOLEAN
:
1138 return CEE_STIND_I1
;
1141 case MONO_TYPE_CHAR
:
1142 return CEE_STIND_I2
;
1145 return CEE_STIND_I4
;
1149 case MONO_TYPE_FNPTR
:
1151 case MONO_TYPE_CLASS
:
1152 case MONO_TYPE_STRING
:
1153 case MONO_TYPE_OBJECT
:
1154 case MONO_TYPE_SZARRAY
:
1155 case MONO_TYPE_ARRAY
:
1156 return CEE_STIND_REF
;
1159 return CEE_STIND_I8
;
1161 return CEE_STIND_R4
;
1163 return CEE_STIND_R8
;
1164 case MONO_TYPE_VALUETYPE
:
1165 if (m_class_is_enumtype (type
->data
.klass
)) {
1166 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1170 case MONO_TYPE_TYPEDBYREF
:
1172 case MONO_TYPE_GENERICINST
:
1173 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1176 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1181 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1183 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1185 #ifdef ENABLE_NETCORE
1186 mono_set_pending_exception (mono_exception_from_name (mono_defaults
.corlib
, "System", "PlatformNotSupportedException"));
1190 MonoMulticastDelegate
*mcast_delegate
;
1194 g_assert (delegate
);
1195 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
1196 if (mcast_delegate
->delegates
!= NULL
) {
1197 mono_error_set_argument (error
, NULL
, "The delegate must have only one target");
1198 mono_error_set_pending_exception (error
);
1202 #ifndef DISABLE_REMOTING
1203 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1204 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1205 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
1206 /* If the target is a proxy, make a direct call. Is proxy's work
1207 // to make the call asynchronous.
1209 MonoMethodMessage
*msg
;
1210 MonoDelegate
*async_callback
;
1212 MonoAsyncResult
*ares
;
1214 MonoArray
*out_args
;
1215 method
= delegate
->method
;
1217 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, error
);
1218 if (mono_error_set_pending_exception (error
))
1220 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, error
);
1221 if (mono_error_set_pending_exception (error
))
1223 MONO_OBJECT_SETREF_INTERNAL (ares
, async_delegate
, (MonoObject
*)delegate
);
1224 MONO_OBJECT_SETREF_INTERNAL (ares
, async_callback
, (MonoObject
*)async_callback
);
1225 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1226 msg
->call_type
= CallType_BeginInvoke
;
1229 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1230 if (!is_ok (error
)) {
1231 mono_error_set_pending_exception (error
);
1235 mono_set_pending_exception ((MonoException
*) exc
);
1241 klass
= delegate
->object
.vtable
->klass
;
1243 ERROR_DECL (begin_invoke_error
);
1244 method
= mono_get_delegate_begin_invoke_checked (klass
, begin_invoke_error
);
1245 mono_error_cleanup (begin_invoke_error
); /* if we can't call BeginInvoke, fall back on Invoke */
1247 method
= mono_get_delegate_invoke_internal (klass
);
1250 MonoAsyncResult
*result
= mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, error
);
1251 mono_error_set_pending_exception (error
);
1257 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
1259 GString
*res
= g_string_new ("");
1262 g_string_append (res
, prefix
);
1263 g_string_append_c (res
, '_');
1266 mono_type_get_desc (res
, sig
->ret
, FALSE
);
1269 g_string_append (res
, "__this__");
1271 for (int i
= 0; i
< sig
->param_count
; ++i
) {
1272 g_string_append_c (res
, '_');
1273 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
1275 char *result
= res
->str
;
1276 g_string_free (res
, FALSE
);
1281 * mono_marshal_get_string_encoding:
1283 * Return the string encoding which should be used for a given parameter.
1286 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1288 /* First try the parameter marshal info */
1290 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
1291 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
1292 return spec
->data
.array_data
.elem_type
;
1295 return spec
->native
;
1299 return MONO_NATIVE_LPSTR
;
1301 /* Then try the method level marshal info */
1302 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1303 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1304 return MONO_NATIVE_LPSTR
;
1305 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1306 return MONO_NATIVE_LPWSTR
;
1307 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1309 return MONO_NATIVE_LPWSTR
;
1311 return MONO_NATIVE_LPSTR
;
1314 return MONO_NATIVE_LPSTR
;
1319 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1321 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1324 case MONO_NATIVE_LPWSTR
:
1325 return MONO_MARSHAL_CONV_STR_LPWSTR
;
1326 case MONO_NATIVE_LPSTR
:
1327 case MONO_NATIVE_VBBYREFSTR
:
1328 return MONO_MARSHAL_CONV_STR_LPSTR
;
1329 case MONO_NATIVE_LPTSTR
:
1330 return MONO_MARSHAL_CONV_STR_LPTSTR
;
1331 case MONO_NATIVE_BSTR
:
1332 return MONO_MARSHAL_CONV_STR_BSTR
;
1333 case MONO_NATIVE_UTF8STR
:
1334 return MONO_MARSHAL_CONV_STR_UTF8STR
;
1336 return MONO_MARSHAL_CONV_INVALID
;
1341 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1343 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1346 case MONO_NATIVE_LPWSTR
:
1347 return MONO_MARSHAL_CONV_SB_LPWSTR
;
1348 case MONO_NATIVE_LPSTR
:
1349 return MONO_MARSHAL_CONV_SB_LPSTR
;
1350 case MONO_NATIVE_UTF8STR
:
1351 return MONO_MARSHAL_CONV_SB_UTF8STR
;
1352 case MONO_NATIVE_LPTSTR
:
1353 return MONO_MARSHAL_CONV_SB_LPTSTR
;
1355 return MONO_MARSHAL_CONV_INVALID
;
1360 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1362 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1367 case MONO_NATIVE_LPWSTR
:
1369 return MONO_MARSHAL_CONV_LPWSTR_STR
;
1370 case MONO_NATIVE_UTF8STR
:
1371 return MONO_MARSHAL_CONV_UTF8STR_STR
;
1372 case MONO_NATIVE_LPSTR
:
1373 case MONO_NATIVE_VBBYREFSTR
:
1374 return MONO_MARSHAL_CONV_LPSTR_STR
;
1375 case MONO_NATIVE_LPTSTR
:
1379 return MONO_MARSHAL_CONV_LPTSTR_STR
;
1380 case MONO_NATIVE_BSTR
:
1381 return MONO_MARSHAL_CONV_BSTR_STR
;
1383 return MONO_MARSHAL_CONV_INVALID
;
1388 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1390 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1395 case MONO_NATIVE_LPWSTR
:
1396 return MONO_MARSHAL_CONV_LPWSTR_SB
;
1397 case MONO_NATIVE_UTF8STR
:
1398 return MONO_MARSHAL_CONV_UTF8STR_SB
;
1399 case MONO_NATIVE_LPSTR
:
1400 return MONO_MARSHAL_CONV_LPSTR_SB
;
1402 case MONO_NATIVE_LPTSTR
:
1403 return MONO_MARSHAL_CONV_LPTSTR_SB
;
1406 return MONO_MARSHAL_CONV_INVALID
;
1411 * Return whenever a field of a native structure or an array member needs to
1415 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1417 MonoMarshalNative encoding
;
1420 case MONO_TYPE_VALUETYPE
:
1421 /* FIXME: Optimize this */
1423 case MONO_TYPE_OBJECT
:
1424 case MONO_TYPE_CLASS
:
1425 if (t
->data
.klass
== mono_class_try_get_stringbuilder_class ()) {
1427 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
1431 case MONO_TYPE_STRING
:
1432 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1433 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
1440 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
1443 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1446 mono_marshal_lock ();
1449 g_hash_table_new (hash_func
, equal_func
);
1450 mono_memory_barrier ();
1453 mono_marshal_unlock ();
1459 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1461 return get_cache (var
, hash_func
, equal_func
);
1465 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
1469 mono_marshal_lock ();
1470 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1471 mono_marshal_unlock ();
1478 * Create a MonoMethod from MB, set INFO as wrapper info.
1481 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1482 int max_stack
, WrapperInfo
*info
)
1486 res
= mono_mb_create_method (mb
, sig
, max_stack
);
1488 mono_marshal_set_wrapper_info (res
, info
);
1492 /* Create the method from the builder and place it in the cache */
1494 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
1495 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1496 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
1503 mono_marshal_lock ();
1504 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1505 mono_marshal_unlock ();
1508 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
1509 mono_marshal_lock ();
1510 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1513 g_hash_table_insert (cache
, key
, res
);
1514 mono_marshal_set_wrapper_info (res
, info
);
1515 mono_marshal_unlock ();
1519 mono_marshal_unlock ();
1520 mono_free_method (newm
);
1528 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
1529 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1532 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
1536 * mono_marshal_method_from_wrapper:
1539 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
1542 int wrapper_type
= wrapper
->wrapper_type
;
1545 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1548 info
= mono_marshal_get_wrapper_info (wrapper
);
1550 switch (wrapper_type
) {
1551 case MONO_WRAPPER_REMOTING_INVOKE
:
1552 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
1553 case MONO_WRAPPER_XDOMAIN_INVOKE
:
1554 m
= info
->d
.remoting
.method
;
1555 if (wrapper
->is_inflated
) {
1559 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
1560 * contains an uninflated method.
1562 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1563 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1567 case MONO_WRAPPER_SYNCHRONIZED
:
1568 m
= info
->d
.synchronized
.method
;
1569 if (wrapper
->is_inflated
) {
1572 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1573 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1577 case MONO_WRAPPER_UNBOX
:
1578 return info
->d
.unbox
.method
;
1579 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
1580 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
1581 return info
->d
.managed_to_native
.method
;
1584 case MONO_WRAPPER_RUNTIME_INVOKE
:
1585 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
1586 return info
->d
.runtime_invoke
.method
;
1589 case MONO_WRAPPER_DELEGATE_INVOKE
:
1591 return info
->d
.delegate_invoke
.method
;
1600 * mono_marshal_get_wrapper_info:
1602 * Retrieve the WrapperInfo structure associated with WRAPPER.
1605 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
1607 g_assert (wrapper
->wrapper_type
);
1609 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
1613 * mono_marshal_set_wrapper_info:
1615 * Set the WrapperInfo structure associated with the wrapper
1616 * method METHOD to INFO.
1619 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
1623 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1626 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
1631 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
1635 info
= (WrapperInfo
*)mono_image_alloc0 (get_method_image (mb
->method
), sizeof (WrapperInfo
));
1636 info
->subtype
= subtype
;
1641 * get_wrapper_target_class:
1643 * Return the class where a wrapper method should be placed.
1646 get_wrapper_target_class (MonoImage
*image
)
1653 * - can't put all wrappers into an mscorlib class, because they reference
1654 * metadata (signature) so they should be put into the same image as the
1655 * method they wrap, so they are unloaded together.
1656 * - putting them into a class with a type initalizer could cause the
1657 * initializer to be executed which can be a problem if the wrappers are
1659 * - putting them into an inflated class can cause problems if the the
1660 * class is deleted because it references an image which is unloaded.
1661 * To avoid these problems, we put the wrappers into the <Module> class of
1664 if (image_is_dynamic (image
)) {
1665 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
1667 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), error
);
1668 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1676 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
1677 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
1681 * check_generic_wrapper_cache:
1683 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
1684 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
1685 * generic method definition.
1688 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
1691 MonoMethod
*inst
, *def
;
1692 MonoGenericContext
*ctx
;
1694 g_assert (orig_method
->is_inflated
);
1695 ctx
= mono_method_get_context (orig_method
);
1698 * Look for the instance
1700 res
= mono_marshal_find_in_cache (cache
, key
);
1705 * Look for the definition
1707 def
= mono_marshal_find_in_cache (cache
, def_key
);
1710 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1711 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1713 mono_memory_barrier ();
1714 mono_marshal_lock ();
1715 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1717 g_hash_table_insert (cache
, key
, inst
);
1720 mono_marshal_unlock ();
1727 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
1730 MonoMethod
*inst
, *res
;
1733 * We use the same cache for the generic definition and the instances.
1735 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1736 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1737 mono_memory_barrier ();
1738 mono_marshal_lock ();
1739 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1741 g_hash_table_insert (cache
, key
, inst
);
1744 mono_marshal_unlock ();
1749 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
1753 MonoMethod
*inst
, *def
;
1756 * Look for the instance
1758 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
1763 * Look for the definition
1765 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
1767 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1768 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1771 mono_memory_barrier ();
1772 mono_marshal_lock ();
1773 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1775 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1778 mono_marshal_unlock ();
1785 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
1788 MonoMethod
*inst
, *res
;
1789 WrapperInfo
*ginfo
, *info
;
1792 * We use the same cache for the generic definition and the instances.
1794 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1795 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1797 ginfo
= mono_marshal_get_wrapper_info (def
);
1799 info
= (WrapperInfo
*)mono_image_alloc0 (m_class_get_image (def
->klass
), sizeof (WrapperInfo
));
1800 info
->subtype
= ginfo
->subtype
;
1801 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
1802 info
->d
.delegate_invoke
.method
= mono_class_inflate_generic_method_checked (ginfo
->d
.delegate_invoke
.method
, ctx
, error
);
1803 mono_error_assert_ok (error
);
1807 mono_memory_barrier ();
1808 mono_marshal_lock ();
1809 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1811 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1814 mono_marshal_unlock ();
1818 #ifndef ENABLE_ILGEN
1820 emit_delegate_begin_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1826 * mono_marshal_get_delegate_begin_invoke:
1829 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
1831 MonoMethodSignature
*sig
;
1832 MonoMethodBuilder
*mb
;
1836 MonoGenericContext
*ctx
= NULL
;
1837 MonoMethod
*orig_method
= NULL
;
1839 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
1840 !strcmp (method
->name
, "BeginInvoke"));
1843 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
1845 if (method
->is_inflated
) {
1846 orig_method
= method
;
1847 ctx
= &((MonoMethodInflated
*)method
)->context
;
1848 method
= ((MonoMethodInflated
*)method
)->declaring
;
1851 sig
= mono_signature_no_pinvoke (method
);
1857 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1858 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
1862 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_begin_invoke_cache
,
1863 (GHashFunc
)mono_signature_hash
,
1864 (GCompareFunc
)mono_metadata_signature_equal
);
1865 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
1869 g_assert (sig
->hasthis
);
1871 name
= mono_signature_to_name (sig
, "begin_invoke");
1873 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1875 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1878 get_marshal_cb ()->emit_delegate_begin_invoke (mb
, sig
);
1880 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
1881 info
->d
.delegate_invoke
.method
= method
;
1885 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1886 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
1888 res
= mono_mb_create_and_cache_full (cache
, sig
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1895 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1897 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1899 #ifdef ENABLE_NETCORE
1900 mono_set_pending_exception (mono_exception_from_name (mono_defaults
.corlib
, "System", "PlatformNotSupportedException"));
1904 MonoDomain
*domain
= mono_domain_get ();
1905 MonoAsyncResult
*ares
;
1906 MonoMethod
*method
= NULL
;
1907 MonoMethodSignature
*sig
;
1908 MonoMethodMessage
*msg
;
1909 MonoObject
*res
, *exc
;
1910 MonoArray
*out_args
;
1913 g_assert (delegate
);
1915 if (!delegate
->method_info
) {
1916 g_assert (delegate
->method
);
1917 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, error
);
1918 if (!is_ok (error
)) {
1919 mono_error_set_pending_exception (error
);
1922 MONO_OBJECT_SETREF_INTERNAL (delegate
, method_info
, rm
);
1925 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
1926 g_assert_not_reached ();
1928 klass
= delegate
->object
.vtable
->klass
;
1930 method
= mono_get_delegate_end_invoke_checked (klass
, error
);
1931 mono_error_assert_ok (error
);
1932 g_assert (method
!= NULL
);
1934 sig
= mono_signature_no_pinvoke (method
);
1936 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, error
);
1937 if (mono_error_set_pending_exception (error
))
1940 ares
= (MonoAsyncResult
*)mono_array_get_internal (msg
->args
, gpointer
, sig
->param_count
- 1);
1942 mono_error_set_remoting (error
, "The async result object is null or of an unexpected type.");
1943 mono_error_set_pending_exception (error
);
1947 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
1948 mono_error_set_invalid_operation (error
,
1949 "%s", "The IAsyncResult object provided does not match this delegate.");
1950 mono_error_set_pending_exception (error
);
1954 #ifndef DISABLE_REMOTING
1955 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1956 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1957 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
1958 if (!is_ok (error
)) {
1959 mono_error_set_pending_exception (error
);
1962 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, error
);
1963 if (mono_error_set_pending_exception (error
))
1965 msg
->call_type
= CallType_EndInvoke
;
1966 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1967 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1968 if (!is_ok (error
)) {
1969 mono_error_set_pending_exception (error
);
1975 res
= mono_threadpool_end_invoke (ares
, &out_args
, &exc
, error
);
1976 if (mono_error_set_pending_exception (error
))
1981 if (((MonoException
*)exc
)->stack_trace
) {
1982 ERROR_DECL (inner_error
);
1983 char *strace
= mono_string_to_utf8_checked_internal (((MonoException
*)exc
)->stack_trace
, inner_error
);
1984 if (is_ok (inner_error
)) {
1986 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
1988 MonoString
*tmp_str
= mono_string_new_checked (domain
, tmp
, inner_error
);
1990 if (is_ok (inner_error
))
1991 MONO_OBJECT_SETREF_INTERNAL (((MonoException
*)exc
), stack_trace
, tmp_str
);
1993 if (!is_ok (inner_error
))
1994 mono_error_cleanup (inner_error
); /* no stack trace, but at least throw the original exception */
1996 mono_set_pending_exception ((MonoException
*)exc
);
1999 mono_method_return_message_restore (method
, params
, out_args
, error
);
2000 mono_error_set_pending_exception (error
);
2005 #ifndef ENABLE_ILGEN
2007 emit_delegate_end_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
2013 * mono_marshal_get_delegate_end_invoke:
2016 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
2018 MonoMethodSignature
*sig
;
2019 MonoMethodBuilder
*mb
;
2023 MonoGenericContext
*ctx
= NULL
;
2024 MonoMethod
*orig_method
= NULL
;
2026 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2027 !strcmp (method
->name
, "EndInvoke"));
2030 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
2032 if (method
->is_inflated
) {
2033 orig_method
= method
;
2034 ctx
= &((MonoMethodInflated
*)method
)->context
;
2035 method
= ((MonoMethodInflated
*)method
)->declaring
;
2038 sig
= mono_signature_no_pinvoke (method
);
2044 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2045 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2049 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_end_invoke_cache
,
2050 (GHashFunc
)mono_signature_hash
,
2051 (GCompareFunc
)mono_metadata_signature_equal
);
2052 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2056 g_assert (sig
->hasthis
);
2058 name
= mono_signature_to_name (sig
, "end_invoke");
2060 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2062 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2065 get_marshal_cb ()->emit_delegate_end_invoke (mb
, sig
);
2067 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
2068 info
->d
.delegate_invoke
.method
= method
;
2072 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2073 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2075 res
= mono_mb_create_and_cache_full (cache
, sig
,
2076 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2085 MonoMethodSignature
*sig
;
2087 } SignaturePointerPair
;
2090 signature_pointer_pair_hash (gconstpointer data
)
2092 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
2094 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
2098 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
2100 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
2101 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
2105 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
2107 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
2109 return pair
->pointer
== user_data
;
2113 free_signature_pointer_pair (SignaturePointerPair
*pair
)
2118 #ifndef ENABLE_ILGEN
2120 mb_skip_visibility_noilgen (MonoMethodBuilder
*mb
)
2125 mb_set_dynamic_noilgen (MonoMethodBuilder
*mb
)
2130 mb_emit_exception_noilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
2135 mb_emit_exception_for_error_noilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
2140 emit_delegate_invoke_internal_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodSignature
*invoke_sig
, gboolean static_method_with_first_arg_bound
, gboolean callvirt
, gboolean closed_over_null
, MonoMethod
*method
, MonoMethod
*target_method
, MonoClass
*target_class
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
)
2146 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
2148 MonoMethodSignature
*sig
, *invoke_sig
;
2149 MonoMethodBuilder
*mb
;
2152 gpointer cache_key
= NULL
;
2153 SignaturePointerPair key
= { NULL
, NULL
};
2154 SignaturePointerPair
*new_key
;
2156 MonoClass
*target_class
= NULL
;
2157 gboolean closed_over_null
= FALSE
;
2158 MonoGenericContext
*ctx
= NULL
;
2159 MonoGenericContainer
*container
= NULL
;
2160 MonoMethod
*orig_method
= method
;
2162 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
2165 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2166 !strcmp (method
->name
, "Invoke"));
2168 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2171 * If the delegate target is null, and the target method is not static, a virtual
2172 * call is made to that method with the first delegate argument as this. This is
2173 * a non-documented .NET feature.
2176 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
2177 if (target_method
->is_inflated
) {
2179 MonoType
*target_type
;
2181 g_assert (method
->signature
->hasthis
);
2182 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
2183 mono_method_get_context (method
), error
);
2184 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
2185 target_class
= mono_class_from_mono_type_internal (target_type
);
2187 target_class
= target_method
->klass
;
2190 closed_over_null
= sig
->param_count
== mono_method_signature_internal (target_method
)->param_count
;
2193 if (static_method_with_first_arg_bound
) {
2194 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
2195 g_assert (!callvirt
);
2196 invoke_sig
= mono_method_signature_internal (target_method
);
2198 * The wrapper has a different lifetime from the method to be invoked.
2199 * If the method is dynamic we don't want to be using its signature
2200 * in the wrapper since it could get freed early.
2202 if (method_is_dynamic (target_method
))
2203 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (target_method
), invoke_sig
);
2207 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
2209 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
2210 ctx
= &((MonoMethodInflated
*)method
)->context
;
2211 method
= ((MonoMethodInflated
*)method
)->declaring
;
2213 container
= mono_method_get_generic_container (method
);
2215 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
2216 g_assert (container
);
2218 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2225 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2226 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2229 cache_key
= method
->klass
;
2230 } else if (static_method_with_first_arg_bound
) {
2231 cache
= get_cache (&get_method_image (target_method
)->delegate_bound_static_invoke_cache
,
2232 (GHashFunc
)mono_signature_hash
,
2233 (GCompareFunc
)mono_metadata_signature_equal
);
2235 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
2237 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
2240 cache_key
= invoke_sig
;
2241 } else if (callvirt
) {
2242 GHashTable
**cache_ptr
;
2244 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
2246 /* We need to cache the signature+method pair */
2247 mono_marshal_lock ();
2249 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
2251 key
.sig
= invoke_sig
;
2252 key
.pointer
= target_method
;
2253 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
2254 mono_marshal_unlock ();
2258 // Inflated methods should not be in this cache because it's not stored on the imageset.
2259 g_assert (!method
->is_inflated
);
2260 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_invoke_cache
,
2261 (GHashFunc
)mono_signature_hash
,
2262 (GCompareFunc
)mono_metadata_signature_equal
);
2263 res
= mono_marshal_find_in_cache (cache
, sig
);
2269 if (!static_method_with_first_arg_bound
) {
2270 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
2271 invoke_sig
->hasthis
= 0;
2274 if (static_method_with_first_arg_bound
)
2275 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
2276 else if (closed_over_null
)
2277 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
2279 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
2281 name
= mono_signature_to_name (invoke_sig
, "invoke");
2283 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2285 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2288 get_marshal_cb ()->emit_delegate_invoke_internal (mb
, sig
, invoke_sig
, static_method_with_first_arg_bound
, callvirt
, closed_over_null
, method
, target_method
, target_class
, ctx
, container
);
2290 get_marshal_cb ()->mb_skip_visibility (mb
);
2292 info
= mono_wrapper_info_create (mb
, subtype
);
2293 info
->d
.delegate_invoke
.method
= method
;
2298 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2299 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2300 } else if (callvirt
) {
2301 new_key
= g_new0 (SignaturePointerPair
, 1);
2304 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
2308 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2312 /* mono_method_print_code (res); */
2318 * mono_marshal_get_delegate_invoke:
2319 * The returned method invokes all methods in a multicast delegate.
2322 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
2324 gboolean callvirt
= FALSE
;
2325 gboolean static_method_with_first_arg_bound
= FALSE
;
2326 MonoMethod
*target_method
= NULL
;
2327 MonoMethodSignature
*sig
;
2329 sig
= mono_signature_no_pinvoke (method
);
2331 if (del
&& !del
->target
&& del
->method
&& mono_method_signature_internal (del
->method
)->hasthis
) {
2332 if (!(del
->method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) && !m_class_is_valuetype (del
->method
->klass
) && sig
->param_count
== mono_method_signature_internal (del
->method
)->param_count
+ 1) {
2333 /* The first argument of the delegate is passed as this, the normal invoke code can handle this */
2337 target_method
= del
->method
;
2340 if (del
&& del
->method
&& mono_method_signature_internal (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2341 static_method_with_first_arg_bound
= TRUE
;
2342 target_method
= del
->method
;
2345 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
2349 MonoMethodSignature
*ctor_sig
;
2350 MonoMethodSignature
*sig
;
2353 /* protected by the marshal lock, contains CtorSigPair pointers */
2354 static GSList
*strsig_list
= NULL
;
2356 static MonoMethodSignature
*
2357 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
2359 MonoMethodSignature
*callsig
;
2363 mono_marshal_lock ();
2365 for (item
= strsig_list
; item
; item
= item
->next
) {
2366 cs
= (CtorSigPair
*)item
->data
;
2367 /* mono_metadata_signature_equal () is safe to call with the marshal lock
2368 * because it is lock-free.
2370 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
2375 mono_marshal_unlock ();
2379 static MonoMethodSignature
*
2380 add_string_ctor_signature (MonoMethod
*method
)
2382 MonoMethodSignature
*callsig
;
2385 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2386 callsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2387 cs
= g_new (CtorSigPair
, 1);
2389 cs
->ctor_sig
= mono_method_signature_internal (method
);
2391 mono_marshal_lock ();
2392 strsig_list
= g_slist_prepend (strsig_list
, cs
);
2393 mono_marshal_unlock ();
2398 * mono_marshal_get_string_ctor_signature:
2400 * Return the modified signature used by string ctors (they return the newly created
2403 MonoMethodSignature
*
2404 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
2406 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2408 sig
= add_string_ctor_signature (method
);
2414 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
2417 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2420 /* The result needs loaded indirectly */
2424 /* Can't share this with 'I' as that needs another indirection */
2425 return m_class_get_this_arg (mono_defaults
.int_class
);
2428 if (MONO_TYPE_IS_REFERENCE (t
))
2429 return mono_get_object_type ();
2432 /* The result needs to be boxed */
2437 /* Can't share these as the argument needs to be loaded using sign/zero extension */
2440 return m_class_get_byval_arg (mono_defaults.sbyte_class);
2442 return m_class_get_byval_arg (mono_defaults.int16_class);
2444 return mono_get_int32_type ();
2447 return m_class_get_byval_arg (mono_defaults
.int64_class
);
2448 case MONO_TYPE_BOOLEAN
:
2449 return m_class_get_byval_arg (mono_defaults
.byte_class
);
2450 case MONO_TYPE_CHAR
:
2451 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
2453 return mono_get_int_type ();
2454 case MONO_TYPE_VALUETYPE
:
2455 if (m_class_is_enumtype (t
->data
.klass
)) {
2456 t
= mono_class_enum_basetype_internal (t
->data
.klass
);
2466 * mono_marshal_get_runtime_invoke_sig:
2468 * Return a common signature used for sharing runtime invoke wrappers.
2470 static MonoMethodSignature
*
2471 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
2473 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
2476 res
->generic_param_count
= 0;
2477 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
2478 for (i
= 0; i
< res
->param_count
; ++i
)
2479 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
2485 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
2487 /* Can't share wrappers which return a vtype since it needs to be boxed */
2488 if (sig1
->ret
!= sig2
->ret
&& !(MONO_TYPE_IS_REFERENCE (sig1
->ret
) && MONO_TYPE_IS_REFERENCE (sig2
->ret
)) && !mono_metadata_type_equal (sig1
->ret
, sig2
->ret
))
2491 return mono_metadata_signature_equal (sig1
, sig2
);
2494 struct _MonoWrapperMethodCacheKey
{
2497 gboolean need_direct_wrapper
;
2500 struct _MonoWrapperSignatureCacheKey
{
2501 MonoMethodSignature
*signature
;
2505 typedef struct _MonoWrapperMethodCacheKey MonoWrapperMethodCacheKey
;
2506 typedef struct _MonoWrapperSignatureCacheKey MonoWrapperSignatureCacheKey
;
2509 wrapper_cache_method_key_hash (MonoWrapperMethodCacheKey
*key
)
2511 return mono_aligned_addr_hash (key
->method
) ^ (((!!key
->virtual_
) << 17) | ((!!key
->need_direct_wrapper
) << 19) * 17);
2515 wrapper_cache_signature_key_hash (MonoWrapperSignatureCacheKey
*key
)
2517 return mono_signature_hash (key
->signature
) ^ (((!!key
->valuetype
) << 18) * 17);
2521 wrapper_cache_method_key_equal (MonoWrapperMethodCacheKey
*key1
, MonoWrapperMethodCacheKey
*key2
)
2523 if (key1
->virtual_
!= key2
->virtual_
|| key1
->need_direct_wrapper
!= key2
->need_direct_wrapper
)
2525 return key1
->method
== key2
->method
;
2529 wrapper_cache_signature_key_equal (MonoWrapperSignatureCacheKey
*key1
, MonoWrapperSignatureCacheKey
*key2
)
2531 if (key1
->valuetype
!= key2
->valuetype
)
2533 return runtime_invoke_signature_equal (key1
->signature
, key2
->signature
);
2537 * mono_marshal_get_runtime_invoke:
2538 * Generates IL code for the runtime invoke function:
2540 * <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
2542 * We also catch exceptions if \p exc is not NULL.
2543 * If \p virtual is TRUE, then \p method is invoked virtually on \p this. This is useful since
2544 * it means that the compiled code for \p method does not have to be looked up
2545 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
2546 * its \p method argument.
2549 mono_marshal_get_runtime_invoke_full (MonoMethod
*method
, gboolean virtual_
, gboolean need_direct_wrapper
)
2551 MonoMethodSignature
*sig
, *csig
, *callsig
;
2552 MonoMethodBuilder
*mb
;
2553 GHashTable
*method_cache
= NULL
, *sig_cache
= NULL
;
2554 GHashTable
**cache_table
= NULL
;
2555 MonoClass
*target_klass
;
2556 MonoMethod
*res
= NULL
;
2557 static MonoMethodSignature
*cctor_signature
= NULL
;
2558 static MonoMethodSignature
*finalize_signature
= NULL
;
2560 const char *param_names
[16];
2562 MonoWrapperMethodCacheKey
*method_key
;
2563 MonoWrapperMethodCacheKey method_key_lookup_only
;
2564 memset (&method_key_lookup_only
, 0, sizeof (method_key_lookup_only
));
2565 method_key_lookup_only
.method
= method
;
2566 method_key_lookup_only
.virtual_
= virtual_
;
2567 method_key_lookup_only
.need_direct_wrapper
= need_direct_wrapper
;
2568 method_key
= &method_key_lookup_only
;
2572 if (!cctor_signature
) {
2573 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2574 cctor_signature
->ret
= mono_get_void_type ();
2576 if (!finalize_signature
) {
2577 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2578 finalize_signature
->ret
= mono_get_void_type ();
2579 finalize_signature
->hasthis
= 1;
2582 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_method_cache
;
2583 method_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_method_key_hash
, (GCompareFunc
) wrapper_cache_method_key_equal
);
2585 res
= mono_marshal_find_in_cache (method_cache
, method_key
);
2589 if (method
->string_ctor
) {
2590 callsig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2592 callsig
= add_string_ctor_signature (method
);
2594 if (method_is_dynamic (method
))
2595 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2597 callsig
= mono_method_signature_internal (method
);
2600 sig
= mono_method_signature_internal (method
);
2602 target_klass
= get_wrapper_target_class (m_class_get_image (method
->klass
));
2604 /* Try to share wrappers for non-corlib methods with simple signatures */
2605 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
2606 callsig
= cctor_signature
;
2607 target_klass
= mono_defaults
.object_class
;
2608 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
2609 callsig
= finalize_signature
;
2610 target_klass
= mono_defaults
.object_class
;
2613 if (need_direct_wrapper
|| virtual_
) {
2614 /* Already searched at the start. We cannot cache those wrappers based
2615 * on signatures because they contain a reference to the method */
2617 MonoMethodSignature
*tmp_sig
;
2619 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
2620 MonoWrapperSignatureCacheKey sig_key
;
2621 memset (&sig_key
, 0, sizeof (sig_key
));
2622 sig_key
.signature
= callsig
;
2623 sig_key
.valuetype
= m_class_is_valuetype (method
->klass
);
2625 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_signature_cache
;
2626 sig_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_signature_key_hash
, (GCompareFunc
) wrapper_cache_signature_key_equal
);
2628 /* from mono_marshal_find_in_cache */
2629 mono_marshal_lock ();
2630 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, &sig_key
);
2631 mono_marshal_unlock ();
2638 /* Make a copy of the signature from the image mempool */
2640 callsig
= mono_metadata_signature_dup_full (m_class_get_image (target_klass
), callsig
);
2644 csig
= mono_metadata_signature_alloc (m_class_get_image (target_klass
), 4);
2646 MonoType
*object_type
= mono_get_object_type ();
2647 MonoType
*int_type
= mono_get_int_type ();
2649 csig
->ret
= object_type
;
2650 if (m_class_is_valuetype (method
->klass
) && mono_method_signature_internal (method
)->hasthis
)
2651 csig
->params
[0] = get_runtime_invoke_type (m_class_get_this_arg (method
->klass
), FALSE
);
2653 csig
->params
[0] = object_type
;
2654 csig
->params
[1] = int_type
;
2655 csig
->params
[2] = int_type
;
2656 csig
->params
[3] = int_type
;
2659 /* This is called from runtime code so it has to be cdecl */
2660 csig
->call_convention
= MONO_CALL_C
;
2663 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : (need_direct_wrapper
? "runtime_invoke_direct" : "runtime_invoke"));
2664 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2667 param_names
[0] = "this";
2668 param_names
[1] = "params";
2669 param_names
[2] = "exc";
2670 param_names
[3] = "method";
2672 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, m_class_get_image (target_klass
), method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
2674 method_key
= g_new (MonoWrapperMethodCacheKey
, 1);
2675 memcpy (method_key
, &method_key_lookup_only
, sizeof (MonoWrapperMethodCacheKey
));
2677 if (need_direct_wrapper
|| virtual_
) {
2678 get_marshal_cb ()->mb_skip_visibility (mb
);
2679 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
2680 info
->d
.runtime_invoke
.method
= method
;
2681 res
= mono_mb_create_and_cache_full (method_cache
, method_key
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
2683 MonoWrapperSignatureCacheKey
*sig_key
= g_new0 (MonoWrapperSignatureCacheKey
, 1);
2684 sig_key
->signature
= callsig
;
2685 sig_key
->valuetype
= m_class_is_valuetype (method
->klass
);
2687 /* taken from mono_mb_create_and_cache */
2688 mono_marshal_lock ();
2689 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2690 mono_marshal_unlock ();
2692 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2693 info
->d
.runtime_invoke
.sig
= callsig
;
2695 /* Somebody may have created it before us */
2698 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2700 mono_marshal_lock ();
2701 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2704 g_hash_table_insert (sig_cache
, sig_key
, res
);
2705 g_hash_table_insert (method_cache
, method_key
, res
);
2707 mono_free_method (newm
);
2709 g_free (method_key
);
2711 mono_marshal_unlock ();
2714 g_free (method_key
);
2717 /* end mono_mb_create_and_cache */
2726 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
2728 gboolean need_direct_wrapper
= FALSE
;
2731 need_direct_wrapper
= TRUE
;
2733 if (method
->dynamic
)
2734 need_direct_wrapper
= TRUE
;
2736 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2737 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2739 * Array Get/Set/Address methods. The JIT implements them using inline code
2740 * so we need to create an invoke wrapper which calls the method directly.
2742 need_direct_wrapper
= TRUE
;
2745 if (method
->string_ctor
) {
2746 /* Can't share this as we push a string as this */
2747 need_direct_wrapper
= TRUE
;
2750 return mono_marshal_get_runtime_invoke_full (method
, virtual_
, need_direct_wrapper
);
2753 #ifndef ENABLE_ILGEN
2755 emit_runtime_invoke_body_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
2756 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
2757 gboolean virtual_
, gboolean need_direct_wrapper
)
2762 emit_runtime_invoke_dynamic_noilgen (MonoMethodBuilder
*mb
)
2768 * mono_marshal_get_runtime_invoke_dynamic:
2770 * Return a method which can be used to invoke managed methods from native code
2772 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
2773 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
2774 * ARGS should point to an architecture specific structure containing
2775 * the arguments and space for the return value.
2776 * The other arguments are the same as for runtime_invoke (), except that
2777 * ARGS should contain the this argument too.
2778 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
2779 * is only one copy of it, which is useful in full-aot.
2782 mono_marshal_get_runtime_invoke_dynamic (void)
2784 static MonoMethod
*method
;
2785 MonoMethodSignature
*csig
;
2786 MonoMethodBuilder
*mb
;
2793 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
2795 MonoType
*void_type
= mono_get_void_type ();
2796 MonoType
*int_type
= mono_get_int_type ();
2798 csig
->ret
= void_type
;
2799 csig
->params
[0] = int_type
;
2800 csig
->params
[1] = int_type
;
2801 csig
->params
[2] = int_type
;
2802 csig
->params
[3] = int_type
;
2804 name
= g_strdup ("runtime_invoke_dynamic");
2805 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2808 get_marshal_cb ()->emit_runtime_invoke_dynamic (mb
);
2810 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
2812 mono_marshal_lock ();
2813 /* double-checked locking */
2815 method
= mono_mb_create (mb
, csig
, 16, info
);
2817 mono_marshal_unlock ();
2825 * mono_marshal_get_runtime_invoke_for_sig:
2827 * Return a runtime invoke wrapper for a given signature.
2830 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
2832 MonoMethodSignature
*csig
, *callsig
;
2833 MonoMethodBuilder
*mb
;
2835 GHashTable
*cache
= NULL
;
2836 GHashTable
**cache_table
= NULL
;
2837 MonoMethod
*res
= NULL
;
2839 const char *param_names
[16];
2842 /* A simplified version of mono_marshal_get_runtime_invoke */
2844 image
= mono_defaults
.corlib
;
2846 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
2848 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
2850 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
2851 (GCompareFunc
)runtime_invoke_signature_equal
);
2853 /* from mono_marshal_find_in_cache */
2854 mono_marshal_lock ();
2855 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2856 mono_marshal_unlock ();
2863 /* Make a copy of the signature from the image mempool */
2864 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
2866 MonoType
*object_type
= mono_get_object_type ();
2867 MonoType
*int_type
= mono_get_int_type ();
2868 csig
= mono_metadata_signature_alloc (image
, 4);
2869 csig
->ret
= object_type
;
2870 csig
->params
[0] = object_type
;
2871 csig
->params
[1] = int_type
;
2872 csig
->params
[2] = int_type
;
2873 csig
->params
[3] = int_type
;
2876 /* This is called from runtime code so it has to be cdecl */
2877 csig
->call_convention
= MONO_CALL_C
;
2880 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
2881 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2884 param_names
[0] = "this";
2885 param_names
[1] = "params";
2886 param_names
[2] = "exc";
2887 param_names
[3] = "method";
2889 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
2891 /* taken from mono_mb_create_and_cache */
2892 mono_marshal_lock ();
2893 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2894 mono_marshal_unlock ();
2896 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2897 info
->d
.runtime_invoke
.sig
= callsig
;
2899 /* Somebody may have created it before us */
2902 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2904 mono_marshal_lock ();
2905 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2908 g_hash_table_insert (cache
, callsig
, res
);
2910 mono_free_method (newm
);
2912 mono_marshal_unlock ();
2915 /* end mono_mb_create_and_cache */
2922 #ifndef ENABLE_ILGEN
2924 emit_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
2929 emit_return_noilgen (MonoMethodBuilder
*mb
)
2935 * mono_marshal_get_icall_wrapper:
2936 * Generates IL code for the JIT icall wrapper. The generated method
2937 * calls the unmanaged code in \p callinfo->func.
2940 mono_marshal_get_icall_wrapper (MonoJitICallInfo
*callinfo
, gboolean check_exceptions
)
2942 MonoMethodSignature
*csig
, *csig2
;
2943 MonoMethodBuilder
*mb
;
2947 gconstpointer
const func
= callinfo
->func
;
2949 GHashTable
*cache
= get_cache (& m_class_get_image (mono_defaults
.object_class
)->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
2950 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
2953 MonoMethodSignature
*const sig
= callinfo
->sig
;
2954 g_assert (sig
->pinvoke
);
2956 char *const name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
2957 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
2959 mb
->method
->save_lmf
= 1;
2961 /* Add an explicit this argument */
2963 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
2965 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2967 get_marshal_cb ()->emit_icall_wrapper (mb
, callinfo
, csig2
, check_exceptions
);
2969 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2971 if (csig
->call_convention
== MONO_CALL_VARARG
)
2972 csig
->call_convention
= 0;
2974 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
2975 info
->d
.icall
.jit_icall_id
= mono_jit_icall_info_id (callinfo
);
2976 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
2984 mono_marshal_get_aot_init_wrapper_name (MonoAotInitSubtype subtype
)
2986 const char *name
= NULL
;
2988 case AOT_INIT_METHOD
:
2989 name
= "init_method";
2991 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
2992 name
= "init_method_gshared_mrgctx";
2994 case AOT_INIT_METHOD_GSHARED_THIS
:
2995 name
= "init_method_gshared_this";
2997 case AOT_INIT_METHOD_GSHARED_VTABLE
:
2998 name
= "init_method_gshared_vtable";
3001 g_assert_not_reached ();
3007 mono_marshal_get_aot_init_wrapper (MonoAotInitSubtype subtype
)
3009 MonoMethodBuilder
*mb
;
3012 MonoMethodSignature
*csig
= NULL
;
3013 MonoType
*void_type
= mono_get_void_type ();
3014 MonoType
*int_type
= mono_get_int_type ();
3015 const char *name
= mono_marshal_get_aot_init_wrapper_name (subtype
);
3018 case AOT_INIT_METHOD
:
3019 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
3020 csig
->ret
= void_type
;
3021 csig
->params
[0] = int_type
;
3022 csig
->params
[1] = int_type
;
3024 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
3025 case AOT_INIT_METHOD_GSHARED_THIS
:
3026 case AOT_INIT_METHOD_GSHARED_VTABLE
:
3027 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3028 csig
->ret
= void_type
;
3029 csig
->params
[0] = int_type
;
3030 csig
->params
[1] = int_type
;
3031 csig
->params
[2] = int_type
;
3034 g_assert_not_reached ();
3037 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
3039 // Just stub out the method with a "CEE_RET"
3040 // Our codegen backend generates other code here
3041 get_marshal_cb ()->emit_return (mb
);
3043 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_AOT_INIT
);
3044 info
->d
.aot_init
.subtype
= subtype
;
3045 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
3052 * mono_marshal_get_llvm_func_wrapper:
3054 * Return a dummy wrapper which represents an LLVM function to the
3055 * rest of the runtime for EH etc. purposes. The body of the method is
3059 mono_marshal_get_llvm_func_wrapper (MonoLLVMFuncWrapperSubtype subtype
)
3061 MonoMethodBuilder
*mb
;
3064 MonoMethodSignature
*csig
= NULL
;
3065 MonoType
*void_type
= mono_get_void_type ();
3066 char *name
= g_strdup_printf ("llvm_func_wrapper_%d", subtype
);
3068 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
3069 csig
->ret
= void_type
;
3071 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
3073 // Just stub out the method with a "CEE_RET"
3074 // Our codegen backend generates other code here
3075 get_marshal_cb ()->emit_return (mb
);
3077 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_LLVM_FUNC
);
3078 info
->d
.llvm_func
.subtype
= subtype
;
3079 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
3085 #ifndef ENABLE_ILGEN
3087 emit_marshal_custom_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3088 MonoMarshalSpec
*spec
,
3089 int conv_arg
, MonoType
**conv_arg_type
,
3090 MarshalAction action
)
3092 MonoType
*int_type
= mono_get_int_type ();
3093 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
3094 *conv_arg_type
= int_type
;
3099 emit_marshal_asany_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3100 MonoMarshalSpec
*spec
,
3101 int conv_arg
, MonoType
**conv_arg_type
,
3102 MarshalAction action
)
3108 emit_marshal_vtype_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3109 MonoMarshalSpec
*spec
,
3110 int conv_arg
, MonoType
**conv_arg_type
,
3111 MarshalAction action
)
3117 emit_marshal_string_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3118 MonoMarshalSpec
*spec
,
3119 int conv_arg
, MonoType
**conv_arg_type
,
3120 MarshalAction action
)
3122 MonoType
*int_type
= mono_get_int_type ();
3124 case MARSHAL_ACTION_CONV_IN
:
3125 *conv_arg_type
= int_type
;
3127 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3128 *conv_arg_type
= int_type
;
3136 emit_marshal_safehandle_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3137 MonoMarshalSpec
*spec
, int conv_arg
,
3138 MonoType
**conv_arg_type
, MarshalAction action
)
3140 MonoType
*int_type
= mono_get_int_type ();
3141 if (action
== MARSHAL_ACTION_CONV_IN
)
3142 *conv_arg_type
= int_type
;
3148 emit_marshal_handleref_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3149 MonoMarshalSpec
*spec
, int conv_arg
,
3150 MonoType
**conv_arg_type
, MarshalAction action
)
3152 MonoType
*int_type
= mono_get_int_type ();
3153 if (action
== MARSHAL_ACTION_CONV_IN
)
3154 *conv_arg_type
= int_type
;
3160 emit_marshal_object_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3161 MonoMarshalSpec
*spec
,
3162 int conv_arg
, MonoType
**conv_arg_type
,
3163 MarshalAction action
)
3165 MonoType
*int_type
= mono_get_int_type ();
3166 if (action
== MARSHAL_ACTION_CONV_IN
)
3167 *conv_arg_type
= int_type
;
3172 emit_marshal_variant_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3173 MonoMarshalSpec
*spec
,
3174 int conv_arg
, MonoType
**conv_arg_type
,
3175 MarshalAction action
)
3177 g_assert_not_reached ();
3182 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
3184 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
3185 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
3187 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
3189 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
3199 #ifndef ENABLE_ILGEN
3201 emit_marshal_array_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3202 MonoMarshalSpec
*spec
,
3203 int conv_arg
, MonoType
**conv_arg_type
,
3204 MarshalAction action
)
3206 MonoType
*int_type
= mono_get_int_type ();
3207 MonoType
*object_type
= mono_get_object_type ();
3209 case MARSHAL_ACTION_CONV_IN
:
3210 *conv_arg_type
= object_type
;
3212 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3213 *conv_arg_type
= int_type
;
3221 mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
3224 return mono_get_int32_type ();
3226 switch (spec
->native
) {
3227 case MONO_NATIVE_I1
:
3228 case MONO_NATIVE_U1
:
3229 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3230 case MONO_NATIVE_VARIANTBOOL
:
3231 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
3232 return m_class_get_byval_arg (mono_defaults
.int16_class
);
3233 case MONO_NATIVE_BOOLEAN
:
3234 return mono_get_int32_type ();
3236 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3237 return mono_get_int32_type ();
3243 mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
3245 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3247 switch (spec
->native
) {
3248 case MONO_NATIVE_I1
:
3249 case MONO_NATIVE_U1
:
3250 conv_arg_class
= mono_defaults
.byte_class
;
3251 if (ldop
) *ldop
= CEE_LDIND_I1
;
3253 case MONO_NATIVE_VARIANTBOOL
:
3254 conv_arg_class
= mono_defaults
.int16_class
;
3255 if (ldop
) *ldop
= CEE_LDIND_I2
;
3257 case MONO_NATIVE_BOOLEAN
:
3260 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3263 return conv_arg_class
;
3266 #ifndef ENABLE_ILGEN
3268 emit_marshal_boolean_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3269 MonoMarshalSpec
*spec
,
3270 int conv_arg
, MonoType
**conv_arg_type
,
3271 MarshalAction action
)
3273 MonoType
*int_type
= mono_get_int_type ();
3275 case MARSHAL_ACTION_CONV_IN
:
3277 *conv_arg_type
= int_type
;
3279 *conv_arg_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, NULL
);
3282 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3283 MonoClass
* conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
3285 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3287 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3296 emit_marshal_ptr_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3297 MonoMarshalSpec
*spec
, int conv_arg
,
3298 MonoType
**conv_arg_type
, MarshalAction action
)
3304 emit_marshal_char_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3305 MonoMarshalSpec
*spec
, int conv_arg
,
3306 MonoType
**conv_arg_type
, MarshalAction action
)
3312 emit_marshal_scalar_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3313 MonoMarshalSpec
*spec
, int conv_arg
,
3314 MonoType
**conv_arg_type
, MarshalAction action
)
3321 mono_emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3322 MonoMarshalSpec
*spec
, int conv_arg
,
3323 MonoType
**conv_arg_type
, MarshalAction action
)
3325 /* Ensure that we have marshalling info for this param */
3326 mono_marshal_load_type_info (mono_class_from_mono_type_internal (t
));
3328 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
3329 return get_marshal_cb ()->emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3331 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
3332 return get_marshal_cb ()->emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3335 case MONO_TYPE_VALUETYPE
:
3336 if (t
->data
.klass
== mono_class_try_get_handleref_class ())
3337 return get_marshal_cb ()->emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3339 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3340 case MONO_TYPE_STRING
:
3341 return get_marshal_cb ()->emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3342 case MONO_TYPE_CLASS
:
3343 case MONO_TYPE_OBJECT
:
3344 #if !defined(DISABLE_COM)
3345 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
3346 return get_marshal_cb ()->emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3349 #if !defined(DISABLE_COM)
3350 if ((spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
3351 spec
->native
== MONO_NATIVE_IDISPATCH
||
3352 spec
->native
== MONO_NATIVE_INTERFACE
)) ||
3353 (t
->type
== MONO_TYPE_CLASS
&& mono_cominterop_is_interface(t
->data
.klass
)))
3354 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3355 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
3356 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
3357 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
3358 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3361 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
3362 mono_class_is_subclass_of_internal (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
3363 return get_marshal_cb ()->emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3365 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3366 case MONO_TYPE_ARRAY
:
3367 case MONO_TYPE_SZARRAY
:
3368 return get_marshal_cb ()->emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3369 case MONO_TYPE_BOOLEAN
:
3370 return get_marshal_cb ()->emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3372 return get_marshal_cb ()->emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3373 case MONO_TYPE_CHAR
:
3374 return get_marshal_cb ()->emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3387 case MONO_TYPE_FNPTR
:
3388 return get_marshal_cb ()->emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3389 case MONO_TYPE_GENERICINST
:
3390 if (mono_type_generic_inst_is_valuetype (t
))
3391 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3393 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3399 #ifndef ENABLE_ILGEN
3401 emit_create_string_hack_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
3406 emit_native_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*pinfo
)
3412 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean set_default
)
3414 MonoMethodSignature
*sig
;
3419 * Under windows, delegates passed to native code must use the STDCALL
3420 * calling convention.
3423 csig
->call_convention
= MONO_CALL_STDCALL
;
3426 sig
= mono_method_signature_internal (method
);
3430 cmod_count
= mono_type_custom_modifier_count (sig
->ret
);
3432 /* Change default calling convention if needed */
3433 /* Why is this a modopt ? */
3434 if (cmod_count
== 0)
3437 for (i
= 0; i
< cmod_count
; ++i
) {
3440 MonoType
*cmod_type
= mono_type_get_custom_modifier (sig
->ret
, i
, &required
, error
);
3441 mono_error_assert_ok (error
);
3442 MonoClass
*cmod_class
= mono_class_from_mono_type_internal (cmod_type
);
3443 if ((m_class_get_image (cmod_class
) == mono_defaults
.corlib
) && !strcmp (m_class_get_name_space (cmod_class
), "System.Runtime.CompilerServices")) {
3444 const char *cmod_class_name
= m_class_get_name (cmod_class
);
3445 if (!strcmp (cmod_class_name
, "CallConvCdecl"))
3446 csig
->call_convention
= MONO_CALL_C
;
3447 else if (!strcmp (cmod_class_name
, "CallConvStdcall"))
3448 csig
->call_convention
= MONO_CALL_STDCALL
;
3449 else if (!strcmp (cmod_class_name
, "CallConvFastcall"))
3450 csig
->call_convention
= MONO_CALL_FASTCALL
;
3451 else if (!strcmp (cmod_class_name
, "CallConvThiscall"))
3452 csig
->call_convention
= MONO_CALL_THISCALL
;
3458 * mono_marshal_get_native_wrapper:
3459 * \param method The \c MonoMethod to wrap.
3460 * \param check_exceptions Whenever to check for pending exceptions
3462 * Generates IL code for the pinvoke wrapper. The generated method
3463 * calls the unmanaged code in \c piinfo->addr.
3466 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
3468 MonoMethodSignature
*sig
, *csig
;
3469 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
3470 MonoMethodBuilder
*mb
;
3471 MonoMarshalSpec
**mspecs
;
3474 gboolean pinvoke
= FALSE
;
3475 gboolean skip_gc_trans
= FALSE
;
3478 ERROR_DECL (emitted_error
);
3481 g_assert (method
!= NULL
);
3482 g_assertf (mono_method_signature_internal (method
)->pinvoke
, "%s flags:%X iflags:%X param_count:%X",
3483 method
->name
, method
->flags
, method
->iflags
, mono_method_signature_internal (method
)->param_count
);
3485 GHashTable
**cache_ptr
;
3487 MonoType
*string_type
= m_class_get_byval_arg (mono_defaults
.string_class
);
3490 if (check_exceptions
)
3491 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
3493 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
3495 if (check_exceptions
)
3496 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
3498 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
3501 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
3503 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3506 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
3507 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
3511 return mono_cominterop_get_native_wrapper (method
);
3513 g_assert_not_reached ();
3517 sig
= mono_method_signature_internal (method
);
3519 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3520 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
3523 if (!piinfo
->addr
) {
3525 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
3526 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "Method contains unsupported native code");
3528 mono_lookup_pinvoke_call_internal (method
, emitted_error
);
3530 if (!aot
|| (method
->klass
== mono_defaults
.string_class
))
3531 piinfo
->addr
= mono_lookup_internal_call (method
);
3535 /* hack - redirect certain string constructors to CreateString */
3536 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
3539 g_assert (!pinvoke
);
3540 g_assert (method
->string_ctor
);
3541 g_assert (sig
->hasthis
);
3543 /* CreateString returns a value */
3544 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3545 csig
->ret
= string_type
;
3549 #ifdef ENABLE_NETCORE
3551 while ((m
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
3553 * Find the corresponding String::Ctor () method which has the same signature but its static
3554 * and returns a string.
3556 if (!strcmp ("Ctor", m
->name
)) {
3559 MonoMethodSignature
*rsig
= mono_method_signature_internal (m
);
3560 if (csig
->param_count
== rsig
->param_count
) {
3561 for (i
= 0; i
< csig
->param_count
; ++i
)
3562 if (!mono_metadata_type_equal (csig
->params
[i
], rsig
->params
[i
]))
3564 if (i
== csig
->param_count
) {
3573 while ((m
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
3574 if (!strcmp ("CreateString", m
->name
) &&
3575 mono_metadata_signature_equal (csig
, mono_method_signature_internal (m
))) {
3585 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
3586 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
3588 /* create a wrapper to preserve .ctor in stack trace */
3589 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
3591 get_marshal_cb ()->emit_create_string_hack (mb
, csig
, res
);
3593 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
3594 info
->d
.string_ctor
.method
= method
;
3596 /* use native_wrapper_cache because internal calls are looked up there */
3597 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3598 csig
->param_count
+ 1, info
, NULL
);
3604 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3606 mb
->method
->save_lmf
= 1;
3609 * In AOT mode and embedding scenarios, it is possible that the icall is not
3610 * registered in the runtime doing the AOT compilation.
3612 if (!piinfo
->addr
&& !aot
) {
3613 /* if there's no code but the error isn't set, just use a fairly generic exception. */
3614 if (is_ok (emitted_error
))
3615 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "");
3616 get_marshal_cb ()->mb_emit_exception_for_error (mb
, emitted_error
);
3617 mono_error_cleanup (emitted_error
);
3619 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3620 info
->d
.managed_to_native
.method
= method
;
3622 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3624 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3625 csig
->param_count
+ 16, info
, NULL
);
3631 g_assert (is_ok (emitted_error
));
3633 /* internal calls: we simply push all arguments and call the method (no conversions) */
3634 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
3636 csig
= mono_metadata_signature_dup_add_this (get_method_image (method
), sig
, method
->klass
);
3638 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3640 //printf ("%s\n", mono_method_full_name (method, 1));
3642 /* hack - string constructors returns a value */
3643 if (method
->string_ctor
)
3644 csig
->ret
= string_type
;
3646 get_marshal_cb ()->emit_native_icall_wrapper (mb
, method
, csig
, check_exceptions
, aot
, piinfo
);
3648 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3649 info
->d
.managed_to_native
.method
= method
;
3651 csig
= mono_metadata_signature_dup_full (get_method_image (method
), csig
);
3653 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3662 g_assert (piinfo
->addr
);
3664 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3665 mono_marshal_set_callconv_from_modopt (method
, csig
, FALSE
);
3667 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
3668 mono_method_get_marshal_info (method
, mspecs
);
3670 #ifdef ENABLE_NETCORE
3671 if (mono_class_try_get_suppress_gc_transition_attribute_class ()) {
3672 MonoCustomAttrInfo
*cinfo
;
3675 cinfo
= mono_custom_attrs_from_method_checked (method
, error
);
3676 mono_error_assert_ok (error
);
3677 gboolean found
= FALSE
;
3679 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3680 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3681 if (ctor_class
== mono_class_try_get_suppress_gc_transition_attribute_class ()) {
3688 skip_gc_trans
= TRUE
;
3689 if (cinfo
&& !cinfo
->cached
)
3690 mono_custom_attrs_free (cinfo
);
3694 mono_marshal_emit_native_wrapper (get_method_image (mb
->method
), mb
, csig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
, skip_gc_trans
);
3695 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
3696 info
->d
.managed_to_native
.method
= method
;
3699 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3703 for (i
= sig
->param_count
; i
>= 0; i
--)
3705 mono_metadata_free_marshal_spec (mspecs
[i
]);
3708 /* mono_method_print_code (res); */
3714 * mono_marshal_get_native_func_wrapper:
3715 * \param image The image to use for memory allocation and for looking up custom marshallers.
3716 * \param sig The signature of the function
3717 * \param func The native function to wrap
3719 * \returns a wrapper method around native functions, similar to the pinvoke
3723 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
3724 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
3726 MonoMethodSignature
*csig
;
3728 SignaturePointerPair key
, *new_key
;
3729 MonoMethodBuilder
*mb
;
3738 // Generic types are not safe to place in MonoImage caches.
3739 g_assert (!sig
->is_inflated
);
3741 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
3742 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
3745 name
= g_strdup_printf ("wrapper_native_%p", func
);
3746 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3747 mb
->method
->save_lmf
= 1;
3749 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
, FALSE
);
3751 csig
= mono_metadata_signature_dup_full (image
, sig
);
3754 new_key
= g_new (SignaturePointerPair
,1);
3755 new_key
->sig
= csig
;
3756 new_key
->pointer
= func
;
3758 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
3764 mono_marshal_set_wrapper_info (res
, NULL
);
3770 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
3774 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
3776 MonoMethodSignature
*sig
, *csig
;
3777 MonoMethodBuilder
*mb
;
3782 MonoMethodPInvoke mpiinfo
;
3783 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
3784 MonoMarshalSpec
**mspecs
;
3785 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
3786 MonoImage
*image
= get_method_image (invoke
);
3789 // FIXME: include UnmanagedFunctionPointerAttribute info
3792 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
3794 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
3796 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
3799 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
3800 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
3802 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3803 mono_method_get_marshal_info (invoke
, mspecs
);
3804 /* Freed below so don't alloc from mempool */
3805 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
3808 name
= g_strdup_printf ("wrapper_aot_native");
3809 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3810 mb
->method
->save_lmf
= 1;
3812 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
, FALSE
);
3814 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
3815 info
->d
.managed_to_native
.method
= invoke
;
3817 g_assert (!sig
->hasthis
);
3818 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
3820 res
= mono_mb_create_and_cache_full (cache
, invoke
,
3821 mb
, csig
, csig
->param_count
+ 16,
3825 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3827 mono_metadata_free_marshal_spec (mspecs
[i
]);
3835 * mono_marshal_emit_managed_wrapper:
3837 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
3838 * the delegate which wraps the managed method to be called. For closed delegates,
3839 * it could have fewer parameters than the method it wraps.
3840 * THIS_LOC is the memory location where the target of the delegate is stored.
3843 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3845 get_marshal_cb ()->emit_managed_wrapper (mb
, invoke_sig
, mspecs
, m
, method
, target_handle
);
3848 #ifndef ENABLE_ILGEN
3850 emit_managed_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3852 MonoMethodSignature
*sig
, *csig
;
3854 MonoType
*int_type
= mono_get_int_type ();
3859 /* we first do all conversions */
3860 for (i
= 0; i
< sig
->param_count
; i
++) {
3861 MonoType
*t
= sig
->params
[i
];
3864 case MONO_TYPE_OBJECT
:
3865 case MONO_TYPE_CLASS
:
3866 case MONO_TYPE_VALUETYPE
:
3867 case MONO_TYPE_ARRAY
:
3868 case MONO_TYPE_SZARRAY
:
3869 case MONO_TYPE_STRING
:
3870 case MONO_TYPE_BOOLEAN
:
3871 mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
3875 if (!sig
->ret
->byref
) {
3876 switch (sig
->ret
->type
) {
3877 case MONO_TYPE_STRING
:
3878 csig
->ret
= int_type
;
3888 * mono_marshal_get_managed_wrapper:
3889 * Generates IL code to call managed methods from unmanaged code
3890 * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
3893 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
, MonoError
*error
)
3895 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
3896 MonoMethodBuilder
*mb
;
3897 MonoMethod
*res
, *invoke
;
3898 MonoMarshalSpec
**mspecs
;
3899 MonoMethodPInvoke piinfo
;
3902 EmitMarshalContext m
;
3904 g_assert (method
!= NULL
);
3907 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3908 mono_error_set_invalid_program (error
, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method
, TRUE
));
3913 * FIXME: Should cache the method+delegate type pair, since the same method
3914 * could be called with different delegates, thus different marshalling
3917 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
3919 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
3922 invoke
= mono_get_delegate_invoke_internal (delegate_klass
);
3923 invoke_sig
= mono_method_signature_internal (invoke
);
3925 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3926 mono_method_get_marshal_info (invoke
, mspecs
);
3928 sig
= mono_method_signature_internal (method
);
3930 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3932 /*the target gchandle must be the first entry after size and the wrapper itself.*/
3933 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
3935 /* we copy the signature, so that we can modify it */
3937 /* Need to free this later */
3938 csig
= mono_metadata_signature_dup (invoke_sig
);
3940 csig
= mono_metadata_signature_dup_full (get_method_image (method
), invoke_sig
);
3944 memset (&m
, 0, sizeof (m
));
3950 m
.image
= get_method_image (method
);
3952 mono_marshal_set_callconv_from_modopt (invoke
, csig
, TRUE
);
3954 /* The attribute is only available in Net 2.0 */
3955 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
3956 MonoCustomAttrInfo
*cinfo
;
3957 MonoCustomAttrEntry
*attr
;
3960 * The pinvoke attributes are stored in a real custom attribute. Obtain the
3961 * contents of the attribute without constructing it, as that might not be
3962 * possible when running in cross-compiling mode.
3964 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, error
);
3965 mono_error_assert_ok (error
);
3968 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3969 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3970 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
3971 attr
= &cinfo
->attrs
[i
];
3977 gpointer
*typed_args
, *named_args
;
3978 CattrNamedArg
*arginfo
;
3981 MonoBoolean set_last_error
= 0;
3985 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
3986 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
3987 g_assert (is_ok (error
));
3990 call_conv
= *(gint32
*)typed_args
[0];
3992 for (i
= 0; i
< num_named_args
; ++i
) {
3993 CattrNamedArg
*narg
= &arginfo
[i
];
3995 g_assert (narg
->field
);
3996 if (!strcmp (narg
->field
->name
, "CharSet")) {
3997 charset
= *(gint32
*)named_args
[i
];
3998 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
3999 set_last_error
= *(MonoBoolean
*)named_args
[i
];
4000 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
4001 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox_internal (o);
4002 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
4003 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox_internal (o);
4005 g_assert_not_reached ();
4007 g_free (named_args
[i
]);
4009 g_free (typed_args
[0]);
4010 g_free (typed_args
);
4011 g_free (named_args
);
4014 memset (&piinfo
, 0, sizeof (piinfo
));
4016 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
4018 csig
->call_convention
= call_conv
- 1;
4021 if (cinfo
&& !cinfo
->cached
)
4022 mono_custom_attrs_free (cinfo
);
4025 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
4027 if (!target_handle
) {
4030 // FIXME: Associate it with the method+delegate_klass pair
4031 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4032 info
->d
.native_to_managed
.method
= method
;
4033 info
->d
.native_to_managed
.klass
= delegate_klass
;
4035 res
= mono_mb_create_and_cache_full (cache
, method
,
4036 mb
, csig
, sig
->param_count
+ 16,
4039 get_marshal_cb ()->mb_set_dynamic (mb
);
4040 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
4044 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
4046 mono_metadata_free_marshal_spec (mspecs
[i
]);
4049 /* mono_method_print_code (res); */
4054 #ifndef ENABLE_ILGEN
4056 emit_vtfixup_ftnptr_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
4062 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
4066 MonoMethodSignature
*sig
;
4067 MonoMethodBuilder
*mb
;
4072 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, error
);
4074 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (error
));
4077 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
4078 MonoMethodSignature
*csig
;
4079 MonoMarshalSpec
**mspecs
;
4080 EmitMarshalContext m
;
4082 sig
= mono_method_signature_internal (method
);
4083 g_assert (!sig
->hasthis
);
4085 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
4086 mono_method_get_marshal_info (method
, mspecs
);
4088 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
4089 csig
= mono_metadata_signature_dup_full (image
, sig
);
4093 memset (&m
, 0, sizeof (m
));
4101 mono_marshal_set_callconv_from_modopt (method
, csig
, TRUE
);
4103 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
4105 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
4107 get_marshal_cb ()->mb_set_dynamic (mb
);
4108 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
4111 for (i
= sig
->param_count
; i
>= 0; i
--)
4113 mono_metadata_free_marshal_spec (mspecs
[i
]);
4116 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4117 mono_error_assert_ok (error
);
4118 return compiled_ptr
;
4121 sig
= mono_method_signature_internal (method
);
4122 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4124 param_count
= sig
->param_count
+ sig
->hasthis
;
4125 get_marshal_cb ()->emit_vtfixup_ftnptr (mb
, method
, param_count
, type
);
4126 get_marshal_cb ()->mb_set_dynamic (mb
);
4128 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
4131 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4132 mono_error_assert_ok (error
);
4133 return compiled_ptr
;
4136 #ifndef ENABLE_ILGEN
4138 emit_castclass_noilgen (MonoMethodBuilder
*mb
)
4144 * mono_marshal_get_castclass_with_cache:
4145 * This does the equivalent of \c mono_object_castclass_with_cache.
4148 mono_marshal_get_castclass_with_cache (void)
4150 static MonoMethod
*cached
;
4152 MonoMethodBuilder
*mb
;
4153 MonoMethodSignature
*sig
;
4159 MonoType
*object_type
= mono_get_object_type ();
4160 MonoType
*int_type
= mono_get_int_type ();
4162 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
4163 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4164 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4165 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4166 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4167 sig
->ret
= object_type
;
4170 get_marshal_cb ()->emit_castclass (mb
);
4172 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
4173 res
= mono_mb_create (mb
, sig
, 8, info
);
4176 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4177 mono_free_method (res
);
4178 mono_metadata_free_method_signature (sig
);
4185 /* this is an icall */
4187 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
4190 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, error
);
4191 if (mono_error_set_pending_exception (error
))
4194 if (mono_object_is_transparent_proxy (obj
))
4197 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
4199 cache_update
= cache_update
| 0x1;
4201 *cache
= cache_update
;
4206 #ifndef ENABLE_ILGEN
4208 emit_isinst_noilgen (MonoMethodBuilder
*mb
)
4214 * mono_marshal_get_isinst_with_cache:
4215 * This does the equivalent of \c mono_marshal_isinst_with_cache.
4218 mono_marshal_get_isinst_with_cache (void)
4220 static MonoMethod
*cached
;
4222 MonoMethodBuilder
*mb
;
4223 MonoMethodSignature
*sig
;
4229 MonoType
*object_type
= mono_get_object_type ();
4230 MonoType
*int_type
= mono_get_int_type ();
4232 mb
= mono_mb_new (mono_defaults
.object_class
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
4233 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4235 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4237 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4239 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4240 sig
->ret
= object_type
;
4243 get_marshal_cb ()->emit_isinst (mb
);
4245 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
4246 res
= mono_mb_create (mb
, sig
, 8, info
);
4249 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4250 mono_free_method (res
);
4251 mono_metadata_free_method_signature (sig
);
4258 #ifndef ENABLE_ILGEN
4260 emit_struct_to_ptr_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4266 * mono_marshal_get_struct_to_ptr:
4267 * \param klass \c MonoClass
4269 * Generates IL code for <code>StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)</code>
4272 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
4274 MonoMethodBuilder
*mb
;
4278 g_assert (klass
!= NULL
);
4280 mono_marshal_load_type_info (klass
);
4282 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4284 if ((res
= marshal_info
->str_to_ptr
))
4287 MONO_STATIC_POINTER_INIT (MonoMethod
, stoptr
)
4290 stoptr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "StructureToPtr", 3, 0, error
);
4291 mono_error_assert_ok (error
);
4293 MONO_STATIC_POINTER_INIT_END (MonoMethod
, stoptr
)
4297 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_OTHER
);
4299 get_marshal_cb ()->emit_struct_to_ptr (mb
, klass
);
4301 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
4302 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
4305 mono_marshal_lock ();
4306 if (!marshal_info
->str_to_ptr
)
4307 marshal_info
->str_to_ptr
= res
;
4309 res
= marshal_info
->str_to_ptr
;
4310 mono_marshal_unlock ();
4314 #ifndef ENABLE_ILGEN
4316 emit_ptr_to_struct_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4322 * mono_marshal_get_ptr_to_struct:
4323 * \param klass \c MonoClass
4324 * Generates IL code for <code>PtrToStructure (IntPtr src, object structure)</code>
4327 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
4329 MonoMethodBuilder
*mb
;
4330 static MonoMethodSignature
*ptostr
= NULL
;
4334 g_assert (klass
!= NULL
);
4336 mono_marshal_load_type_info (klass
);
4338 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4339 if (marshal_info
->ptr_to_str
)
4340 return marshal_info
->ptr_to_str
;
4343 MonoMethodSignature
*sig
;
4345 /* Create the signature corresponding to
4346 static void PtrToStructure (IntPtr ptr, object structure);
4347 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
4348 sig
= mono_icall_sig_void_ptr_object
;
4349 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4351 mono_memory_barrier ();
4355 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_OTHER
);
4357 get_marshal_cb ()->emit_ptr_to_struct (mb
, klass
);
4359 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
4360 res
= mono_mb_create (mb
, ptostr
, 0, info
);
4363 mono_marshal_lock ();
4364 if (!marshal_info
->ptr_to_str
)
4365 marshal_info
->ptr_to_str
= res
;
4367 res
= marshal_info
->ptr_to_str
;
4368 mono_marshal_unlock ();
4373 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
4374 * This is used to avoid infinite recursion since it is hard to determine where to
4375 * replace a method with its synchronized wrapper, and where not.
4376 * The runtime should execute METHOD instead of the wrapper.
4379 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
4381 MonoMethodBuilder
*mb
;
4383 MonoMethodSignature
*sig
;
4385 MonoGenericContext
*ctx
= NULL
;
4386 MonoGenericContainer
*container
= NULL
;
4388 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4389 ctx
= &((MonoMethodInflated
*)method
)->context
;
4390 method
= ((MonoMethodInflated
*)method
)->declaring
;
4391 container
= mono_method_get_generic_container (method
);
4393 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4394 g_assert (container
);
4397 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4398 get_marshal_cb ()->mb_emit_exception (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
4399 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4401 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4403 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
4404 info
->d
.synchronized_inner
.method
= method
;
4405 res
= mono_mb_create (mb
, sig
, 0, info
);
4409 res
= mono_class_inflate_generic_method_checked (res
, ctx
, error
);
4410 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4415 #ifndef ENABLE_ILGEN
4417 emit_synchronized_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4419 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4420 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4421 mono_class_set_type_load_failure (method
->klass
, "");
4429 * mono_marshal_get_synchronized_wrapper:
4430 * Generates IL code for the synchronized wrapper: the generated method
4431 * calls \p method while locking \c this or the parent type.
4434 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
4436 MonoMethodSignature
*sig
;
4437 MonoMethodBuilder
*mb
;
4441 MonoGenericContext
*ctx
= NULL
;
4442 MonoMethod
*orig_method
= NULL
;
4443 MonoGenericContainer
*container
= NULL
;
4447 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
4450 /* FIXME: Support generic methods too */
4451 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4452 orig_method
= method
;
4453 ctx
= &((MonoMethodInflated
*)method
)->context
;
4454 method
= ((MonoMethodInflated
*)method
)->declaring
;
4455 container
= mono_method_get_generic_container (method
);
4457 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4458 g_assert (container
);
4465 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4466 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
4470 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4471 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4475 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4478 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
4480 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4481 info
->d
.synchronized
.method
= method
;
4483 mono_marshal_lock ();
4485 MONO_STATIC_POINTER_INIT (MonoMethod
, enter_method
)
4486 MonoMethodDesc
*desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
4487 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4488 g_assert (enter_method
);
4489 mono_method_desc_free (desc
);
4490 MONO_STATIC_POINTER_INIT_END (MonoMethod
, enter_method
)
4492 MONO_STATIC_POINTER_INIT (MonoMethod
, exit_method
)
4493 MonoMethodDesc
*desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
4494 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4495 g_assert (exit_method
);
4496 mono_method_desc_free (desc
);
4497 MONO_STATIC_POINTER_INIT_END (MonoMethod
, exit_method
)
4499 MONO_STATIC_POINTER_INIT (MonoMethod
, gettypefromhandle_method
)
4500 MonoMethodDesc
*desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
4501 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
4502 g_assert (gettypefromhandle_method
);
4503 mono_method_desc_free (desc
);
4504 MONO_STATIC_POINTER_INIT_END (MonoMethod
, gettypefromhandle_method
)
4506 mono_marshal_unlock ();
4508 get_marshal_cb ()->mb_skip_visibility (mb
);
4509 get_marshal_cb ()->emit_synchronized_wrapper (mb
, method
, ctx
, container
, enter_method
, exit_method
, gettypefromhandle_method
);
4513 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4514 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4516 res
= mono_mb_create_and_cache_full (cache
, method
,
4517 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4524 #ifndef ENABLE_ILGEN
4526 emit_unbox_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4532 * mono_marshal_get_unbox_wrapper:
4533 * The returned method calls \p method unboxing the \c this argument.
4536 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
4538 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4539 MonoMethodBuilder
*mb
;
4544 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4546 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4549 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
4551 g_assert (sig
->hasthis
);
4553 get_marshal_cb ()->emit_unbox_wrapper (mb
, method
);
4555 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4556 info
->d
.unbox
.method
= method
;
4558 res
= mono_mb_create_and_cache_full (cache
, method
,
4559 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4562 /* mono_method_print_code (res); */
4568 is_monomorphic_array (MonoClass
*klass
)
4570 MonoClass
*element_class
;
4571 if (m_class_get_rank (klass
) != 1)
4574 element_class
= m_class_get_element_class (klass
);
4575 return mono_class_is_sealed (element_class
) || m_class_is_valuetype (element_class
);
4578 static MonoStelemrefKind
4579 get_virtual_stelemref_kind (MonoClass
*element_class
)
4581 if (element_class
== mono_defaults
.object_class
)
4582 return STELEMREF_OBJECT
;
4583 if (is_monomorphic_array (element_class
))
4584 return STELEMREF_SEALED_CLASS
;
4586 /* magic ifaces requires aditional checks for when the element type is an array */
4587 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && m_class_is_array_special_interface (element_class
))
4588 return STELEMREF_COMPLEX
;
4590 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
4591 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && !mono_class_has_variant_generic_params (element_class
))
4592 #ifdef COMPRESSED_INTERFACE_BITMAP
4593 return STELEMREF_COMPLEX
;
4595 return STELEMREF_INTERFACE
;
4597 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
4598 if (mono_class_is_marshalbyref (element_class
) || m_class_get_rank (element_class
) || mono_class_has_variant_generic_params (element_class
))
4599 return STELEMREF_COMPLEX
;
4600 if (mono_class_is_sealed (element_class
))
4601 return STELEMREF_SEALED_CLASS
;
4602 if (m_class_get_idepth (element_class
) <= MONO_DEFAULT_SUPERTABLE_SIZE
)
4603 return STELEMREF_CLASS_SMALL_IDEPTH
;
4605 return STELEMREF_CLASS
;
4610 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
4612 char *name
= mono_type_get_full_name (m_class_element_class (mono_object_class (array
)));
4613 printf ("slow vstore of %s\n", name
);
4618 #ifndef ENABLE_ILGEN
4620 emit_virtual_stelemref_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
4625 static const char *strelemref_wrapper_name
[] = {
4626 "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
4629 static const gchar
*
4630 mono_marshal_get_strelemref_wrapper_name (MonoStelemrefKind kind
)
4632 return strelemref_wrapper_name
[kind
];
4637 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
4638 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
4639 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
4640 * - Add a case for arrays of arrays.
4643 get_virtual_stelemref_wrapper (MonoStelemrefKind kind
)
4645 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
4646 static MonoMethodSignature
*signature
;
4647 MonoMethodBuilder
*mb
;
4650 const char *param_names
[16];
4653 if (cached_methods
[kind
])
4654 return cached_methods
[kind
];
4656 MonoType
*void_type
= mono_get_void_type ();
4657 MonoType
*object_type
= mono_get_object_type ();
4658 MonoType
*int_type
= mono_get_int_type ();
4660 name
= g_strdup_printf ("virt_stelemref_%s", mono_marshal_get_strelemref_wrapper_name (kind
));
4661 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
4665 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
4667 /* void this::stelemref (size_t idx, void* value) */
4668 sig
->ret
= void_type
;
4669 sig
->hasthis
= TRUE
;
4670 sig
->params
[0] = int_type
; /* this is a natural sized int */
4671 sig
->params
[1] = object_type
;
4675 param_names
[0] = "index";
4676 param_names
[1] = "value";
4677 get_marshal_cb ()->emit_virtual_stelemref (mb
, param_names
, kind
);
4679 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
4680 info
->d
.virtual_stelemref
.kind
= kind
;
4681 res
= mono_mb_create (mb
, signature
, 4, info
);
4682 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
4684 mono_marshal_lock ();
4685 if (!cached_methods
[kind
]) {
4686 cached_methods
[kind
] = res
;
4687 mono_marshal_unlock ();
4689 mono_marshal_unlock ();
4690 mono_free_method (res
);
4694 return cached_methods
[kind
];
4698 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
4700 MonoStelemrefKind kind
;
4702 g_assert (m_class_get_rank (array_class
) == 1);
4703 kind
= get_virtual_stelemref_kind (m_class_get_element_class (array_class
));
4705 return get_virtual_stelemref_wrapper (kind
);
4709 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
4714 *nwrappers
= STELEMREF_KIND_COUNT
;
4715 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
4716 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
4717 res
[i
] = get_virtual_stelemref_wrapper ((MonoStelemrefKind
)i
);
4721 #ifndef ENABLE_ILGEN
4723 emit_stelemref_noilgen (MonoMethodBuilder
*mb
)
4729 * mono_marshal_get_stelemref:
4732 mono_marshal_get_stelemref (void)
4734 MonoMethodSignature
*sig
;
4735 MonoMethodBuilder
*mb
;
4738 MONO_STATIC_POINTER_INIT (MonoMethod
, ret
)
4740 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
4742 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4744 MonoType
*void_type
= mono_get_void_type ();
4745 MonoType
*object_type
= mono_get_object_type ();
4746 MonoType
*int_type
= mono_get_int_type ();
4749 /* void stelemref (void* array, int idx, void* value) */
4750 sig
->ret
= void_type
;
4751 sig
->params
[0] = object_type
;
4752 sig
->params
[1] = int_type
; /* this is a natural sized int */
4753 sig
->params
[2] = object_type
;
4755 get_marshal_cb ()->emit_stelemref (mb
);
4757 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4758 ret
= mono_mb_create (mb
, sig
, 4, info
);
4761 MONO_STATIC_POINTER_INIT_END (MonoMethod
, ret
)
4766 #ifndef ENABLE_ILGEN
4768 mb_emit_byte_noilgen (MonoMethodBuilder
*mb
, guint8 op
)
4774 * mono_marshal_get_gsharedvt_in_wrapper:
4776 * This wrapper handles calls from normal code to gsharedvt code.
4779 mono_marshal_get_gsharedvt_in_wrapper (void)
4781 MONO_STATIC_POINTER_INIT (MonoMethod
, ret
)
4783 MonoMethodSignature
*sig
;
4784 MonoMethodBuilder
*mb
;
4787 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_OTHER
);
4789 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4790 sig
->ret
= mono_get_void_type ();
4793 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4795 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4797 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
4798 ret
= mono_mb_create (mb
, sig
, 4, info
);
4801 MONO_STATIC_POINTER_INIT_END (MonoMethod
, ret
)
4807 * mono_marshal_get_gsharedvt_out_wrapper:
4809 * This wrapper handles calls from gsharedvt code to normal code.
4812 mono_marshal_get_gsharedvt_out_wrapper (void)
4814 MONO_STATIC_POINTER_INIT (MonoMethod
, ret
)
4816 MonoMethodSignature
*sig
;
4817 MonoMethodBuilder
*mb
;
4820 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_OTHER
);
4822 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4823 sig
->ret
= mono_get_void_type ();
4826 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4828 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4830 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
4831 ret
= mono_mb_create (mb
, sig
, 4, info
);
4834 MONO_STATIC_POINTER_INIT_END (MonoMethod
, ret
)
4839 #ifndef ENABLE_ILGEN
4841 emit_array_address_noilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
4852 /* LOCKING: vars accessed under the marshal lock */
4853 static ArrayElemAddr
*elem_addr_cache
= NULL
;
4854 static int elem_addr_cache_size
= 0;
4855 static int elem_addr_cache_next
= 0;
4858 * mono_marshal_get_array_address:
4859 * \param rank rank of the array type
4860 * \param elem_size size in bytes of an element of an array.
4862 * Returns a MonoMethod that implements the code to get the address
4863 * of an element in a multi-dimenasional array of \p rank dimensions.
4864 * The returned method takes an array as the first argument and then
4865 * \p rank indexes for the \p rank dimensions.
4866 * If ELEM_SIZE is 0, read the array size from the array object.
4869 mono_marshal_get_array_address (int rank
, int elem_size
)
4872 MonoMethodBuilder
*mb
;
4873 MonoMethodSignature
*sig
;
4879 mono_marshal_lock ();
4880 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4881 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4882 ret
= elem_addr_cache
[i
].method
;
4886 mono_marshal_unlock ();
4890 MonoType
*object_type
= mono_get_object_type ();
4891 MonoType
*int_type
= mono_get_int_type ();
4892 MonoType
*int32_type
= mono_get_int32_type ();
4894 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
4896 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
4897 sig
->ret
= int_type
;
4898 sig
->params
[0] = object_type
;
4899 for (int i
= 0; i
< rank
; ++i
) {
4900 sig
->params
[i
+ 1] = int32_type
;
4903 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
4904 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4907 get_marshal_cb ()->emit_array_address (mb
, rank
, elem_size
);
4909 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
4910 info
->d
.element_addr
.rank
= rank
;
4911 info
->d
.element_addr
.elem_size
= elem_size
;
4912 ret
= mono_mb_create (mb
, sig
, 4, info
);
4915 /* cache the result */
4917 mono_marshal_lock ();
4918 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4919 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4920 /* FIXME: free ret */
4921 ret
= elem_addr_cache
[i
].method
;
4927 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
4928 int new_size
= elem_addr_cache_size
+ 4;
4929 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
4930 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
4931 g_free (elem_addr_cache
);
4932 elem_addr_cache
= new_array
;
4933 elem_addr_cache_size
= new_size
;
4935 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
4936 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
4937 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
4938 elem_addr_cache_next
++;
4940 mono_marshal_unlock ();
4944 #ifndef ENABLE_ILGEN
4946 emit_array_accessor_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4952 * mono_marshal_get_array_accessor_wrapper:
4954 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
4957 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
4959 MonoMethodSignature
*sig
;
4960 MonoMethodBuilder
*mb
;
4963 MonoGenericContext
*ctx
= NULL
;
4964 MonoMethod
*orig_method
= NULL
;
4968 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
4969 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
4970 * FIXME: Use generic methods.
4977 g_assert_not_reached ();
4979 cache
= get_cache (&get_method_image (method
)->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
4980 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4984 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4987 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4989 get_marshal_cb ()->emit_array_accessor_wrapper (mb
, method
, sig
, ctx
);
4991 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
4992 info
->d
.array_accessor
.method
= method
;
4996 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4997 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4999 res
= mono_mb_create_and_cache_full (cache
, method
,
5000 mb
, sig
, sig
->param_count
+ 16,
5011 mono_marshal_alloc_co_task_mem (size_t size
)
5014 /* This returns a valid pointer for size 0 on MS.NET */
5017 return g_try_malloc (size
);
5022 * mono_marshal_alloc:
5025 mono_marshal_alloc (gsize size
, MonoError
*error
)
5031 res
= mono_marshal_alloc_co_task_mem (size
);
5034 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
" bytes", size
);
5039 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
5041 ves_icall_marshal_alloc_impl (gsize size
, MonoError
*error
)
5043 return mono_marshal_alloc (size
, error
);
5049 mono_marshal_free_co_task_mem (void *ptr
)
5057 * mono_marshal_free:
5060 mono_marshal_free (gpointer ptr
)
5062 mono_marshal_free_co_task_mem (ptr
);
5066 * mono_marshal_free_array:
5069 mono_marshal_free_array (gpointer
*ptr
, int size
)
5076 for (i
= 0; i
< size
; i
++)
5081 mono_marshal_string_to_utf16 (MonoString
*s
)
5083 // FIXME This should be an intrinsic.
5084 // FIXMEcoop The input parameter is easy to deal with,
5085 // but what happens with the result?
5086 // See https://github.com/mono/mono/issues/12165.
5087 return s
? mono_string_chars_internal (s
) : NULL
;
5090 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
5092 mono_marshal_string_to_utf16_copy_impl (MonoStringHandle s
, MonoError
*error
)
5094 if (MONO_HANDLE_IS_NULL (s
))
5097 gsize
const length
= mono_string_handle_length (s
);
5098 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((length
+ 1) * sizeof (*res
), error
);
5099 return_val_if_nok (error
, NULL
);
5100 gchandle_t gchandle
= 0;
5101 memcpy (res
, mono_string_handle_pin_chars (s
, &gchandle
), length
* sizeof (*res
));
5102 mono_gchandle_free_internal (gchandle
);
5108 * mono_marshal_set_last_error:
5110 * This function is invoked to set the last error value from a P/Invoke call
5111 * which has \c SetLastError set.
5114 mono_marshal_set_last_error (void)
5116 /* This icall is called just after a P/Invoke call before the P/Invoke
5117 * wrapper transitions the runtime back to running mode. */
5119 MONO_REQ_GC_SAFE_MODE
;
5120 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
5122 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
5127 mono_marshal_set_last_error_windows (int error
)
5130 /* This icall is called just after a P/Invoke call before the P/Invoke
5131 * wrapper transitions the runtime back to running mode. */
5132 MONO_REQ_GC_SAFE_MODE
;
5133 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
5138 mono_marshal_clear_last_error (void)
5140 /* This icall is called just before a P/Invoke call. */
5142 SetLastError (ERROR_SUCCESS
);
5149 copy_managed_common (MonoArrayHandle managed
, gconstpointer native
, gint32 start_index
,
5150 gint32 length
, gpointer
*managed_addr
, guint32
*gchandle
, MonoError
*error
)
5152 MONO_CHECK_ARG_NULL_HANDLE (managed
, 0);
5153 MONO_CHECK_ARG_NULL (native
, 0);
5155 MonoClass
*klass
= mono_handle_class (managed
);
5157 // FIXME? move checks to managed
5158 if (m_class_get_rank (klass
) != 1) {
5159 mono_error_set_argument (error
, "array", "array is multi-dimensional");
5162 if (start_index
< 0) {
5163 mono_error_set_argument (error
, "startIndex", "Must be >= 0");
5167 mono_error_set_argument (error
, "length", "Must be >= 0");
5170 if (start_index
+ length
> mono_array_handle_length (managed
)) {
5171 mono_error_set_argument (error
, "length", "start_index + length > array length");
5175 gsize
const element_size
= mono_array_element_size (klass
);
5177 // Handle generic arrays, which do not allow fixed.
5179 *managed_addr
= mono_array_handle_pin_with_size (managed
, element_size
, start_index
, gchandle
);
5181 return element_size
* length
;
5185 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArrayHandle src
, gint32 start_index
,
5186 gpointer dest
, gint32 length
, gconstpointer managed_source_addr
, MonoError
*error
);
5189 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArrayHandle src
, gint32 start_index
,
5190 gpointer dest
, gint32 length
, gconstpointer managed_source_addr
, MonoError
*error
)
5192 g_assert_not_netcore ();
5194 guint32 gchandle
= 0;
5195 gsize
const bytes
= copy_managed_common (src
, dest
, start_index
, length
, (gpointer
*)&managed_source_addr
, &gchandle
, error
);
5197 memmove (dest
, managed_source_addr
, bytes
); // no references should be involved
5198 mono_gchandle_free_internal (gchandle
);
5202 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gconstpointer src
, gint32 start_index
,
5203 MonoArrayHandle dest
, gint32 length
, gpointer managed_dest_addr
, MonoError
*error
);
5206 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gconstpointer src
, gint32 start_index
,
5207 MonoArrayHandle dest
, gint32 length
, gpointer managed_dest_addr
, MonoError
*error
)
5209 g_assert_not_netcore ();
5211 guint32 gchandle
= 0;
5212 gsize
const bytes
= copy_managed_common (dest
, src
, start_index
, length
, &managed_dest_addr
, &gchandle
, error
);
5214 memmove (managed_dest_addr
, src
, bytes
); // no references should be involved
5215 mono_gchandle_free_internal (gchandle
);
5219 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (const char *ptr
, MonoError
*error
);
5222 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (const char *ptr
, MonoError
*error
)
5224 g_assert_not_netcore ();
5227 return NULL_HANDLE_STRING
;
5228 return mono_string_new_handle (mono_domain_get (), ptr
, error
);
5232 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (const char *ptr
, gint32 len
, MonoError
*error
);
5235 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (const char *ptr
, gint32 len
, MonoError
*error
)
5237 g_assert_not_netcore ();
5240 mono_error_set_argument_null (error
, "ptr", "");
5241 return NULL_HANDLE_STRING
;
5243 return mono_string_new_utf8_len (mono_domain_get (), ptr
, len
, error
);
5247 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (const gunichar2
*ptr
, MonoError
*error
);
5250 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (const gunichar2
*ptr
, MonoError
*error
)
5252 g_assert_not_netcore ();
5255 const gunichar2
*t
= ptr
;
5258 return NULL_HANDLE_STRING
;
5263 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5264 return_val_if_nok (error
, NULL_HANDLE_STRING
);
5270 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (const gunichar2
*ptr
, gint32 len
, MonoError
*error
);
5273 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (const gunichar2
*ptr
, gint32 len
, MonoError
*error
)
5275 g_assert_not_netcore ();
5278 mono_error_set_argument_null (error
, "ptr", "");
5279 return NULL_HANDLE_STRING
;
5281 return mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5285 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5287 return GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
));
5291 ves_icall_System_Runtime_InteropServices_Marshal_SetLastWin32Error (guint32 err
)
5293 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (err
));
5297 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype
, MonoError
*error
)
5299 if (MONO_HANDLE_IS_NULL (rtype
)) {
5300 mono_error_set_argument_null (error
, "type", "");
5304 MonoType
* const type
= MONO_HANDLE_GETVAL (rtype
, type
);
5305 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
5306 if (!mono_class_init_checked (klass
, error
))
5309 guint32
const layout
= (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
);
5311 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
5312 return sizeof (gpointer
);
5313 } else if (type
->type
== MONO_TYPE_VOID
) {
5315 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5316 mono_error_set_argument_format (error
, "t", "Type %s cannot be marshaled as an unmanaged structure.", m_class_get_name (klass
));
5321 return (guint32
)mono_marshal_type_size (type
, NULL
, &align
, FALSE
, m_class_is_unicode (klass
));
5325 ves_icall_System_Runtime_InteropServices_Marshal_SizeOfHelper (MonoReflectionTypeHandle rtype
, MonoBoolean throwIfNotMarshalable
, MonoError
*error
)
5327 return ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (rtype
, error
);
5331 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObjectHandle obj
, gpointer dst
, MonoBoolean delete_old
, MonoError
*error
)
5333 MONO_CHECK_ARG_NULL_HANDLE_NAMED (obj
, "structure",);
5334 MONO_CHECK_ARG_NULL_NAMED (dst
, "ptr",);
5336 #ifdef ENABLE_NETCORE
5337 MonoClass
*klass
= mono_handle_class (obj
);
5338 if (m_class_is_auto_layout (klass
)) {
5339 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5342 if (m_class_is_ginst (klass
)) {
5343 mono_error_set_argument (error
, "structure", "The specified object must not be an instance of a generic type.");
5348 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (obj
));
5350 gpointer pa
[ ] = { MONO_HANDLE_RAW (obj
), &dst
, &delete_old
};
5352 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
5356 ptr_to_structure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5358 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (dst
));
5360 gpointer pa
[ ] = { &src
, MONO_HANDLE_RAW (dst
) };
5362 // FIXMEcoop? mono_runtime_invoke_handle causes a GC assertion failure in marshal2 with interpreter
5363 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5366 #ifdef ENABLE_NETCORE
5369 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructureInternal (gconstpointer src
, MonoObjectHandle dst
, MonoBoolean allow_vtypes
, MonoError
*error
)
5374 t
= m_class_get_byval_arg (mono_handle_class (dst
));
5375 if (!allow_vtypes
&& MONO_TYPE_ISSTRUCT (t
)) {
5376 mono_error_set_argument (error
, "structure", "The structure must not be a value class.");
5380 klass
= mono_class_from_mono_type_internal (t
);
5381 if (m_class_is_auto_layout (klass
)) {
5382 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5386 ptr_to_structure (src
, dst
, error
);
5392 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5396 MONO_CHECK_ARG_NULL (src
,);
5397 MONO_CHECK_ARG_NULL_HANDLE (dst
,);
5399 t
= mono_type_get_underlying_type (m_class_get_byval_arg (mono_handle_class (dst
)));
5401 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5402 mono_error_set_argument (error
, "dst", "Destination is a boxed value type.");
5406 ptr_to_structure (src
, dst
, error
);
5410 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gconstpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5415 MONO_CHECK_ARG_NULL_HANDLE (type
, NULL_HANDLE
);
5417 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5418 if (!mono_class_init_checked (klass
, error
))
5421 MonoObjectHandle res
= mono_object_new_handle (mono_domain_get (), klass
, error
);
5422 return_val_if_nok (error
, NULL_HANDLE
);
5424 ptr_to_structure (src
, res
, error
);
5425 return_val_if_nok (error
, NULL_HANDLE
);
5432 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type
, MonoStringHandle field_name
, MonoError
*error
)
5435 if (MONO_HANDLE_IS_NULL (ref_type
)) {
5436 mono_error_set_argument_null (error
, "t", "");
5439 if (MONO_HANDLE_IS_NULL (field_name
)) {
5440 #ifdef ENABLE_NETCORE
5441 mono_error_set_argument_null (error
, NULL
, "");
5443 mono_error_set_argument_null (error
, "fieldName", "");
5448 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (ref_type
))) {
5449 #ifdef ENABLE_NETCORE
5450 mono_error_set_argument (error
, "fieldName", "");
5452 mono_error_set_argument (error
, "type", "");
5457 char *fname
= mono_string_handle_to_utf8 (field_name
, error
);
5458 return_val_if_nok (error
, 0);
5460 MonoType
*type
= MONO_HANDLE_GETVAL (ref_type
, type
);
5461 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
5462 if (!mono_class_init_checked (klass
, error
))
5464 #ifdef ENABLE_NETCORE
5465 if (m_class_is_auto_layout (klass
)) {
5466 mono_error_set_argument (error
, NULL
, "");
5470 int match_index
= -1;
5471 while (klass
&& match_index
== -1) {
5472 MonoClassField
* field
;
5474 gpointer iter
= NULL
;
5475 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5476 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5478 if (!strcmp (fname
, mono_field_get_name (field
))) {
5485 if (match_index
== -1)
5486 klass
= m_class_get_parent (klass
);
5491 if(match_index
== -1) {
5492 /* Get back original class instance */
5493 klass
= mono_class_from_mono_type_internal (type
);
5495 mono_error_set_argument_format (error
, "fieldName", "Field passed in is not a marshaled member of the type %s", m_class_get_name (klass
));
5499 MonoMarshalType
*info
= mono_marshal_load_type_info (klass
);
5500 return info
->fields
[match_index
].offset
;
5506 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2
*utf16
, int length
);
5509 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2
*utf16
, int length
)
5511 g_assert_not_netcore ();
5515 char * const utf8
= mono_utf16_to_utf8 (utf16
, length
, error
);
5517 mono_error_set_pending_exception (error
);
5523 mono_marshal_alloc_hglobal (size_t size
)
5525 return g_try_malloc (size
);
5528 #endif /* !HOST_WIN32 */
5531 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2
*s
, int length
);
5534 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2
*s
, int length
)
5536 g_assert_not_netcore ();
5543 gsize
const len
= ((gsize
)length
+ 1) * 2;
5544 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc_hglobal_error (len
, error
);
5546 memcpy (res
, s
, length
* 2);
5550 mono_error_set_pending_exception (error
);
5555 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
5557 MonoMarshalType
*info
;
5560 info
= mono_marshal_load_type_info (klass
);
5562 for (i
= 0; i
< info
->num_fields
; i
++) {
5563 MonoMarshalConv conv
;
5564 MonoType
*ftype
= info
->fields
[i
].field
->type
;
5567 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5570 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
5571 m_class_is_unicode (klass
), &conv
);
5573 cpos
= ptr
+ info
->fields
[i
].offset
;
5576 case MONO_MARSHAL_CONV_NONE
:
5577 if (MONO_TYPE_ISSTRUCT (ftype
)) {
5578 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
5582 case MONO_MARSHAL_CONV_STR_LPWSTR
:
5583 /* We assume this field points inside a MonoString */
5585 case MONO_MARSHAL_CONV_STR_LPTSTR
:
5587 /* We assume this field points inside a MonoString
5591 case MONO_MARSHAL_CONV_STR_LPSTR
:
5592 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
5593 case MONO_MARSHAL_CONV_STR_TBSTR
:
5594 case MONO_MARSHAL_CONV_STR_UTF8STR
:
5595 mono_marshal_free (*(gpointer
*)cpos
);
5597 case MONO_MARSHAL_CONV_STR_BSTR
:
5598 mono_free_bstr (*(gpointer
*)cpos
);
5607 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5609 MONO_CHECK_ARG_NULL_NAMED (src
, "ptr",);
5610 MONO_CHECK_ARG_NULL_HANDLE_NAMED (type
, "structureType",);
5612 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (type
))) {
5613 mono_error_set_argument (error
, "structureType", "");
5617 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5618 if (!mono_class_init_checked (klass
, error
))
5620 #ifdef ENABLE_NETCORE
5621 if (m_class_is_auto_layout (klass
)) {
5622 mono_error_set_argument (error
, "structureType", "The specified structure must be blittable or have layout information.");
5628 mono_struct_delete_old (klass
, (char *)src
);
5632 mono_marshal_alloc_hglobal_error (gsize size
, MonoError
*error
)
5635 /* This returns a valid pointer for size 0 on MS.NET */
5638 void* p
= mono_marshal_alloc_hglobal (size
);
5640 mono_error_set_out_of_memory (error
, "");
5645 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gsize size
)
5648 void* result
= mono_marshal_alloc_hglobal_error (size
, error
);
5649 mono_error_set_pending_exception (error
);
5656 mono_marshal_realloc_hglobal (gpointer ptr
, size_t size
)
5658 return g_try_realloc (ptr
, size
);
5664 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gsize size
)
5666 gpointer res
= ptr
? mono_marshal_realloc_hglobal (ptr
, size
) : NULL
;
5670 mono_error_set_out_of_memory (error
, "");
5671 mono_error_set_pending_exception (error
);
5680 mono_marshal_free_hglobal (gpointer ptr
)
5688 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
5690 mono_marshal_free_hglobal (ptr
);
5694 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
)
5696 void *res
= mono_marshal_alloc_co_task_mem (size
);
5700 mono_error_set_out_of_memory (error
, "");
5701 mono_error_set_pending_exception (error
);
5708 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gsize size
);
5711 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gsize size
)
5713 g_assert_not_netcore ();
5715 void *res
= mono_marshal_alloc_co_task_mem (size
);
5719 mono_error_set_out_of_memory (error
, "");
5720 mono_error_set_pending_exception (error
);
5727 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
5729 mono_marshal_free_co_task_mem (ptr
);
5735 mono_marshal_realloc_co_task_mem (gpointer ptr
, size_t size
)
5737 return g_try_realloc (ptr
, size
);
5742 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
)
5744 void *res
= mono_marshal_realloc_co_task_mem (ptr
, size
);
5748 mono_error_set_out_of_memory (error
, "");
5749 mono_error_set_pending_exception (error
);
5755 #ifndef ENABLE_NETCORE
5757 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArrayHandle arrayobj
, int index
, MonoError
*error
)
5759 int esize
= mono_array_element_size (mono_handle_class (arrayobj
));
5760 return mono_array_addr_with_size_fast (MONO_HANDLE_RAW (arrayobj
), esize
, index
);
5765 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionTypeHandle type
, MonoError
*error
)
5767 MonoClass
*klass
= mono_type_get_class_internal (MONO_HANDLE_GETVAL (type
, type
));
5768 if (!mono_class_init_checked (klass
, error
))
5769 return MONO_HANDLE_CAST (MonoDelegate
, NULL_HANDLE
);
5771 return mono_ftnptr_to_delegate_impl (klass
, ftn
, error
);
5775 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate
, MonoError
*error
)
5777 return mono_delegate_to_ftnptr_impl (delegate
, error
);
5781 ves_icall_System_Runtime_InteropServices_Marshal_IsPinnableType (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5783 MonoClass
*klass
= mono_class_from_mono_type_internal (MONO_HANDLE_GETVAL (type_h
, type
));
5785 if (m_class_get_rank (klass
)) {
5786 MonoClass
*eklass
= m_class_get_element_class (klass
);
5787 if (m_class_is_primitive (eklass
))
5789 return eklass
!= mono_defaults
.object_class
&& m_class_is_blittable (eklass
);
5791 return m_class_is_blittable (klass
);
5795 * mono_marshal_is_loading_type_info:
5797 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
5801 mono_marshal_is_loading_type_info (MonoClass
*klass
)
5803 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5805 return g_slist_find (loads_list
, klass
) != NULL
;
5809 * mono_marshal_load_type_info:
5811 * Initialize \c klass::marshal_info using information from metadata. This function can
5812 * recursively call itself, and the caller is responsible to avoid that by calling
5813 * \c mono_marshal_is_loading_type_info beforehand.
5815 * LOCKING: Acquires the loader lock.
5818 mono_marshal_load_type_info (MonoClass
* klass
)
5821 guint32 native_size
= 0, min_align
= 1, packing
;
5822 MonoMarshalType
*info
;
5823 MonoClassField
* field
;
5828 g_assert (klass
!= NULL
);
5830 info
= mono_class_get_marshal_info (klass
);
5834 if (!m_class_is_inited (klass
))
5835 mono_class_init_internal (klass
);
5837 info
= mono_class_get_marshal_info (klass
);
5842 * This function can recursively call itself, so we keep the list of classes which are
5843 * under initialization in a TLS list.
5845 g_assert (!mono_marshal_is_loading_type_info (klass
));
5846 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5847 loads_list
= g_slist_prepend (loads_list
, klass
);
5848 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5851 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5852 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5854 if (mono_field_is_deleted (field
))
5859 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
5861 info
= (MonoMarshalType
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
5862 info
->num_fields
= count
;
5864 /* Try to find a size for this type in metadata */
5865 mono_metadata_packing_from_typedef (m_class_get_image (klass
), m_class_get_type_token (klass
), NULL
, &native_size
);
5867 if (m_class_get_parent (klass
)) {
5868 int parent_size
= mono_class_native_size (m_class_get_parent (klass
), NULL
);
5870 /* Add parent size to real size */
5871 native_size
+= parent_size
;
5872 info
->native_size
= parent_size
;
5875 packing
= m_class_get_packing_size (klass
) ? m_class_get_packing_size (klass
) : 8;
5878 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5882 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5885 if (mono_field_is_deleted (field
))
5887 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
5888 mono_metadata_field_info_with_mempool (m_class_get_image (klass
), mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
5889 NULL
, NULL
, &info
->fields
[j
].mspec
);
5891 info
->fields
[j
].field
= field
;
5893 if ((mono_class_num_fields (klass
) == 1) && (m_class_get_instance_size (klass
) == MONO_ABI_SIZEOF (MonoObject
)) &&
5894 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
5895 /* This field is a hack inserted by MCS to empty structures */
5900 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
5901 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
5902 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5903 &align
, TRUE
, m_class_is_unicode (klass
));
5904 align
= m_class_get_packing_size (klass
) ? MIN (m_class_get_packing_size (klass
), align
): align
;
5905 min_align
= MAX (align
, min_align
);
5906 info
->fields
[j
].offset
= info
->native_size
;
5907 info
->fields
[j
].offset
+= align
- 1;
5908 info
->fields
[j
].offset
&= ~(align
- 1);
5909 info
->native_size
= info
->fields
[j
].offset
+ size
;
5911 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
5912 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5913 &align
, TRUE
, m_class_is_unicode (klass
));
5914 min_align
= MAX (align
, min_align
);
5915 info
->fields
[j
].offset
= field
->offset
- MONO_ABI_SIZEOF (MonoObject
);
5916 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
5922 if (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_PTR
)
5923 info
->native_size
= TARGET_SIZEOF_VOID_P
;
5925 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5926 info
->native_size
= MAX (native_size
, info
->native_size
);
5928 * If the provided Size is equal or larger than the calculated size, and there
5929 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
5931 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
5932 if (native_size
&& native_size
== info
->native_size
&& m_class_get_packing_size (klass
) == 0)
5935 min_align
= MIN (min_align
, packing
);
5939 if (info
->native_size
& (min_align
- 1)) {
5940 info
->native_size
+= min_align
- 1;
5941 info
->native_size
&= ~(min_align
- 1);
5944 info
->min_align
= min_align
;
5946 /* Update the class's blittable info, if the layouts don't match */
5947 if (info
->native_size
!= mono_class_value_size (klass
, NULL
)) {
5948 mono_class_set_nonblittable (klass
); /* FIXME - how is this justified? what if we previously thought the class was blittable? */
5951 /* If this is an array type, ensure that we have element info */
5952 if (m_class_get_rank (klass
) && !mono_marshal_is_loading_type_info (m_class_get_element_class (klass
))) {
5953 mono_marshal_load_type_info (m_class_get_element_class (klass
));
5956 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5957 loads_list
= g_slist_remove (loads_list
, klass
);
5958 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5960 mono_marshal_lock ();
5961 MonoMarshalType
*info2
= mono_class_get_marshal_info (klass
);
5963 /*We do double-checking locking on marshal_info */
5964 mono_memory_barrier ();
5965 mono_class_set_marshal_info (klass
, info
);
5966 ++class_marshal_info_count
;
5970 mono_marshal_unlock ();
5976 * mono_class_native_size:
5977 * \param klass a class
5978 * \returns the native size of an object instance (when marshaled
5979 * to unmanaged code)
5982 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
5984 MonoMarshalType
*info
= mono_class_get_marshal_info (klass
);
5986 if (mono_marshal_is_loading_type_info (klass
)) {
5991 mono_marshal_load_type_info (klass
);
5993 info
= mono_class_get_marshal_info (klass
);
5997 *align
= info
->min_align
;
5999 return info
->native_size
;
6003 * mono_type_native_stack_size:
6004 * @t: the type to return the size it uses on the stack
6006 * Returns: the number of bytes required to hold an instance of this
6007 * type on the native stack
6010 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
6014 g_assert (t
!= NULL
);
6020 *align
= TARGET_SIZEOF_VOID_P
;
6021 return TARGET_SIZEOF_VOID_P
;
6025 case MONO_TYPE_BOOLEAN
:
6026 case MONO_TYPE_CHAR
:
6037 case MONO_TYPE_STRING
:
6038 case MONO_TYPE_OBJECT
:
6039 case MONO_TYPE_CLASS
:
6040 case MONO_TYPE_SZARRAY
:
6042 case MONO_TYPE_FNPTR
:
6043 case MONO_TYPE_ARRAY
:
6044 *align
= TARGET_SIZEOF_VOID_P
;
6045 return TARGET_SIZEOF_VOID_P
;
6050 *align
= MONO_ABI_ALIGNOF (double);
6054 *align
= MONO_ABI_ALIGNOF (gint64
);
6056 case MONO_TYPE_GENERICINST
:
6057 if (!mono_type_generic_inst_is_valuetype (t
)) {
6058 *align
= TARGET_SIZEOF_VOID_P
;
6059 return TARGET_SIZEOF_VOID_P
;
6062 case MONO_TYPE_TYPEDBYREF
:
6063 case MONO_TYPE_VALUETYPE
: {
6065 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
6067 if (m_class_is_enumtype (klass
))
6068 return mono_type_native_stack_size (mono_class_enum_basetype_internal (klass
), align
);
6070 size
= mono_class_native_size (klass
, align
);
6071 *align
= *align
+ 3;
6081 g_error ("type 0x%02x unknown", t
->type
);
6087 * mono_marshal_type_size:
6090 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
6091 gboolean as_field
, gboolean unicode
)
6094 MonoMarshalNative native_type
= (MonoMarshalNative
)mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
6097 switch (native_type
) {
6098 case MONO_NATIVE_BOOLEAN
:
6101 case MONO_NATIVE_I1
:
6102 case MONO_NATIVE_U1
:
6105 case MONO_NATIVE_I2
:
6106 case MONO_NATIVE_U2
:
6107 case MONO_NATIVE_VARIANTBOOL
:
6110 case MONO_NATIVE_I4
:
6111 case MONO_NATIVE_U4
:
6112 case MONO_NATIVE_ERROR
:
6115 case MONO_NATIVE_I8
:
6116 case MONO_NATIVE_U8
:
6117 *align
= MONO_ABI_ALIGNOF (gint64
);
6119 case MONO_NATIVE_R4
:
6122 case MONO_NATIVE_R8
:
6123 *align
= MONO_ABI_ALIGNOF (double);
6125 case MONO_NATIVE_INT
:
6126 case MONO_NATIVE_UINT
:
6127 case MONO_NATIVE_LPSTR
:
6128 case MONO_NATIVE_LPWSTR
:
6129 case MONO_NATIVE_LPTSTR
:
6130 case MONO_NATIVE_BSTR
:
6131 case MONO_NATIVE_ANSIBSTR
:
6132 case MONO_NATIVE_TBSTR
:
6133 case MONO_NATIVE_UTF8STR
:
6134 case MONO_NATIVE_LPARRAY
:
6135 case MONO_NATIVE_SAFEARRAY
:
6136 case MONO_NATIVE_IUNKNOWN
:
6137 case MONO_NATIVE_IDISPATCH
:
6138 case MONO_NATIVE_INTERFACE
:
6139 case MONO_NATIVE_ASANY
:
6140 case MONO_NATIVE_FUNC
:
6141 case MONO_NATIVE_LPSTRUCT
:
6142 *align
= MONO_ABI_ALIGNOF (gpointer
);
6143 return TARGET_SIZEOF_VOID_P
;
6144 case MONO_NATIVE_STRUCT
:
6145 klass
= mono_class_from_mono_type_internal (type
);
6146 if (klass
== mono_defaults
.object_class
&&
6147 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
6151 #ifdef ENABLE_NETCORE
6152 else if (strcmp (m_class_get_name_space (klass
), "System") == 0 &&
6153 strcmp (m_class_get_name (klass
), "Decimal") == 0) {
6155 // Special case: Managed Decimal consists of 4 int32 fields, the alignment should be 8 on x64 to follow
6156 // https://github.com/dotnet/coreclr/blob/4450e5ca663b9e66c20e6f9751c941efa3716fde/src/vm/methodtablebuilder.cpp#L9753
6157 *align
= MONO_ABI_ALIGNOF (gpointer
);
6158 return mono_class_native_size (klass
, NULL
);
6161 padded_size
= mono_class_native_size (klass
, align
);
6162 if (padded_size
== 0)
6165 case MONO_NATIVE_BYVALTSTR
: {
6166 int esize
= unicode
? 2: 1;
6169 return mspec
->data
.array_data
.num_elem
* esize
;
6171 case MONO_NATIVE_BYVALARRAY
: {
6172 // FIXME: Have to consider ArraySubType
6174 klass
= mono_class_from_mono_type_internal (type
);
6175 if (m_class_get_element_class (klass
) == mono_defaults
.char_class
) {
6176 esize
= unicode
? 2 : 1;
6179 esize
= mono_class_native_size (m_class_get_element_class (klass
), align
);
6182 return mspec
->data
.array_data
.num_elem
* esize
;
6184 case MONO_NATIVE_CUSTOM
:
6185 *align
= TARGET_SIZEOF_VOID_P
;
6186 return TARGET_SIZEOF_VOID_P
;
6188 case MONO_NATIVE_CURRENCY
:
6189 case MONO_NATIVE_VBBYREFSTR
:
6191 g_error ("native type %02x not implemented", native_type
);
6194 g_assert_not_reached ();
6199 * mono_marshal_asany:
6200 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
6203 mono_marshal_asany_impl (MonoObjectHandle o
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6205 if (MONO_HANDLE_IS_NULL (o
))
6208 MonoType
*t
= m_class_get_byval_arg (mono_handle_class (o
));
6216 case MONO_TYPE_BOOLEAN
:
6219 case MONO_TYPE_CHAR
:
6224 return mono_handle_unbox_unsafe (o
);
6225 case MONO_TYPE_STRING
:
6226 switch (string_encoding
) {
6227 case MONO_NATIVE_LPWSTR
:
6228 return mono_marshal_string_to_utf16_copy_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6229 case MONO_NATIVE_LPSTR
:
6230 case MONO_NATIVE_UTF8STR
:
6231 // Same code path, because in Mono, we treated strings as Utf8
6232 return mono_string_to_utf8str_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6234 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6235 g_assert_not_reached ();
6238 case MONO_TYPE_CLASS
:
6239 case MONO_TYPE_VALUETYPE
: {
6241 MonoClass
*klass
= t
->data
.klass
;
6243 if (mono_class_is_auto_layout (klass
))
6246 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6247 return mono_handle_unbox_unsafe (o
);
6249 gpointer res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), error
);
6250 return_val_if_nok (error
, NULL
);
6252 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6253 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (o
));
6254 MonoBoolean delete_old
= FALSE
;
6255 gpointer pa
[ ] = { MONO_HANDLE_RAW (o
), &res
, &delete_old
};
6257 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
6258 return_val_if_nok (error
, NULL
);
6266 mono_error_set_argument (error
, "", "No PInvoke conversion exists for value passed to Object-typed parameter.");
6271 * mono_marshal_free_asany:
6272 * This is a JIT icall, it sets the pending exception (in wrapper)
6275 mono_marshal_free_asany_impl (MonoObjectHandle o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6280 if (MONO_HANDLE_IS_NULL (o
))
6283 t
= m_class_get_byval_arg (mono_handle_class (o
));
6285 case MONO_TYPE_STRING
:
6286 switch (string_encoding
) {
6287 case MONO_NATIVE_LPWSTR
:
6288 case MONO_NATIVE_LPSTR
:
6289 case MONO_NATIVE_UTF8STR
:
6290 mono_marshal_free (ptr
);
6293 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6294 g_assert_not_reached ();
6297 case MONO_TYPE_CLASS
:
6298 case MONO_TYPE_VALUETYPE
: {
6299 klass
= t
->data
.klass
;
6301 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6304 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
6305 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (o
));
6309 pa
[1] = MONO_HANDLE_RAW (o
);
6311 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
6316 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6317 mono_struct_delete_old (klass
, (char *)ptr
);
6320 mono_marshal_free (ptr
);
6328 #ifndef ENABLE_ILGEN
6330 emit_generic_array_helper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6336 * mono_marshal_get_generic_array_helper:
6338 * Return a wrapper which is used to implement the implicit interfaces on arrays.
6339 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
6342 mono_marshal_get_generic_array_helper (MonoClass
*klass
, const gchar
*name
, MonoMethod
*method
)
6344 MonoMethodSignature
*sig
, *csig
;
6345 MonoMethodBuilder
*mb
;
6349 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
6350 mb
->method
->slot
= -1;
6352 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
6353 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
6355 sig
= mono_method_signature_internal (method
);
6356 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
6357 csig
->generic_param_count
= 0;
6359 get_marshal_cb ()->emit_generic_array_helper (mb
, method
, csig
);
6361 /* We can corlib internal methods */
6362 get_marshal_cb ()->mb_skip_visibility (mb
);
6364 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
6365 info
->d
.generic_array_helper
.method
= method
;
6366 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
6374 * The mono_win32_compat_* functions are implementations of inline
6375 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
6376 * although not exported by kernel32.
6378 * We map the appropiate kernel32 entries to these functions using
6379 * dllmaps declared in the global etc/mono/config.
6383 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
6385 if (!dest
|| !source
)
6388 memcpy (dest
, source
, length
);
6392 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
6394 memset (dest
, fill
, length
);
6398 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
6400 if (!dest
|| !source
)
6403 memmove (dest
, source
, length
);
6407 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
6409 memset (dest
, 0, length
);
6413 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
6418 for (i
= 0; i
< len
; ++i
)
6425 while (byte
&& !(byte
& 1))
6427 g_assert (byte
== 1);
6433 #ifndef ENABLE_ILGEN
6435 emit_thunk_invoke_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6441 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
6443 MonoMethodBuilder
*mb
;
6444 MonoMethodSignature
*sig
, *csig
;
6449 int i
, param_count
, sig_size
;
6453 klass
= method
->klass
;
6454 image
= m_class_get_image (klass
);
6456 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
6458 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
6461 MonoType
*object_type
= mono_get_object_type ();
6463 sig
= mono_method_signature_internal (method
);
6464 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
6466 /* add "this" and exception param */
6467 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
6469 /* dup & extend signature */
6470 csig
= mono_metadata_signature_alloc (image
, param_count
);
6471 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
6472 memcpy (csig
, sig
, sig_size
);
6473 csig
->param_count
= param_count
;
6476 csig
->call_convention
= MONO_CALL_DEFAULT
;
6480 csig
->params
[0] = m_class_get_byval_arg (klass
);
6481 /* move params up by one */
6482 for (i
= 0; i
< sig
->param_count
; i
++)
6483 csig
->params
[i
+ 1] = sig
->params
[i
];
6486 /* setup exception param as byref+[out] */
6487 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
, m_class_get_byval_arg (mono_defaults
.exception_class
));
6488 csig
->params
[param_count
- 1]->byref
= 1;
6489 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
6491 /* convert struct return to object */
6492 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6493 csig
->ret
= object_type
;
6495 get_marshal_cb ()->emit_thunk_invoke_wrapper (mb
, method
, csig
);
6497 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
6504 clear_runtime_invoke_method_cache (GHashTable
*table
, MonoMethod
*method
)
6506 MonoWrapperMethodCacheKey hash_key
= {method
, FALSE
, FALSE
};
6508 * Since we have a small set of possible keys, remove each one separately, thus
6509 * avoiding the traversal of the entire hash table, when using foreach_remove.
6511 g_hash_table_remove (table
, &hash_key
);
6512 hash_key
.need_direct_wrapper
= TRUE
;
6513 g_hash_table_remove (table
, &hash_key
);
6514 hash_key
.virtual_
= TRUE
;
6515 g_hash_table_remove (table
, &hash_key
);
6516 hash_key
.need_direct_wrapper
= FALSE
;
6517 g_hash_table_remove (table
, &hash_key
);
6521 * mono_marshal_free_dynamic_wrappers:
6523 * Free wrappers of the dynamic method METHOD.
6526 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
6531 MonoImage
*image
= get_method_image (method
);
6533 g_assert (method_is_dynamic (method
));
6535 /* This could be called during shutdown */
6536 if (marshal_mutex_initialized
)
6537 mono_marshal_lock ();
6539 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
6540 * they could be shared with other methods ?
6542 if (image
->wrapper_caches
.runtime_invoke_method_cache
)
6543 clear_runtime_invoke_method_cache (image
->wrapper_caches
.runtime_invoke_method_cache
, method
);
6544 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
6545 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
6546 // FIXME: Need to clear the caches in other images as well
6547 if (image
->delegate_bound_static_invoke_cache
)
6548 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature_internal (method
));
6550 if (marshal_mutex_initialized
)
6551 mono_marshal_unlock ();
6555 mono_marshal_get_type_object (MonoClass
*klass
)
6558 MonoType
*type
= m_class_get_byval_arg (klass
);
6559 MonoObject
*result
= (MonoObject
*)mono_type_get_object_checked (mono_domain_get (), type
, error
);
6560 mono_error_set_pending_exception (error
);
6565 mono_marshal_emit_native_wrapper (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
, gboolean skip_gc_trans
)
6567 get_marshal_cb ()->emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, aot
, check_exceptions
, func_param
, skip_gc_trans
);
6570 #ifndef ENABLE_ILGEN
6572 emit_native_wrapper_noilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
, gboolean skip_gc_trans
)
6577 static MonoMarshalCallbacks marshal_cb
;
6578 static gboolean cb_inited
= FALSE
;
6581 mono_install_marshal_callbacks (MonoMarshalCallbacks
*cb
)
6583 g_assert (!cb_inited
);
6584 g_assert (cb
->version
== MONO_MARSHAL_CALLBACKS_VERSION
);
6585 memcpy (&marshal_cb
, cb
, sizeof (MonoMarshalCallbacks
));
6589 #ifndef ENABLE_ILGEN
6591 install_noilgen (void)
6593 MonoMarshalCallbacks cb
;
6594 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6595 cb
.emit_marshal_array
= emit_marshal_array_noilgen
;
6596 cb
.emit_marshal_boolean
= emit_marshal_boolean_noilgen
;
6597 cb
.emit_marshal_ptr
= emit_marshal_ptr_noilgen
;
6598 cb
.emit_marshal_char
= emit_marshal_char_noilgen
;
6599 cb
.emit_marshal_scalar
= emit_marshal_scalar_noilgen
;
6600 cb
.emit_marshal_custom
= emit_marshal_custom_noilgen
;
6601 cb
.emit_marshal_asany
= emit_marshal_asany_noilgen
;
6602 cb
.emit_marshal_vtype
= emit_marshal_vtype_noilgen
;
6603 cb
.emit_marshal_string
= emit_marshal_string_noilgen
;
6604 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_noilgen
;
6605 cb
.emit_marshal_handleref
= emit_marshal_handleref_noilgen
;
6606 cb
.emit_marshal_object
= emit_marshal_object_noilgen
;
6607 cb
.emit_marshal_variant
= emit_marshal_variant_noilgen
;
6608 cb
.emit_castclass
= emit_castclass_noilgen
;
6609 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_noilgen
;
6610 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_noilgen
;
6611 cb
.emit_isinst
= emit_isinst_noilgen
;
6612 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_noilgen
;
6613 cb
.emit_stelemref
= emit_stelemref_noilgen
;
6614 cb
.emit_array_address
= emit_array_address_noilgen
;
6615 cb
.emit_native_wrapper
= emit_native_wrapper_noilgen
;
6616 cb
.emit_managed_wrapper
= emit_managed_wrapper_noilgen
;
6617 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_noilgen
;
6618 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_noilgen
;
6619 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_noilgen
;
6620 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_noilgen
;
6621 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_noilgen
;
6622 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_noilgen
;
6623 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_noilgen
;
6624 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_noilgen
;
6625 cb
.emit_generic_array_helper
= emit_generic_array_helper_noilgen
;
6626 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_noilgen
;
6627 cb
.emit_create_string_hack
= emit_create_string_hack_noilgen
;
6628 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_noilgen
;
6629 cb
.emit_icall_wrapper
= emit_icall_wrapper_noilgen
;
6630 cb
.emit_return
= emit_return_noilgen
;
6631 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_noilgen
;
6632 cb
.mb_skip_visibility
= mb_skip_visibility_noilgen
;
6633 cb
.mb_set_dynamic
= mb_set_dynamic_noilgen
;
6634 cb
.mb_emit_exception
= mb_emit_exception_noilgen
;
6635 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_noilgen
;
6636 cb
.mb_emit_byte
= mb_emit_byte_noilgen
;
6637 mono_install_marshal_callbacks (&cb
);
6641 static MonoMarshalCallbacks
*
6642 get_marshal_cb (void)
6644 if (G_UNLIKELY (!cb_inited
)) {
6646 mono_marshal_ilgen_init ();