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");
115 get_method_image (MonoMethod
*method
)
117 return m_class_get_image (method
->klass
);
120 // func is an identifier, that names a function, and is also in jit-icall-reg.h,
121 // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
123 // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
124 // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
125 // must be extern "C".
126 #define register_icall(func, sig, no_wrapper) \
127 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (no_wrapper), #func))
130 mono_signature_no_pinvoke (MonoMethod
*method
)
132 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
134 sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
135 sig
->pinvoke
= FALSE
;
142 mono_marshal_init_tls (void)
144 mono_native_tls_alloc (&last_error_tls_id
, NULL
);
145 mono_native_tls_alloc (&load_type_info_tls_id
, NULL
);
149 mono_object_isinst_icall_impl (MonoObjectHandle obj
, MonoClass
* klass
, MonoError
*error
)
154 /* This is called from stelemref so it is expected to succeed */
156 if (mono_class_is_interface (klass
)) {
157 MonoVTable
*vt
= mono_handle_vtable (obj
);
159 if (!m_class_is_inited (klass
))
160 mono_class_init_internal (klass
);
162 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, m_class_get_interface_id (klass
)))
166 return mono_object_handle_isinst (obj
, klass
, error
);
170 ves_icall_mono_string_from_utf16_impl (const gunichar2
*data
, MonoError
*error
)
172 MonoString
*s
= mono_string_from_utf16_checked (data
, error
);
173 return_val_if_nok (error
, NULL_HANDLE_STRING
);
174 return MONO_HANDLE_NEW (MonoString
, s
);
178 ves_icall_mono_string_to_utf8_impl (MonoStringHandle str
, MonoError
*error
)
180 return mono_string_handle_to_utf8 (str
, error
);
184 ves_icall_string_new_wrapper_impl (const char *text
, MonoError
*error
)
186 return text
? mono_string_new_handle (mono_domain_get (), text
, error
) : NULL_HANDLE_STRING
;
190 mono_marshal_init (void)
192 static gboolean module_initialized
= FALSE
;
194 if (!module_initialized
) {
195 module_initialized
= TRUE
;
196 mono_coop_mutex_init_recursive (&marshal_mutex
);
197 marshal_mutex_initialized
= TRUE
;
199 register_icall (mono_marshal_string_to_utf16
, mono_icall_sig_ptr_obj
, FALSE
);
200 register_icall (mono_marshal_string_to_utf16_copy
, mono_icall_sig_ptr_obj
, FALSE
);
201 register_icall (mono_string_to_utf16_internal
, mono_icall_sig_ptr_obj
, FALSE
);
202 register_icall (ves_icall_mono_string_from_utf16
, mono_icall_sig_obj_ptr
, FALSE
);
203 register_icall (mono_string_from_byvalstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
204 register_icall (mono_string_from_byvalwstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
205 register_icall (mono_string_new_wrapper_internal
, mono_icall_sig_obj_ptr
, FALSE
);
206 register_icall (ves_icall_string_new_wrapper
, mono_icall_sig_obj_ptr
, FALSE
);
207 register_icall (mono_string_new_len_wrapper
, mono_icall_sig_obj_ptr_int
, FALSE
);
208 register_icall (ves_icall_mono_string_to_utf8
, mono_icall_sig_ptr_obj
, FALSE
);
209 register_icall (mono_string_to_utf8str
, mono_icall_sig_ptr_obj
, FALSE
);
210 register_icall (mono_string_to_ansibstr
, mono_icall_sig_ptr_object
, FALSE
);
211 register_icall (mono_string_builder_to_utf8
, mono_icall_sig_ptr_object
, FALSE
);
212 register_icall (mono_string_builder_to_utf16
, mono_icall_sig_ptr_object
, FALSE
);
213 register_icall (mono_array_to_savearray
, mono_icall_sig_ptr_object
, FALSE
);
214 register_icall (mono_array_to_lparray
, mono_icall_sig_ptr_object
, FALSE
);
215 register_icall (mono_free_lparray
, mono_icall_sig_void_object_ptr
, FALSE
);
216 register_icall (mono_byvalarray_to_byte_array
, mono_icall_sig_void_object_ptr_int32
, FALSE
);
217 register_icall (mono_array_to_byte_byvalarray
, mono_icall_sig_void_ptr_object_int32
, FALSE
);
218 register_icall (mono_delegate_to_ftnptr
, mono_icall_sig_ptr_object
, FALSE
);
219 register_icall (mono_ftnptr_to_delegate
, mono_icall_sig_object_ptr_ptr
, FALSE
);
220 register_icall (mono_marshal_asany
, mono_icall_sig_ptr_object_int32_int32
, FALSE
);
221 register_icall (mono_marshal_free_asany
, mono_icall_sig_void_object_ptr_int32_int32
, FALSE
);
222 register_icall (ves_icall_marshal_alloc
, mono_icall_sig_ptr_ptr
, FALSE
);
223 register_icall (mono_marshal_free
, mono_icall_sig_void_ptr
, FALSE
);
224 register_icall (mono_marshal_set_last_error
, mono_icall_sig_void
, TRUE
);
225 register_icall (mono_marshal_set_last_error_windows
, mono_icall_sig_void_int32
, TRUE
);
226 register_icall (mono_marshal_clear_last_error
, mono_icall_sig_void
, TRUE
);
227 register_icall (mono_string_utf8_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
228 register_icall (mono_string_utf8_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
229 register_icall (mono_string_utf16_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
230 register_icall (mono_string_utf16_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
231 register_icall (mono_marshal_free_array
, mono_icall_sig_void_ptr_int32
, FALSE
);
232 register_icall (mono_string_to_byvalstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
233 register_icall (mono_string_to_byvalwstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
234 // Because #define g_free monoeg_g_free.
235 register_icall (monoeg_g_free
, mono_icall_sig_void_ptr
, FALSE
);
236 register_icall (mono_object_isinst_icall
, mono_icall_sig_object_object_ptr
, TRUE
);
237 register_icall (mono_struct_delete_old
, mono_icall_sig_void_ptr_ptr
, FALSE
);
238 register_icall (mono_delegate_begin_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
239 register_icall (mono_delegate_end_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
240 register_icall (mono_gc_wbarrier_generic_nostore_internal
, mono_icall_sig_void_ptr
, FALSE
);
241 register_icall (mono_gchandle_get_target_internal
, mono_icall_sig_object_int32
, TRUE
);
242 register_icall (mono_marshal_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
243 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
244 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
245 register_icall (mono_threads_enter_gc_unsafe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
246 register_icall (mono_threads_exit_gc_unsafe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
247 register_icall (mono_threads_attach_coop
, mono_icall_sig_ptr_ptr_ptr
, TRUE
);
248 register_icall (mono_threads_detach_coop
, mono_icall_sig_void_ptr_ptr
, TRUE
);
249 register_icall (mono_marshal_get_type_object
, mono_icall_sig_object_ptr
, TRUE
);
251 mono_cominterop_init ();
252 mono_remoting_init ();
254 mono_counters_register ("MonoClass::class_marshal_info_count count",
255 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_marshal_info_count
);
260 mono_marshal_cleanup (void)
262 mono_cominterop_cleanup ();
264 mono_native_tls_free (load_type_info_tls_id
);
265 mono_native_tls_free (last_error_tls_id
);
266 mono_coop_mutex_destroy (&marshal_mutex
);
267 marshal_mutex_initialized
= FALSE
;
271 mono_marshal_lock_internal (void)
273 mono_marshal_lock ();
277 mono_marshal_unlock_internal (void)
279 mono_marshal_unlock ();
282 // This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error.
284 mono_delegate_to_ftnptr_impl (MonoDelegateHandle delegate
, MonoError
*error
)
286 gpointer result
= NULL
;
287 MonoMethod
*method
, *wrapper
;
289 uint32_t target_handle
= 0;
291 if (MONO_HANDLE_IS_NULL (delegate
))
294 if (MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
)) {
295 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
299 klass
= mono_handle_class (delegate
);
300 g_assert (m_class_is_delegate (klass
));
302 method
= MONO_HANDLE_GETVAL (delegate
, method
);
303 if (MONO_HANDLE_GETVAL (delegate
, method_is_virtual
)) {
304 MonoObjectHandle delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
305 method
= mono_object_handle_get_virtual_method (delegate_target
, method
, error
);
306 goto_if_nok (error
, leave
);
309 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
312 ftnptr
= mono_lookup_pinvoke_call_internal (method
, error
);
314 g_assert (!is_ok (error
));
321 MonoObjectHandle delegate_target
;
322 delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
323 if (!MONO_HANDLE_IS_NULL (delegate_target
)) {
324 /* Produce a location which can be embedded in JITted code */
325 target_handle
= mono_gchandle_new_weakref_from_handle (delegate_target
);
328 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
, error
);
329 goto_if_nok (error
, leave
);
331 MONO_HANDLE_SETVAL (delegate
, delegate_trampoline
, gpointer
, mono_compile_method_checked (wrapper
, error
));
332 goto_if_nok (error
, leave
);
334 // Add the delegate to the delegate hash table
335 delegate_hash_table_add (delegate
);
337 /* when the object is collected, collect the dynamic method, too */
338 mono_object_register_finalizer ((MonoObject
*) MONO_HANDLE_RAW (delegate
));
340 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
343 if (!is_ok (error
) && target_handle
!= 0)
344 mono_gchandle_free_internal (target_handle
);
349 * this hash table maps from a delegate trampoline object to a weak reference
350 * of the delegate. As an optimizations with a non-moving GC we store the
351 * object pointer itself, otherwise we use a GC handle.
353 static GHashTable
*delegate_hash_table
;
356 delegate_hash_table_new (void) {
357 return g_hash_table_new (NULL
, NULL
);
361 delegate_hash_table_remove (MonoDelegate
*d
)
363 guint32 gchandle
= 0;
368 mono_marshal_lock ();
369 if (delegate_hash_table
== NULL
)
370 delegate_hash_table
= delegate_hash_table_new ();
371 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
372 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
373 mono_marshal_unlock ();
375 mono_gchandle_free_internal (gchandle
);
379 delegate_hash_table_add (MonoDelegateHandle d
)
381 mono_marshal_lock ();
382 if (delegate_hash_table
== NULL
)
383 delegate_hash_table
= delegate_hash_table_new ();
384 gpointer delegate_trampoline
= MONO_HANDLE_GETVAL (d
, delegate_trampoline
);
385 gboolean has_target
= MONO_HANDLE_GETVAL (d
, target
) != NULL
;
387 // If the delegate has an instance method there is 1 to 1 mapping between
388 // the delegate object and the delegate_trampoline
389 guint32 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
));
391 // Somehow, some other thread beat us to it ?
392 g_assert (mono_gchandle_target_equal (gchandle
, MONO_HANDLE_CAST (MonoObject
, d
)));
394 gchandle
= mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, d
));
395 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
398 if (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
) == NULL
) {
399 guint32 gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, d
), FALSE
);
400 // This delegate will always be associated with its delegate_trampoline in the table.
401 // We don't free this delegate object because it is too expensive to keep track of these
402 // pairs and avoid races with the delegate finalization.
403 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
406 mono_marshal_unlock ();
410 * mono_marshal_use_aot_wrappers:
412 * Instructs this module to use AOT compatible wrappers.
415 mono_marshal_use_aot_wrappers (gboolean use
)
417 use_aot_wrappers
= use
;
421 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
424 MonoCustomAttrInfo
*cinfo
;
425 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
427 /* The attribute is only available in Net 2.0 */
428 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
430 * The pinvoke attributes are stored in a real custom attribute so we have to
433 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
434 if (!is_ok (error
)) {
435 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
436 mono_error_cleanup (error
);
438 if (cinfo
&& !mono_runtime_get_no_exec ()) {
439 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), error
);
441 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
443 if (!is_ok (error
)) {
444 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
445 mono_error_cleanup (error
);
449 mono_custom_attrs_free (cinfo
);
454 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
456 mono_ftnptr_to_delegate_impl (MonoClass
*klass
, gpointer ftn
, MonoError
*error
)
459 MonoDelegateHandle d
= MONO_HANDLE_NEW (MonoDelegate
, NULL
);
464 mono_marshal_lock ();
465 if (delegate_hash_table
== NULL
)
466 delegate_hash_table
= delegate_hash_table_new ();
467 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
468 mono_marshal_unlock ();
470 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_CAST (MonoDelegate
, mono_gchandle_get_target_handle (gchandle
)));
472 if (MONO_HANDLE_IS_NULL (d
)) {
473 /* This is a native function, so construct a delegate for it */
474 MonoMethodSignature
*sig
;
476 MonoMarshalSpec
**mspecs
;
477 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
478 MonoMethodPInvoke piinfo
;
479 MonoObjectHandle this_obj
;
482 if (use_aot_wrappers
) {
483 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
484 this_obj
= MONO_HANDLE_NEW (MonoObject
, mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, error
));
485 goto_if_nok (error
, leave
);
487 memset (&piinfo
, 0, sizeof (piinfo
));
488 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
490 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
491 mono_method_get_marshal_info (invoke
, mspecs
);
492 /* Freed below so don't alloc from mempool */
493 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
496 wrapper
= mono_marshal_get_native_func_wrapper (m_class_get_image (klass
), sig
, &piinfo
, mspecs
, ftn
);
497 this_obj
= MONO_HANDLE_NEW (MonoObject
, NULL
);
499 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
501 mono_metadata_free_marshal_spec (mspecs
[i
]);
506 MONO_HANDLE_ASSIGN (d
, mono_object_new_handle (mono_domain_get (), klass
, error
));
507 goto_if_nok (error
, leave
);
508 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, error
);
509 goto_if_nok (error
, leave
);
511 mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject
, d
), this_obj
, compiled_ptr
, wrapper
, error
);
512 goto_if_nok (error
, leave
);
515 g_assert (!MONO_HANDLE_IS_NULL (d
));
516 if (MONO_HANDLE_DOMAIN (d
) != mono_domain_get ())
517 mono_error_set_not_supported (error
, "Delegates cannot be marshalled from native code into a domain other than their home domain");
523 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
528 delegate_hash_table_remove (delegate
);
530 ptr
= (gpointer
)mono_atomic_xchg_ptr (&delegate
->delegate_trampoline
, NULL
);
532 if (!delegate
->target
) {
533 /* The wrapper method is shared between delegates -> no need to free it */
542 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
543 /* FIXME we leak wrapper with the interpreter */
547 method
= mono_jit_info_get_method (ji
);
548 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
550 /*the target gchandle is the first entry after size and the wrapper itself.*/
551 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
554 mono_gchandle_free_internal (gchandle
);
556 mono_runtime_free_method (mono_object_domain (delegate
), method
);
560 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
562 mono_string_from_byvalstr_impl (const char *data
, int max_len
, MonoError
*error
)
564 // FIXME This optimization ok to miss before wrapper? Or null is rare?
566 return NULL_HANDLE_STRING
;
569 while (len
< max_len
- 1 && data
[len
])
573 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), data
, len
, error
);
574 return_val_if_nok (error
, NULL_HANDLE_STRING
);
575 return MONO_HANDLE_NEW (MonoString
, s
);
578 /* This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error */
580 mono_string_from_byvalwstr_impl (const gunichar2
*data
, int max_len
, MonoError
*error
)
582 // FIXME This optimization ok to miss before wrapper? Or null is rare?
584 return NULL_HANDLE_STRING
;
586 // FIXME Check max_len while scanning data? mono_string_from_byvalstr does.
587 const int len
= g_utf16_len (data
);
589 return mono_string_new_utf16_handle (mono_domain_get (), data
, MIN (len
, max_len
), error
);
593 mono_array_to_savearray_impl (MonoArrayHandle array
, MonoError
*error
)
595 if (!MONO_HANDLE_BOOL (array
))
598 g_assert_not_reached ();
603 mono_array_to_lparray_impl (MonoArrayHandle array_handle
, MonoError
*error
)
605 if (!MONO_HANDLE_BOOL (array_handle
))
608 MonoArray
*array
= MONO_HANDLE_RAW (array_handle
); // FIXMEcoop
611 gpointer
*nativeArray
= NULL
;
612 int nativeArraySize
= 0;
614 MonoClass
*klass
= array
->obj
.vtable
->klass
;
615 MonoClass
*klass_element_class
= m_class_get_element_class (klass
);
617 switch (m_class_get_byval_arg (klass_element_class
)->type
) {
619 g_assert_not_reached ();
621 case MONO_TYPE_CLASS
:
622 nativeArraySize
= array
->max_length
;
623 nativeArray
= g_new (gpointer
, nativeArraySize
);
624 for (i
= 0; i
< nativeArraySize
; ++i
) {
625 nativeArray
[i
] = mono_cominterop_get_com_interface (((MonoObject
**)array
->vector
)[i
], klass_element_class
, error
);
626 if (!is_ok (error
)) {
627 // FIXME? Returns uninitialized.
633 case MONO_TYPE_BOOLEAN
:
646 case MONO_TYPE_VALUETYPE
:
650 case MONO_TYPE_GENERICINST
:
651 case MONO_TYPE_OBJECT
:
652 case MONO_TYPE_ARRAY
:
653 case MONO_TYPE_SZARRAY
:
654 case MONO_TYPE_STRING
:
656 g_warning ("type 0x%x not handled", m_class_get_byval_arg (klass_element_class
)->type
);
657 g_assert_not_reached ();
660 return array
->vector
;
664 mono_free_lparray_impl (MonoArrayHandle array
, gpointer
* nativeArray
, MonoError
*error
)
667 if (!nativeArray
|| MONO_HANDLE_IS_NULL (array
))
670 MonoClass
* const klass
= mono_handle_class (array
);
672 if (m_class_get_byval_arg (m_class_get_element_class (klass
))->type
== MONO_TYPE_CLASS
)
673 g_free (nativeArray
);
677 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
679 mono_byvalarray_to_byte_array_impl (MonoArrayHandle arr
, const char *native_arr
, guint32 elnum
, MonoError
*error
)
681 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
683 GError
*gerror
= NULL
;
685 gunichar2
*ut
= g_utf8_to_utf16 (native_arr
, elnum
, NULL
, &items_written
, &gerror
);
688 g_error_free (gerror
);
691 gchandle_t gchandle
= 0;
692 memcpy (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), ut
, items_written
* sizeof (gunichar2
));
693 mono_gchandle_free_internal (gchandle
);
697 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
699 mono_array_to_byte_byvalarray_impl (gpointer native_arr
, MonoArrayHandle arr
, guint32 elnum
, MonoError
*error
)
701 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
703 GError
*gerror
= NULL
;
705 gchandle_t gchandle
= 0;
706 char *as
= g_utf16_to_utf8 (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), mono_array_handle_length (arr
), NULL
, NULL
, &gerror
);
707 mono_gchandle_free_internal (gchandle
);
709 mono_error_set_argument (error
, "string", gerror
->message
);
710 g_error_free (gerror
);
713 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
717 static MonoStringBuilderHandle
718 mono_string_builder_new (int starting_string_length
, MonoError
*error
)
720 static MonoClass
*string_builder_class
;
721 static MonoMethod
*sb_ctor
;
724 int initial_len
= starting_string_length
;
730 MonoMethodDesc
*desc
;
733 string_builder_class
= mono_class_try_get_stringbuilder_class ();
734 g_assert (string_builder_class
); //TODO don't swallow the error
735 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
736 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
738 mono_method_desc_free (desc
);
739 mono_memory_barrier ();
743 // We make a new array in the _to_builder function, so this
744 // array will always be garbage collected.
745 args
[0] = &initial_len
;
747 MonoStringBuilderHandle sb
= MONO_HANDLE_CAST (MonoStringBuilder
, mono_object_new_handle (mono_domain_get (), string_builder_class
, error
));
748 mono_error_assert_ok (error
);
750 mono_runtime_try_invoke_handle (sb_ctor
, MONO_HANDLE_CAST (MonoObject
, sb
), args
, error
);
751 mono_error_assert_ok (error
);
753 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW_GET (MonoArray
, sb
, chunkChars
);
754 g_assert (MONO_HANDLE_GETVAL (chunkChars
, max_length
) >= initial_len
);
760 mono_string_utf16_to_builder_copy (MonoStringBuilderHandle sb
, const gunichar2
*text
, size_t string_len
, MonoError
*error
)
762 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
763 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
765 guint capacity
= mono_string_builder_capacity (sb
);
767 g_assert (capacity
>= string_len
);
769 MONO_ENTER_NO_SAFEPOINTS
;
772 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
773 const int maxLength
= MONO_HANDLE_GETVAL (chunkChars
, max_length
);
774 g_assert (maxLength
>= 0);
775 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
776 g_assert (chunkOffset
>= 0);
777 if (maxLength
> 0 && chunkOffset
< string_len
) {
778 // Check that we will not overrun our boundaries.
779 int charsToCopy
= MIN (string_len
- chunkOffset
, maxLength
);
780 memcpy (MONO_HANDLE_RAW (chunkChars
)->vector
, text
+ chunkOffset
, charsToCopy
* sizeof (gunichar2
));
781 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, charsToCopy
);
783 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, 0);
785 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
786 } while (MONO_HANDLE_BOOL (chunk
));
788 MONO_EXIT_NO_SAFEPOINTS
;
791 MonoStringBuilderHandle
792 mono_string_utf16_to_builder2_impl (const gunichar2
*text
, MonoError
*error
)
795 return NULL_HANDLE_STRING_BUILDER
;
797 const gsize len
= g_utf16_len (text
);
799 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
800 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
802 mono_string_utf16len_to_builder (sb
, text
, len
, error
);
803 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
809 mono_string_utf8len_to_builder (MonoStringBuilderHandle sb
, const char *text
, gsize len
, MonoError
*error
)
811 if (!MONO_HANDLE_BOOL (sb
) || !text
)
814 GError
*gerror
= NULL
;
816 gunichar2
* ut
= g_utf8_to_utf16 (text
, len
, NULL
, &copied
, &gerror
);
817 int capacity
= mono_string_builder_capacity (sb
);
819 if (copied
> capacity
)
823 MONO_HANDLE_SETRAW (sb
, chunkPrevious
, NULL
);
824 mono_string_utf16_to_builder_copy (sb
, ut
, copied
, error
);
827 g_error_free (gerror
);
834 mono_string_utf8_to_builder_impl (MonoStringBuilderHandle sb
, const char *text
, MonoError
*error
)
836 mono_string_utf8len_to_builder (sb
, text
, text
? strlen (text
) : 0, error
);
839 MonoStringBuilderHandle
840 mono_string_utf8_to_builder2_impl (const char *text
, MonoError
*error
)
843 return NULL_HANDLE_STRING_BUILDER
;
845 const gsize len
= strlen (text
);
847 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
848 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
850 mono_string_utf8len_to_builder (sb
, text
, len
, error
);
851 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
857 mono_string_utf16len_to_builder (MonoStringBuilderHandle sb
, const gunichar2
*text
, gsize len
, MonoError
*error
)
859 if (!MONO_HANDLE_BOOL (sb
) || !text
)
861 len
= MIN (len
, mono_string_builder_capacity (sb
));
862 mono_string_utf16_to_builder_copy (sb
, text
, len
, error
);
866 mono_string_utf16_to_builder_impl (MonoStringBuilderHandle sb
, const gunichar2
*text
, MonoError
*error
)
868 mono_string_utf16len_to_builder (sb
, text
, text
? g_utf16_len (text
) : 0, error
);
872 * mono_string_builder_to_utf8:
873 * \param sb the string builder
875 * Converts to utf8 the contents of the \c MonoStringBuilder .
877 * \returns a utf8 string with the contents of the \c StringBuilder .
879 * The return value must be released with mono_marshal_free.
881 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
884 mono_string_builder_to_utf8_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
887 GError
*gerror
= NULL
;
889 gunichar2
*str_utf16
= NULL
;
893 if (!MONO_HANDLE_BOOL (sb
))
896 str_utf16
= mono_string_builder_to_utf16_impl (sb
, error
);
897 goto_if_nok (error
, exit
);
899 tmp
= g_utf16_to_utf8 (str_utf16
, mono_string_builder_string_length (sb
), NULL
, &byte_count
, &gerror
);
901 mono_error_set_execution_engine (error
, "Failed to convert StringBuilder from utf16 to utf8");
905 len
= mono_string_builder_capacity (sb
) + 1;
906 res
= (char *)mono_marshal_alloc (MAX (byte_count
+ 1, len
), error
);
907 if (!is_ok (error
)) {
912 memcpy (res
, tmp
, byte_count
);
913 res
[byte_count
] = 0;
915 g_error_free (gerror
);
916 mono_marshal_free (str_utf16
);
922 * mono_string_builder_to_utf16:
923 * \param sb the string builder
925 * Converts to utf16 the contents of the \c MonoStringBuilder .
927 * Returns: a utf16 string with the contents of the \c StringBuilder .
929 * The return value must be released with mono_marshal_free.
931 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
934 mono_string_builder_to_utf16_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
936 if (!MONO_HANDLE_BOOL (sb
))
939 g_assert (MONO_HANDLE_GET_BOOL (sb
, chunkChars
));
941 guint capacity
= mono_string_builder_capacity (sb
);
942 guint length
= mono_string_builder_string_length (sb
);
944 // Follow CoreCLR and double NULL terminate the buffer so we have more protection
945 // against native code putting garbage in there.
947 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((capacity
+ 2) * sizeof (gunichar2
), error
);
948 return_val_if_nok (error
, NULL
);
951 str
[capacity
+ 1] = 0;
953 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
954 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
956 MONO_ENTER_NO_SAFEPOINTS
;
959 const int chunkLength
= MONO_HANDLE_GETVAL (chunk
, chunkLength
);
960 g_assert (chunkLength
>= 0);
961 if (chunkLength
> 0) {
962 // Check that we will not overrun our boundaries.
963 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
964 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
965 g_assert (chunkOffset
>= 0);
966 g_assertf ((chunkOffset
+ chunkLength
) >= chunkLength
, "integer overflow");
967 g_assertf ((chunkOffset
+ chunkLength
) <= capacity
, "A chunk in the StringBuilder had a length longer than expected from the offset.");
968 memcpy (str
+ chunkOffset
, MONO_HANDLE_RAW (chunkChars
)->vector
, chunkLength
* sizeof (gunichar2
));
970 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
971 } while (MONO_HANDLE_BOOL (chunk
));
975 MONO_EXIT_NO_SAFEPOINTS
;
982 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
984 mono_string_to_utf8str_impl (MonoStringHandle s
, MonoError
*error
)
986 return mono_string_handle_to_utf8 (s
, error
);
992 mono_string_to_ansibstr_impl (MonoStringHandle string_obj
, MonoError
*error
)
994 g_error ("UnmanagedMarshal.BStr is not implemented.");
999 * mono_string_to_byvalstr:
1000 * \param dst Where to store the null-terminated utf8 decoded string.
1001 * \param src the \c MonoString to copy.
1002 * \param size the maximum number of bytes to copy.
1004 * Copies the \c MonoString pointed to by \p src as a utf8 string
1005 * into \p dst, it copies at most \p size bytes into the destination.
1008 mono_string_to_byvalstr_impl (char *dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1010 g_assert (dst
!= NULL
);
1011 g_assert (size
> 0);
1013 memset (dst
, 0, size
);
1014 if (!MONO_HANDLE_BOOL (src
))
1017 // FIXME convert right into dst instead of the double copy.
1019 char *s
= mono_string_handle_to_utf8 (src
, error
);
1020 return_if_nok (error
);
1021 int len
= MIN (size
, strlen (s
));
1022 len
-= (len
>= size
);
1023 memcpy (dst
, s
, len
);
1029 * mono_string_to_byvalwstr:
1030 * \param dst Where to store the null-terminated utf16 decoded string.
1031 * \param src the \c MonoString to copy.
1032 * \param size the maximum number of wide characters to copy (each consumes 2 bytes)
1034 * Copies the \c MonoString pointed to by \p src as a utf16 string into
1035 * \p dst, it copies at most \p size gunichar2s into the destination (including
1036 * a terminating 16-bit zero terminator).
1039 mono_string_to_byvalwstr_impl (gunichar2
*dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1042 g_assert (size
> 0);
1044 if (!MONO_HANDLE_BOOL (src
)) {
1045 memset (dst
, 0, size
* sizeof (gunichar2
));
1049 gchandle_t gchandle
= 0;
1050 int len
= MIN (size
, mono_string_handle_length (src
));
1051 memcpy (dst
, mono_string_handle_pin_chars (src
, &gchandle
), len
* sizeof (gunichar2
));
1052 mono_gchandle_free_internal (gchandle
);
1053 len
-= (size
<= mono_string_handle_length (src
));
1057 /* this is an icall, it sets the pending exception and returns NULL on error */
1059 mono_string_new_len_wrapper_impl (const char *text
, guint length
, MonoError
*error
)
1061 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), text
, length
, error
);
1062 return_val_if_nok (error
, NULL_HANDLE_STRING
);
1063 return MONO_HANDLE_NEW (MonoString
, s
);
1067 mono_type_to_ldind (MonoType
*type
)
1073 switch (type
->type
) {
1075 return CEE_LDIND_I1
;
1077 case MONO_TYPE_BOOLEAN
:
1078 return CEE_LDIND_U1
;
1080 return CEE_LDIND_I2
;
1082 case MONO_TYPE_CHAR
:
1083 return CEE_LDIND_U2
;
1085 return CEE_LDIND_I4
;
1087 return CEE_LDIND_U4
;
1091 case MONO_TYPE_FNPTR
:
1093 case MONO_TYPE_CLASS
:
1094 case MONO_TYPE_STRING
:
1095 case MONO_TYPE_OBJECT
:
1096 case MONO_TYPE_SZARRAY
:
1097 case MONO_TYPE_ARRAY
:
1098 return CEE_LDIND_REF
;
1101 return CEE_LDIND_I8
;
1103 return CEE_LDIND_R4
;
1105 return CEE_LDIND_R8
;
1106 case MONO_TYPE_VALUETYPE
:
1107 if (m_class_is_enumtype (type
->data
.klass
)) {
1108 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1112 case MONO_TYPE_TYPEDBYREF
:
1114 case MONO_TYPE_GENERICINST
:
1115 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1118 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1124 mono_type_to_stind (MonoType
*type
)
1127 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1130 switch (type
->type
) {
1133 case MONO_TYPE_BOOLEAN
:
1134 return CEE_STIND_I1
;
1137 case MONO_TYPE_CHAR
:
1138 return CEE_STIND_I2
;
1141 return CEE_STIND_I4
;
1145 case MONO_TYPE_FNPTR
:
1147 case MONO_TYPE_CLASS
:
1148 case MONO_TYPE_STRING
:
1149 case MONO_TYPE_OBJECT
:
1150 case MONO_TYPE_SZARRAY
:
1151 case MONO_TYPE_ARRAY
:
1152 return CEE_STIND_REF
;
1155 return CEE_STIND_I8
;
1157 return CEE_STIND_R4
;
1159 return CEE_STIND_R8
;
1160 case MONO_TYPE_VALUETYPE
:
1161 if (m_class_is_enumtype (type
->data
.klass
)) {
1162 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1166 case MONO_TYPE_TYPEDBYREF
:
1168 case MONO_TYPE_GENERICINST
:
1169 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1172 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1177 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1179 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1182 MonoMulticastDelegate
*mcast_delegate
;
1186 g_assert (delegate
);
1187 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
1188 if (mcast_delegate
->delegates
!= NULL
) {
1189 mono_error_set_argument (error
, NULL
, "The delegate must have only one target");
1190 mono_error_set_pending_exception (error
);
1194 #ifndef DISABLE_REMOTING
1195 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1196 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1197 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
1198 /* If the target is a proxy, make a direct call. Is proxy's work
1199 // to make the call asynchronous.
1201 MonoMethodMessage
*msg
;
1202 MonoDelegate
*async_callback
;
1204 MonoAsyncResult
*ares
;
1206 MonoArray
*out_args
;
1207 method
= delegate
->method
;
1209 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, error
);
1210 if (mono_error_set_pending_exception (error
))
1212 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, error
);
1213 if (mono_error_set_pending_exception (error
))
1215 MONO_OBJECT_SETREF_INTERNAL (ares
, async_delegate
, (MonoObject
*)delegate
);
1216 MONO_OBJECT_SETREF_INTERNAL (ares
, async_callback
, (MonoObject
*)async_callback
);
1217 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1218 msg
->call_type
= CallType_BeginInvoke
;
1221 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1222 if (!is_ok (error
)) {
1223 mono_error_set_pending_exception (error
);
1227 mono_set_pending_exception ((MonoException
*) exc
);
1233 klass
= delegate
->object
.vtable
->klass
;
1235 ERROR_DECL (begin_invoke_error
);
1236 method
= mono_get_delegate_begin_invoke_checked (klass
, begin_invoke_error
);
1237 mono_error_cleanup (begin_invoke_error
); /* if we can't call BeginInvoke, fall back on Invoke */
1239 method
= mono_get_delegate_invoke_internal (klass
);
1242 MonoAsyncResult
*result
= mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, error
);
1243 mono_error_set_pending_exception (error
);
1248 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
1250 GString
*res
= g_string_new ("");
1253 g_string_append (res
, prefix
);
1254 g_string_append_c (res
, '_');
1257 mono_type_get_desc (res
, sig
->ret
, FALSE
);
1260 g_string_append (res
, "__this__");
1262 for (int i
= 0; i
< sig
->param_count
; ++i
) {
1263 g_string_append_c (res
, '_');
1264 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
1266 char *result
= res
->str
;
1267 g_string_free (res
, FALSE
);
1272 * mono_marshal_get_string_encoding:
1274 * Return the string encoding which should be used for a given parameter.
1277 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1279 /* First try the parameter marshal info */
1281 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
1282 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
1283 return spec
->data
.array_data
.elem_type
;
1286 return spec
->native
;
1290 return MONO_NATIVE_LPSTR
;
1292 /* Then try the method level marshal info */
1293 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1294 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1295 return MONO_NATIVE_LPSTR
;
1296 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1297 return MONO_NATIVE_LPWSTR
;
1298 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1300 return MONO_NATIVE_LPWSTR
;
1302 return MONO_NATIVE_LPSTR
;
1305 return MONO_NATIVE_LPSTR
;
1310 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1312 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1315 case MONO_NATIVE_LPWSTR
:
1316 return MONO_MARSHAL_CONV_STR_LPWSTR
;
1317 case MONO_NATIVE_LPSTR
:
1318 case MONO_NATIVE_VBBYREFSTR
:
1319 return MONO_MARSHAL_CONV_STR_LPSTR
;
1320 case MONO_NATIVE_LPTSTR
:
1321 return MONO_MARSHAL_CONV_STR_LPTSTR
;
1322 case MONO_NATIVE_BSTR
:
1323 return MONO_MARSHAL_CONV_STR_BSTR
;
1324 case MONO_NATIVE_UTF8STR
:
1325 return MONO_MARSHAL_CONV_STR_UTF8STR
;
1327 return MONO_MARSHAL_CONV_INVALID
;
1332 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1334 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1337 case MONO_NATIVE_LPWSTR
:
1338 return MONO_MARSHAL_CONV_SB_LPWSTR
;
1339 case MONO_NATIVE_LPSTR
:
1340 return MONO_MARSHAL_CONV_SB_LPSTR
;
1341 case MONO_NATIVE_UTF8STR
:
1342 return MONO_MARSHAL_CONV_SB_UTF8STR
;
1343 case MONO_NATIVE_LPTSTR
:
1344 return MONO_MARSHAL_CONV_SB_LPTSTR
;
1346 return MONO_MARSHAL_CONV_INVALID
;
1351 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1353 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1358 case MONO_NATIVE_LPWSTR
:
1360 return MONO_MARSHAL_CONV_LPWSTR_STR
;
1361 case MONO_NATIVE_UTF8STR
:
1362 return MONO_MARSHAL_CONV_UTF8STR_STR
;
1363 case MONO_NATIVE_LPSTR
:
1364 case MONO_NATIVE_VBBYREFSTR
:
1365 return MONO_MARSHAL_CONV_LPSTR_STR
;
1366 case MONO_NATIVE_LPTSTR
:
1370 return MONO_MARSHAL_CONV_LPTSTR_STR
;
1371 case MONO_NATIVE_BSTR
:
1372 return MONO_MARSHAL_CONV_BSTR_STR
;
1374 return MONO_MARSHAL_CONV_INVALID
;
1379 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1381 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1386 case MONO_NATIVE_LPWSTR
:
1387 return MONO_MARSHAL_CONV_LPWSTR_SB
;
1388 case MONO_NATIVE_UTF8STR
:
1389 return MONO_MARSHAL_CONV_UTF8STR_SB
;
1390 case MONO_NATIVE_LPSTR
:
1391 return MONO_MARSHAL_CONV_LPSTR_SB
;
1393 case MONO_NATIVE_LPTSTR
:
1394 return MONO_MARSHAL_CONV_LPTSTR_SB
;
1397 return MONO_MARSHAL_CONV_INVALID
;
1402 * Return whenever a field of a native structure or an array member needs to
1406 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1408 MonoMarshalNative encoding
;
1411 case MONO_TYPE_VALUETYPE
:
1412 /* FIXME: Optimize this */
1414 case MONO_TYPE_OBJECT
:
1415 case MONO_TYPE_CLASS
:
1416 if (t
->data
.klass
== mono_class_try_get_stringbuilder_class ()) {
1418 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
1422 case MONO_TYPE_STRING
:
1423 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1424 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
1431 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
1434 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1437 mono_marshal_lock ();
1440 g_hash_table_new (hash_func
, equal_func
);
1441 mono_memory_barrier ();
1444 mono_marshal_unlock ();
1450 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1452 return get_cache (var
, hash_func
, equal_func
);
1456 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
1460 mono_marshal_lock ();
1461 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1462 mono_marshal_unlock ();
1469 * Create a MonoMethod from MB, set INFO as wrapper info.
1472 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1473 int max_stack
, WrapperInfo
*info
)
1477 res
= mono_mb_create_method (mb
, sig
, max_stack
);
1479 mono_marshal_set_wrapper_info (res
, info
);
1483 /* Create the method from the builder and place it in the cache */
1485 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
1486 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1487 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
1494 mono_marshal_lock ();
1495 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1496 mono_marshal_unlock ();
1499 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
1500 mono_marshal_lock ();
1501 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1504 g_hash_table_insert (cache
, key
, res
);
1505 mono_marshal_set_wrapper_info (res
, info
);
1506 mono_marshal_unlock ();
1510 mono_marshal_unlock ();
1511 mono_free_method (newm
);
1519 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
1520 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1523 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
1527 * mono_marshal_method_from_wrapper:
1530 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
1533 int wrapper_type
= wrapper
->wrapper_type
;
1536 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1539 info
= mono_marshal_get_wrapper_info (wrapper
);
1541 switch (wrapper_type
) {
1542 case MONO_WRAPPER_REMOTING_INVOKE
:
1543 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
1544 case MONO_WRAPPER_XDOMAIN_INVOKE
:
1545 m
= info
->d
.remoting
.method
;
1546 if (wrapper
->is_inflated
) {
1550 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
1551 * contains an uninflated method.
1553 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1554 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1558 case MONO_WRAPPER_SYNCHRONIZED
:
1559 m
= info
->d
.synchronized
.method
;
1560 if (wrapper
->is_inflated
) {
1563 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1564 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1568 case MONO_WRAPPER_UNBOX
:
1569 return info
->d
.unbox
.method
;
1570 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
1571 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
1572 return info
->d
.managed_to_native
.method
;
1575 case MONO_WRAPPER_RUNTIME_INVOKE
:
1576 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
1577 return info
->d
.runtime_invoke
.method
;
1580 case MONO_WRAPPER_DELEGATE_INVOKE
:
1582 return info
->d
.delegate_invoke
.method
;
1591 * mono_marshal_get_wrapper_info:
1593 * Retrieve the WrapperInfo structure associated with WRAPPER.
1596 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
1598 g_assert (wrapper
->wrapper_type
);
1600 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
1604 * mono_marshal_set_wrapper_info:
1606 * Set the WrapperInfo structure associated with the wrapper
1607 * method METHOD to INFO.
1610 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
1614 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1617 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
1622 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
1626 info
= (WrapperInfo
*)mono_image_alloc0 (get_method_image (mb
->method
), sizeof (WrapperInfo
));
1627 info
->subtype
= subtype
;
1632 * get_wrapper_target_class:
1634 * Return the class where a wrapper method should be placed.
1637 get_wrapper_target_class (MonoImage
*image
)
1644 * - can't put all wrappers into an mscorlib class, because they reference
1645 * metadata (signature) so they should be put into the same image as the
1646 * method they wrap, so they are unloaded together.
1647 * - putting them into a class with a type initalizer could cause the
1648 * initializer to be executed which can be a problem if the wrappers are
1650 * - putting them into an inflated class can cause problems if the the
1651 * class is deleted because it references an image which is unloaded.
1652 * To avoid these problems, we put the wrappers into the <Module> class of
1655 if (image_is_dynamic (image
)) {
1656 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
1658 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), error
);
1659 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1667 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
1668 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
1672 * check_generic_wrapper_cache:
1674 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
1675 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
1676 * generic method definition.
1679 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
1682 MonoMethod
*inst
, *def
;
1683 MonoGenericContext
*ctx
;
1685 g_assert (orig_method
->is_inflated
);
1686 ctx
= mono_method_get_context (orig_method
);
1689 * Look for the instance
1691 res
= mono_marshal_find_in_cache (cache
, key
);
1696 * Look for the definition
1698 def
= mono_marshal_find_in_cache (cache
, def_key
);
1701 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1702 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1704 mono_memory_barrier ();
1705 mono_marshal_lock ();
1706 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1708 g_hash_table_insert (cache
, key
, inst
);
1711 mono_marshal_unlock ();
1718 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
1721 MonoMethod
*inst
, *res
;
1724 * We use the same cache for the generic definition and the instances.
1726 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1727 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1728 mono_memory_barrier ();
1729 mono_marshal_lock ();
1730 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1732 g_hash_table_insert (cache
, key
, inst
);
1735 mono_marshal_unlock ();
1740 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
1744 MonoMethod
*inst
, *def
;
1747 * Look for the instance
1749 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
1754 * Look for the definition
1756 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
1758 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1759 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1762 mono_memory_barrier ();
1763 mono_marshal_lock ();
1764 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1766 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1769 mono_marshal_unlock ();
1776 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
1779 MonoMethod
*inst
, *res
;
1780 WrapperInfo
*ginfo
, *info
;
1783 * We use the same cache for the generic definition and the instances.
1785 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1786 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
1788 ginfo
= mono_marshal_get_wrapper_info (def
);
1790 info
= (WrapperInfo
*)mono_image_alloc0 (m_class_get_image (def
->klass
), sizeof (WrapperInfo
));
1791 info
->subtype
= ginfo
->subtype
;
1792 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
1793 info
->d
.delegate_invoke
.method
= mono_class_inflate_generic_method_checked (ginfo
->d
.delegate_invoke
.method
, ctx
, error
);
1794 mono_error_assert_ok (error
);
1798 mono_memory_barrier ();
1799 mono_marshal_lock ();
1800 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1802 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1805 mono_marshal_unlock ();
1809 #ifndef ENABLE_ILGEN
1811 emit_delegate_begin_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1817 * mono_marshal_get_delegate_begin_invoke:
1820 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
1822 MonoMethodSignature
*sig
;
1823 MonoMethodBuilder
*mb
;
1827 MonoGenericContext
*ctx
= NULL
;
1828 MonoMethod
*orig_method
= NULL
;
1830 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
1831 !strcmp (method
->name
, "BeginInvoke"));
1834 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
1836 if (method
->is_inflated
) {
1837 orig_method
= method
;
1838 ctx
= &((MonoMethodInflated
*)method
)->context
;
1839 method
= ((MonoMethodInflated
*)method
)->declaring
;
1842 sig
= mono_signature_no_pinvoke (method
);
1848 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1849 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
1853 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_begin_invoke_cache
,
1854 (GHashFunc
)mono_signature_hash
,
1855 (GCompareFunc
)mono_metadata_signature_equal
);
1856 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
1860 g_assert (sig
->hasthis
);
1862 name
= mono_signature_to_name (sig
, "begin_invoke");
1864 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1866 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1869 get_marshal_cb ()->emit_delegate_begin_invoke (mb
, sig
);
1871 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
1872 info
->d
.delegate_invoke
.method
= method
;
1876 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1877 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
1879 res
= mono_mb_create_and_cache_full (cache
, sig
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1886 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1888 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1891 MonoDomain
*domain
= mono_domain_get ();
1892 MonoAsyncResult
*ares
;
1893 MonoMethod
*method
= NULL
;
1894 MonoMethodSignature
*sig
;
1895 MonoMethodMessage
*msg
;
1896 MonoObject
*res
, *exc
;
1897 MonoArray
*out_args
;
1900 g_assert (delegate
);
1902 if (!delegate
->method_info
) {
1903 g_assert (delegate
->method
);
1904 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, error
);
1905 if (!is_ok (error
)) {
1906 mono_error_set_pending_exception (error
);
1909 MONO_OBJECT_SETREF_INTERNAL (delegate
, method_info
, rm
);
1912 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
1913 g_assert_not_reached ();
1915 klass
= delegate
->object
.vtable
->klass
;
1917 method
= mono_get_delegate_end_invoke_checked (klass
, error
);
1918 mono_error_assert_ok (error
);
1919 g_assert (method
!= NULL
);
1921 sig
= mono_signature_no_pinvoke (method
);
1923 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, error
);
1924 if (mono_error_set_pending_exception (error
))
1927 ares
= (MonoAsyncResult
*)mono_array_get_internal (msg
->args
, gpointer
, sig
->param_count
- 1);
1929 mono_error_set_remoting (error
, "The async result object is null or of an unexpected type.");
1930 mono_error_set_pending_exception (error
);
1934 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
1935 mono_error_set_invalid_operation (error
,
1936 "%s", "The IAsyncResult object provided does not match this delegate.");
1937 mono_error_set_pending_exception (error
);
1941 #ifndef DISABLE_REMOTING
1942 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1943 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1944 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
1945 if (!is_ok (error
)) {
1946 mono_error_set_pending_exception (error
);
1949 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, error
);
1950 if (mono_error_set_pending_exception (error
))
1952 msg
->call_type
= CallType_EndInvoke
;
1953 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1954 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1955 if (!is_ok (error
)) {
1956 mono_error_set_pending_exception (error
);
1962 res
= mono_threadpool_end_invoke (ares
, &out_args
, &exc
, error
);
1963 if (mono_error_set_pending_exception (error
))
1968 if (((MonoException
*)exc
)->stack_trace
) {
1969 ERROR_DECL (inner_error
);
1970 char *strace
= mono_string_to_utf8_checked_internal (((MonoException
*)exc
)->stack_trace
, inner_error
);
1971 if (is_ok (inner_error
)) {
1973 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
1975 MonoString
*tmp_str
= mono_string_new_checked (domain
, tmp
, inner_error
);
1977 if (is_ok (inner_error
))
1978 MONO_OBJECT_SETREF_INTERNAL (((MonoException
*)exc
), stack_trace
, tmp_str
);
1980 if (!is_ok (inner_error
))
1981 mono_error_cleanup (inner_error
); /* no stack trace, but at least throw the original exception */
1983 mono_set_pending_exception ((MonoException
*)exc
);
1986 mono_method_return_message_restore (method
, params
, out_args
, error
);
1987 mono_error_set_pending_exception (error
);
1991 #ifndef ENABLE_ILGEN
1993 emit_delegate_end_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1999 * mono_marshal_get_delegate_end_invoke:
2002 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
2004 MonoMethodSignature
*sig
;
2005 MonoMethodBuilder
*mb
;
2009 MonoGenericContext
*ctx
= NULL
;
2010 MonoMethod
*orig_method
= NULL
;
2012 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2013 !strcmp (method
->name
, "EndInvoke"));
2016 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
2018 if (method
->is_inflated
) {
2019 orig_method
= method
;
2020 ctx
= &((MonoMethodInflated
*)method
)->context
;
2021 method
= ((MonoMethodInflated
*)method
)->declaring
;
2024 sig
= mono_signature_no_pinvoke (method
);
2030 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2031 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2035 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_end_invoke_cache
,
2036 (GHashFunc
)mono_signature_hash
,
2037 (GCompareFunc
)mono_metadata_signature_equal
);
2038 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2042 g_assert (sig
->hasthis
);
2044 name
= mono_signature_to_name (sig
, "end_invoke");
2046 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2048 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2051 get_marshal_cb ()->emit_delegate_end_invoke (mb
, sig
);
2053 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
2054 info
->d
.delegate_invoke
.method
= method
;
2058 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2059 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2061 res
= mono_mb_create_and_cache_full (cache
, sig
,
2062 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2071 MonoMethodSignature
*sig
;
2073 } SignaturePointerPair
;
2076 signature_pointer_pair_hash (gconstpointer data
)
2078 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
2080 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
2084 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
2086 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
2087 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
2091 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
2093 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
2095 return pair
->pointer
== user_data
;
2099 free_signature_pointer_pair (SignaturePointerPair
*pair
)
2104 #ifndef ENABLE_ILGEN
2106 mb_skip_visibility_noilgen (MonoMethodBuilder
*mb
)
2111 mb_set_dynamic_noilgen (MonoMethodBuilder
*mb
)
2116 mb_emit_exception_noilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
2121 mb_emit_exception_for_error_noilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
2126 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
)
2132 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
2134 MonoMethodSignature
*sig
, *invoke_sig
;
2135 MonoMethodBuilder
*mb
;
2138 gpointer cache_key
= NULL
;
2139 SignaturePointerPair key
= { NULL
, NULL
};
2140 SignaturePointerPair
*new_key
;
2142 MonoClass
*target_class
= NULL
;
2143 gboolean closed_over_null
= FALSE
;
2144 MonoGenericContext
*ctx
= NULL
;
2145 MonoGenericContainer
*container
= NULL
;
2146 MonoMethod
*orig_method
= method
;
2148 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
2151 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2152 !strcmp (method
->name
, "Invoke"));
2154 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2157 * If the delegate target is null, and the target method is not static, a virtual
2158 * call is made to that method with the first delegate argument as this. This is
2159 * a non-documented .NET feature.
2162 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
2163 if (target_method
->is_inflated
) {
2165 MonoType
*target_type
;
2167 g_assert (method
->signature
->hasthis
);
2168 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
2169 mono_method_get_context (method
), error
);
2170 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
2171 target_class
= mono_class_from_mono_type_internal (target_type
);
2173 target_class
= target_method
->klass
;
2176 closed_over_null
= sig
->param_count
== mono_method_signature_internal (target_method
)->param_count
;
2179 if (static_method_with_first_arg_bound
) {
2180 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
2181 g_assert (!callvirt
);
2182 invoke_sig
= mono_method_signature_internal (target_method
);
2184 * The wrapper has a different lifetime from the method to be invoked.
2185 * If the method is dynamic we don't want to be using its signature
2186 * in the wrapper since it could get freed early.
2188 if (method_is_dynamic (target_method
))
2189 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (target_method
), invoke_sig
);
2193 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
2195 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
2196 ctx
= &((MonoMethodInflated
*)method
)->context
;
2197 method
= ((MonoMethodInflated
*)method
)->declaring
;
2199 container
= mono_method_get_generic_container (method
);
2201 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
2202 g_assert (container
);
2204 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2211 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2212 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2215 cache_key
= method
->klass
;
2216 } else if (static_method_with_first_arg_bound
) {
2217 cache
= get_cache (&get_method_image (target_method
)->delegate_bound_static_invoke_cache
,
2218 (GHashFunc
)mono_signature_hash
,
2219 (GCompareFunc
)mono_metadata_signature_equal
);
2221 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
2223 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
2226 cache_key
= invoke_sig
;
2227 } else if (callvirt
) {
2228 GHashTable
**cache_ptr
;
2230 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
2232 /* We need to cache the signature+method pair */
2233 mono_marshal_lock ();
2235 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
2237 key
.sig
= invoke_sig
;
2238 key
.pointer
= target_method
;
2239 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
2240 mono_marshal_unlock ();
2244 // Inflated methods should not be in this cache because it's not stored on the imageset.
2245 g_assert (!method
->is_inflated
);
2246 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_invoke_cache
,
2247 (GHashFunc
)mono_signature_hash
,
2248 (GCompareFunc
)mono_metadata_signature_equal
);
2249 res
= mono_marshal_find_in_cache (cache
, sig
);
2255 if (!static_method_with_first_arg_bound
) {
2256 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
2257 invoke_sig
->hasthis
= 0;
2260 if (static_method_with_first_arg_bound
)
2261 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
2262 else if (closed_over_null
)
2263 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
2265 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
2267 name
= mono_signature_to_name (invoke_sig
, "invoke");
2269 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2271 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2274 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
);
2276 get_marshal_cb ()->mb_skip_visibility (mb
);
2278 info
= mono_wrapper_info_create (mb
, subtype
);
2279 info
->d
.delegate_invoke
.method
= method
;
2284 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2285 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2286 } else if (callvirt
) {
2287 new_key
= g_new0 (SignaturePointerPair
, 1);
2290 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
2294 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2298 /* mono_method_print_code (res); */
2304 * mono_marshal_get_delegate_invoke:
2305 * The returned method invokes all methods in a multicast delegate.
2308 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
2310 gboolean callvirt
= FALSE
;
2311 gboolean static_method_with_first_arg_bound
= FALSE
;
2312 MonoMethod
*target_method
= NULL
;
2313 MonoMethodSignature
*sig
;
2315 sig
= mono_signature_no_pinvoke (method
);
2317 if (del
&& !del
->target
&& del
->method
&& mono_method_signature_internal (del
->method
)->hasthis
) {
2319 target_method
= del
->method
;
2322 if (del
&& del
->method
&& mono_method_signature_internal (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2323 static_method_with_first_arg_bound
= TRUE
;
2324 target_method
= del
->method
;
2327 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
2331 MonoMethodSignature
*ctor_sig
;
2332 MonoMethodSignature
*sig
;
2335 /* protected by the marshal lock, contains CtorSigPair pointers */
2336 static GSList
*strsig_list
= NULL
;
2338 static MonoMethodSignature
*
2339 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
2341 MonoMethodSignature
*callsig
;
2345 mono_marshal_lock ();
2347 for (item
= strsig_list
; item
; item
= item
->next
) {
2348 cs
= (CtorSigPair
*)item
->data
;
2349 /* mono_metadata_signature_equal () is safe to call with the marshal lock
2350 * because it is lock-free.
2352 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
2357 mono_marshal_unlock ();
2361 static MonoMethodSignature
*
2362 add_string_ctor_signature (MonoMethod
*method
)
2364 MonoMethodSignature
*callsig
;
2367 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2368 callsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2369 cs
= g_new (CtorSigPair
, 1);
2371 cs
->ctor_sig
= mono_method_signature_internal (method
);
2373 mono_marshal_lock ();
2374 strsig_list
= g_slist_prepend (strsig_list
, cs
);
2375 mono_marshal_unlock ();
2380 * mono_marshal_get_string_ctor_signature:
2382 * Return the modified signature used by string ctors (they return the newly created
2385 MonoMethodSignature
*
2386 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
2388 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2390 sig
= add_string_ctor_signature (method
);
2396 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
2399 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2402 /* The result needs loaded indirectly */
2406 /* Can't share this with 'I' as that needs another indirection */
2407 return m_class_get_this_arg (mono_defaults
.int_class
);
2410 if (MONO_TYPE_IS_REFERENCE (t
))
2411 return mono_get_object_type ();
2414 /* The result needs to be boxed */
2419 /* Can't share these as the argument needs to be loaded using sign/zero extension */
2422 return m_class_get_byval_arg (mono_defaults.sbyte_class);
2424 return m_class_get_byval_arg (mono_defaults.int16_class);
2426 return mono_get_int32_type ();
2429 return m_class_get_byval_arg (mono_defaults
.int64_class
);
2430 case MONO_TYPE_BOOLEAN
:
2431 return m_class_get_byval_arg (mono_defaults
.byte_class
);
2432 case MONO_TYPE_CHAR
:
2433 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
2435 return mono_get_int_type ();
2436 case MONO_TYPE_VALUETYPE
:
2437 if (m_class_is_enumtype (t
->data
.klass
)) {
2438 t
= mono_class_enum_basetype_internal (t
->data
.klass
);
2448 * mono_marshal_get_runtime_invoke_sig:
2450 * Return a common signature used for sharing runtime invoke wrappers.
2452 static MonoMethodSignature
*
2453 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
2455 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
2458 res
->generic_param_count
= 0;
2459 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
2460 for (i
= 0; i
< res
->param_count
; ++i
)
2461 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
2467 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
2469 /* Can't share wrappers which return a vtype since it needs to be boxed */
2470 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
))
2473 return mono_metadata_signature_equal (sig1
, sig2
);
2476 struct _MonoWrapperMethodCacheKey
{
2479 gboolean need_direct_wrapper
;
2482 struct _MonoWrapperSignatureCacheKey
{
2483 MonoMethodSignature
*signature
;
2487 typedef struct _MonoWrapperMethodCacheKey MonoWrapperMethodCacheKey
;
2488 typedef struct _MonoWrapperSignatureCacheKey MonoWrapperSignatureCacheKey
;
2491 wrapper_cache_method_key_hash (MonoWrapperMethodCacheKey
*key
)
2493 return mono_aligned_addr_hash (key
->method
) ^ (((!!key
->virtual_
) << 17) | ((!!key
->need_direct_wrapper
) << 19) * 17);
2497 wrapper_cache_signature_key_hash (MonoWrapperSignatureCacheKey
*key
)
2499 return mono_signature_hash (key
->signature
) ^ (((!!key
->valuetype
) << 18) * 17);
2503 wrapper_cache_method_key_equal (MonoWrapperMethodCacheKey
*key1
, MonoWrapperMethodCacheKey
*key2
)
2505 if (key1
->virtual_
!= key2
->virtual_
|| key1
->need_direct_wrapper
!= key2
->need_direct_wrapper
)
2507 return key1
->method
== key2
->method
;
2511 wrapper_cache_signature_key_equal (MonoWrapperSignatureCacheKey
*key1
, MonoWrapperSignatureCacheKey
*key2
)
2513 if (key1
->valuetype
!= key2
->valuetype
)
2515 return runtime_invoke_signature_equal (key1
->signature
, key2
->signature
);
2519 * mono_marshal_get_runtime_invoke:
2520 * Generates IL code for the runtime invoke function:
2522 * <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
2524 * We also catch exceptions if \p exc is not NULL.
2525 * If \p virtual is TRUE, then \p method is invoked virtually on \p this. This is useful since
2526 * it means that the compiled code for \p method does not have to be looked up
2527 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
2528 * its \p method argument.
2531 mono_marshal_get_runtime_invoke_full (MonoMethod
*method
, gboolean virtual_
, gboolean need_direct_wrapper
)
2533 MonoMethodSignature
*sig
, *csig
, *callsig
;
2534 MonoMethodBuilder
*mb
;
2535 GHashTable
*method_cache
= NULL
, *sig_cache
= NULL
;
2536 GHashTable
**cache_table
= NULL
;
2537 MonoClass
*target_klass
;
2538 MonoMethod
*res
= NULL
;
2539 static MonoMethodSignature
*cctor_signature
= NULL
;
2540 static MonoMethodSignature
*finalize_signature
= NULL
;
2542 const char *param_names
[16];
2544 MonoWrapperMethodCacheKey
*method_key
;
2545 MonoWrapperMethodCacheKey method_key_lookup_only
;
2546 memset (&method_key_lookup_only
, 0, sizeof (method_key_lookup_only
));
2547 method_key_lookup_only
.method
= method
;
2548 method_key_lookup_only
.virtual_
= virtual_
;
2549 method_key_lookup_only
.need_direct_wrapper
= need_direct_wrapper
;
2550 method_key
= &method_key_lookup_only
;
2554 if (!cctor_signature
) {
2555 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2556 cctor_signature
->ret
= mono_get_void_type ();
2558 if (!finalize_signature
) {
2559 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2560 finalize_signature
->ret
= mono_get_void_type ();
2561 finalize_signature
->hasthis
= 1;
2564 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_method_cache
;
2565 method_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_method_key_hash
, (GCompareFunc
) wrapper_cache_method_key_equal
);
2567 res
= mono_marshal_find_in_cache (method_cache
, method_key
);
2571 if (method
->string_ctor
) {
2572 callsig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2574 callsig
= add_string_ctor_signature (method
);
2576 if (method_is_dynamic (method
))
2577 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2579 callsig
= mono_method_signature_internal (method
);
2582 sig
= mono_method_signature_internal (method
);
2584 target_klass
= get_wrapper_target_class (m_class_get_image (method
->klass
));
2586 /* Try to share wrappers for non-corlib methods with simple signatures */
2587 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
2588 callsig
= cctor_signature
;
2589 target_klass
= mono_defaults
.object_class
;
2590 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
2591 callsig
= finalize_signature
;
2592 target_klass
= mono_defaults
.object_class
;
2595 if (need_direct_wrapper
|| virtual_
) {
2596 /* Already searched at the start. We cannot cache those wrappers based
2597 * on signatures because they contain a reference to the method */
2599 MonoMethodSignature
*tmp_sig
;
2601 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
2602 MonoWrapperSignatureCacheKey sig_key
;
2603 memset (&sig_key
, 0, sizeof (sig_key
));
2604 sig_key
.signature
= callsig
;
2605 sig_key
.valuetype
= m_class_is_valuetype (method
->klass
);
2607 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_signature_cache
;
2608 sig_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_signature_key_hash
, (GCompareFunc
) wrapper_cache_signature_key_equal
);
2610 /* from mono_marshal_find_in_cache */
2611 mono_marshal_lock ();
2612 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, &sig_key
);
2613 mono_marshal_unlock ();
2620 /* Make a copy of the signature from the image mempool */
2622 callsig
= mono_metadata_signature_dup_full (m_class_get_image (target_klass
), callsig
);
2626 csig
= mono_metadata_signature_alloc (m_class_get_image (target_klass
), 4);
2628 MonoType
*object_type
= mono_get_object_type ();
2629 MonoType
*int_type
= mono_get_int_type ();
2631 csig
->ret
= object_type
;
2632 if (m_class_is_valuetype (method
->klass
) && mono_method_signature_internal (method
)->hasthis
)
2633 csig
->params
[0] = get_runtime_invoke_type (m_class_get_this_arg (method
->klass
), FALSE
);
2635 csig
->params
[0] = object_type
;
2636 csig
->params
[1] = int_type
;
2637 csig
->params
[2] = int_type
;
2638 csig
->params
[3] = int_type
;
2641 /* This is called from runtime code so it has to be cdecl */
2642 csig
->call_convention
= MONO_CALL_C
;
2645 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : (need_direct_wrapper
? "runtime_invoke_direct" : "runtime_invoke"));
2646 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2649 param_names
[0] = "this";
2650 param_names
[1] = "params";
2651 param_names
[2] = "exc";
2652 param_names
[3] = "method";
2654 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, m_class_get_image (target_klass
), method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
2656 method_key
= g_new (MonoWrapperMethodCacheKey
, 1);
2657 memcpy (method_key
, &method_key_lookup_only
, sizeof (MonoWrapperMethodCacheKey
));
2659 if (need_direct_wrapper
|| virtual_
) {
2660 get_marshal_cb ()->mb_skip_visibility (mb
);
2661 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
2662 info
->d
.runtime_invoke
.method
= method
;
2663 res
= mono_mb_create_and_cache_full (method_cache
, method_key
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
2665 MonoWrapperSignatureCacheKey
*sig_key
= g_new0 (MonoWrapperSignatureCacheKey
, 1);
2666 sig_key
->signature
= callsig
;
2667 sig_key
->valuetype
= m_class_is_valuetype (method
->klass
);
2669 /* taken from mono_mb_create_and_cache */
2670 mono_marshal_lock ();
2671 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2672 mono_marshal_unlock ();
2674 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2675 info
->d
.runtime_invoke
.sig
= callsig
;
2677 /* Somebody may have created it before us */
2680 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2682 mono_marshal_lock ();
2683 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2686 g_hash_table_insert (sig_cache
, sig_key
, res
);
2687 g_hash_table_insert (method_cache
, method_key
, res
);
2689 mono_free_method (newm
);
2691 g_free (method_key
);
2693 mono_marshal_unlock ();
2696 g_free (method_key
);
2699 /* end mono_mb_create_and_cache */
2708 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
2710 gboolean need_direct_wrapper
= FALSE
;
2713 need_direct_wrapper
= TRUE
;
2715 if (method
->dynamic
)
2716 need_direct_wrapper
= TRUE
;
2718 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2719 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2721 * Array Get/Set/Address methods. The JIT implements them using inline code
2722 * so we need to create an invoke wrapper which calls the method directly.
2724 need_direct_wrapper
= TRUE
;
2727 if (method
->string_ctor
) {
2728 /* Can't share this as we push a string as this */
2729 need_direct_wrapper
= TRUE
;
2732 return mono_marshal_get_runtime_invoke_full (method
, virtual_
, need_direct_wrapper
);
2735 #ifndef ENABLE_ILGEN
2737 emit_runtime_invoke_body_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
2738 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
2739 gboolean virtual_
, gboolean need_direct_wrapper
)
2744 emit_runtime_invoke_dynamic_noilgen (MonoMethodBuilder
*mb
)
2750 * mono_marshal_get_runtime_invoke_dynamic:
2752 * Return a method which can be used to invoke managed methods from native code
2754 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
2755 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
2756 * ARGS should point to an architecture specific structure containing
2757 * the arguments and space for the return value.
2758 * The other arguments are the same as for runtime_invoke (), except that
2759 * ARGS should contain the this argument too.
2760 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
2761 * is only one copy of it, which is useful in full-aot.
2764 mono_marshal_get_runtime_invoke_dynamic (void)
2766 static MonoMethod
*method
;
2767 MonoMethodSignature
*csig
;
2768 MonoMethodBuilder
*mb
;
2775 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
2777 MonoType
*void_type
= mono_get_void_type ();
2778 MonoType
*int_type
= mono_get_int_type ();
2780 csig
->ret
= void_type
;
2781 csig
->params
[0] = int_type
;
2782 csig
->params
[1] = int_type
;
2783 csig
->params
[2] = int_type
;
2784 csig
->params
[3] = int_type
;
2786 name
= g_strdup ("runtime_invoke_dynamic");
2787 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2790 get_marshal_cb ()->emit_runtime_invoke_dynamic (mb
);
2792 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
2794 mono_marshal_lock ();
2795 /* double-checked locking */
2797 method
= mono_mb_create (mb
, csig
, 16, info
);
2799 mono_marshal_unlock ();
2807 * mono_marshal_get_runtime_invoke_for_sig:
2809 * Return a runtime invoke wrapper for a given signature.
2812 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
2814 MonoMethodSignature
*csig
, *callsig
;
2815 MonoMethodBuilder
*mb
;
2817 GHashTable
*cache
= NULL
;
2818 GHashTable
**cache_table
= NULL
;
2819 MonoMethod
*res
= NULL
;
2821 const char *param_names
[16];
2824 /* A simplified version of mono_marshal_get_runtime_invoke */
2826 image
= mono_defaults
.corlib
;
2828 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
2830 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
2832 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
2833 (GCompareFunc
)runtime_invoke_signature_equal
);
2835 /* from mono_marshal_find_in_cache */
2836 mono_marshal_lock ();
2837 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2838 mono_marshal_unlock ();
2845 /* Make a copy of the signature from the image mempool */
2846 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
2848 MonoType
*object_type
= mono_get_object_type ();
2849 MonoType
*int_type
= mono_get_int_type ();
2850 csig
= mono_metadata_signature_alloc (image
, 4);
2851 csig
->ret
= object_type
;
2852 csig
->params
[0] = object_type
;
2853 csig
->params
[1] = int_type
;
2854 csig
->params
[2] = int_type
;
2855 csig
->params
[3] = int_type
;
2858 /* This is called from runtime code so it has to be cdecl */
2859 csig
->call_convention
= MONO_CALL_C
;
2862 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
2863 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2866 param_names
[0] = "this";
2867 param_names
[1] = "params";
2868 param_names
[2] = "exc";
2869 param_names
[3] = "method";
2871 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
2873 /* taken from mono_mb_create_and_cache */
2874 mono_marshal_lock ();
2875 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2876 mono_marshal_unlock ();
2878 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2879 info
->d
.runtime_invoke
.sig
= callsig
;
2881 /* Somebody may have created it before us */
2884 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2886 mono_marshal_lock ();
2887 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2890 g_hash_table_insert (cache
, callsig
, res
);
2892 mono_free_method (newm
);
2894 mono_marshal_unlock ();
2897 /* end mono_mb_create_and_cache */
2904 #ifndef ENABLE_ILGEN
2906 emit_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
2911 emit_return_noilgen (MonoMethodBuilder
*mb
)
2917 * mono_marshal_get_icall_wrapper:
2918 * Generates IL code for the JIT icall wrapper. The generated method
2919 * calls the unmanaged code in \p callinfo->func.
2922 mono_marshal_get_icall_wrapper (MonoJitICallInfo
*callinfo
, gboolean check_exceptions
)
2924 MonoMethodSignature
*csig
, *csig2
;
2925 MonoMethodBuilder
*mb
;
2929 gconstpointer
const func
= callinfo
->func
;
2931 GHashTable
*cache
= get_cache (& m_class_get_image (mono_defaults
.object_class
)->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
2932 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
2935 MonoMethodSignature
*const sig
= callinfo
->sig
;
2936 g_assert (sig
->pinvoke
);
2938 char *const name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
2939 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
2941 mb
->method
->save_lmf
= 1;
2943 /* Add an explicit this argument */
2945 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
2947 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2949 get_marshal_cb ()->emit_icall_wrapper (mb
, callinfo
, csig2
, check_exceptions
);
2951 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2953 if (csig
->call_convention
== MONO_CALL_VARARG
)
2954 csig
->call_convention
= 0;
2956 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
2957 info
->d
.icall
.jit_icall_id
= mono_jit_icall_info_id (callinfo
);
2958 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
2966 mono_marshal_get_aot_init_wrapper_name (MonoAotInitSubtype subtype
)
2968 const char *name
= NULL
;
2970 case AOT_INIT_METHOD
:
2971 name
= "init_method";
2973 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
2974 name
= "init_method_gshared_mrgctx";
2976 case AOT_INIT_METHOD_GSHARED_THIS
:
2977 name
= "init_method_gshared_this";
2979 case AOT_INIT_METHOD_GSHARED_VTABLE
:
2980 name
= "init_method_gshared_vtable";
2983 g_assert_not_reached ();
2989 mono_marshal_get_aot_init_wrapper (MonoAotInitSubtype subtype
)
2991 MonoMethodBuilder
*mb
;
2994 MonoMethodSignature
*csig
= NULL
;
2995 MonoType
*void_type
= mono_get_void_type ();
2996 MonoType
*int_type
= mono_get_int_type ();
2997 const char *name
= mono_marshal_get_aot_init_wrapper_name (subtype
);
3000 case AOT_INIT_METHOD
:
3001 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
3002 csig
->ret
= void_type
;
3003 csig
->params
[0] = int_type
;
3004 csig
->params
[1] = int_type
;
3006 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
3007 case AOT_INIT_METHOD_GSHARED_THIS
:
3008 case AOT_INIT_METHOD_GSHARED_VTABLE
:
3009 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3010 csig
->ret
= void_type
;
3011 csig
->params
[0] = int_type
;
3012 csig
->params
[1] = int_type
;
3013 csig
->params
[2] = int_type
;
3016 g_assert_not_reached ();
3019 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
3021 // Just stub out the method with a "CEE_RET"
3022 // Our codegen backend generates other code here
3023 get_marshal_cb ()->emit_return (mb
);
3025 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_AOT_INIT
);
3026 info
->d
.aot_init
.subtype
= subtype
;
3027 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
3034 * mono_marshal_get_llvm_func_wrapper:
3036 * Return a dummy wrapper which represents an LLVM function to the
3037 * rest of the runtime for EH etc. purposes. The body of the method is
3041 mono_marshal_get_llvm_func_wrapper (MonoLLVMFuncWrapperSubtype subtype
)
3043 MonoMethodBuilder
*mb
;
3046 MonoMethodSignature
*csig
= NULL
;
3047 MonoType
*void_type
= mono_get_void_type ();
3048 MonoType
*int_type
= mono_get_int_type ();
3049 char *name
= g_strdup_printf ("llvm_func_wrapper_%d", subtype
);
3051 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
3052 csig
->ret
= void_type
;
3054 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
3056 // Just stub out the method with a "CEE_RET"
3057 // Our codegen backend generates other code here
3058 get_marshal_cb ()->emit_return (mb
);
3060 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_LLVM_FUNC
);
3061 info
->d
.llvm_func
.subtype
= subtype
;
3062 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
3068 #ifndef ENABLE_ILGEN
3070 emit_marshal_custom_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3071 MonoMarshalSpec
*spec
,
3072 int conv_arg
, MonoType
**conv_arg_type
,
3073 MarshalAction action
)
3075 MonoType
*int_type
= mono_get_int_type ();
3076 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
3077 *conv_arg_type
= int_type
;
3082 emit_marshal_asany_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3083 MonoMarshalSpec
*spec
,
3084 int conv_arg
, MonoType
**conv_arg_type
,
3085 MarshalAction action
)
3091 emit_marshal_vtype_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3092 MonoMarshalSpec
*spec
,
3093 int conv_arg
, MonoType
**conv_arg_type
,
3094 MarshalAction action
)
3100 emit_marshal_string_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3101 MonoMarshalSpec
*spec
,
3102 int conv_arg
, MonoType
**conv_arg_type
,
3103 MarshalAction action
)
3105 MonoType
*int_type
= mono_get_int_type ();
3107 case MARSHAL_ACTION_CONV_IN
:
3108 *conv_arg_type
= int_type
;
3110 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3111 *conv_arg_type
= int_type
;
3119 emit_marshal_safehandle_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3120 MonoMarshalSpec
*spec
, int conv_arg
,
3121 MonoType
**conv_arg_type
, MarshalAction action
)
3123 MonoType
*int_type
= mono_get_int_type ();
3124 if (action
== MARSHAL_ACTION_CONV_IN
)
3125 *conv_arg_type
= int_type
;
3131 emit_marshal_handleref_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3132 MonoMarshalSpec
*spec
, int conv_arg
,
3133 MonoType
**conv_arg_type
, MarshalAction action
)
3135 MonoType
*int_type
= mono_get_int_type ();
3136 if (action
== MARSHAL_ACTION_CONV_IN
)
3137 *conv_arg_type
= int_type
;
3143 emit_marshal_object_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3144 MonoMarshalSpec
*spec
,
3145 int conv_arg
, MonoType
**conv_arg_type
,
3146 MarshalAction action
)
3148 MonoType
*int_type
= mono_get_int_type ();
3149 if (action
== MARSHAL_ACTION_CONV_IN
)
3150 *conv_arg_type
= int_type
;
3155 emit_marshal_variant_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3156 MonoMarshalSpec
*spec
,
3157 int conv_arg
, MonoType
**conv_arg_type
,
3158 MarshalAction action
)
3160 g_assert_not_reached ();
3165 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
3167 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
3168 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
3170 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
3172 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
3182 #ifndef ENABLE_ILGEN
3184 emit_marshal_array_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3185 MonoMarshalSpec
*spec
,
3186 int conv_arg
, MonoType
**conv_arg_type
,
3187 MarshalAction action
)
3189 MonoType
*int_type
= mono_get_int_type ();
3190 MonoType
*object_type
= mono_get_object_type ();
3192 case MARSHAL_ACTION_CONV_IN
:
3193 *conv_arg_type
= object_type
;
3195 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3196 *conv_arg_type
= int_type
;
3204 mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
3207 return mono_get_int32_type ();
3209 switch (spec
->native
) {
3210 case MONO_NATIVE_I1
:
3211 case MONO_NATIVE_U1
:
3212 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3213 case MONO_NATIVE_VARIANTBOOL
:
3214 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
3215 return m_class_get_byval_arg (mono_defaults
.int16_class
);
3216 case MONO_NATIVE_BOOLEAN
:
3217 return mono_get_int32_type ();
3219 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3220 return mono_get_int32_type ();
3226 mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
3228 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3230 switch (spec
->native
) {
3231 case MONO_NATIVE_I1
:
3232 case MONO_NATIVE_U1
:
3233 conv_arg_class
= mono_defaults
.byte_class
;
3234 if (ldop
) *ldop
= CEE_LDIND_I1
;
3236 case MONO_NATIVE_VARIANTBOOL
:
3237 conv_arg_class
= mono_defaults
.int16_class
;
3238 if (ldop
) *ldop
= CEE_LDIND_I2
;
3240 case MONO_NATIVE_BOOLEAN
:
3243 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3246 return conv_arg_class
;
3249 #ifndef ENABLE_ILGEN
3251 emit_marshal_boolean_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3252 MonoMarshalSpec
*spec
,
3253 int conv_arg
, MonoType
**conv_arg_type
,
3254 MarshalAction action
)
3256 MonoType
*int_type
= mono_get_int_type ();
3258 case MARSHAL_ACTION_CONV_IN
:
3260 *conv_arg_type
= int_type
;
3262 *conv_arg_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, NULL
);
3265 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3266 MonoClass
* conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
3268 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3270 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3279 emit_marshal_ptr_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3280 MonoMarshalSpec
*spec
, int conv_arg
,
3281 MonoType
**conv_arg_type
, MarshalAction action
)
3287 emit_marshal_char_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3288 MonoMarshalSpec
*spec
, int conv_arg
,
3289 MonoType
**conv_arg_type
, MarshalAction action
)
3295 emit_marshal_scalar_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3296 MonoMarshalSpec
*spec
, int conv_arg
,
3297 MonoType
**conv_arg_type
, MarshalAction action
)
3304 mono_emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3305 MonoMarshalSpec
*spec
, int conv_arg
,
3306 MonoType
**conv_arg_type
, MarshalAction action
)
3308 /* Ensure that we have marshalling info for this param */
3309 mono_marshal_load_type_info (mono_class_from_mono_type_internal (t
));
3311 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
3312 return get_marshal_cb ()->emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3314 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
3315 return get_marshal_cb ()->emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3318 case MONO_TYPE_VALUETYPE
:
3319 if (t
->data
.klass
== mono_class_try_get_handleref_class ())
3320 return get_marshal_cb ()->emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3322 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3323 case MONO_TYPE_STRING
:
3324 return get_marshal_cb ()->emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3325 case MONO_TYPE_CLASS
:
3326 case MONO_TYPE_OBJECT
:
3327 #if !defined(DISABLE_COM)
3328 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
3329 return get_marshal_cb ()->emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3332 #if !defined(DISABLE_COM)
3333 if ((spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
3334 spec
->native
== MONO_NATIVE_IDISPATCH
||
3335 spec
->native
== MONO_NATIVE_INTERFACE
)) ||
3336 (t
->type
== MONO_TYPE_CLASS
&& mono_cominterop_is_interface(t
->data
.klass
)))
3337 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3338 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
3339 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
3340 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
3341 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3344 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
3345 mono_class_is_subclass_of_internal (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
3346 return get_marshal_cb ()->emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3348 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3349 case MONO_TYPE_ARRAY
:
3350 case MONO_TYPE_SZARRAY
:
3351 return get_marshal_cb ()->emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3352 case MONO_TYPE_BOOLEAN
:
3353 return get_marshal_cb ()->emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3355 return get_marshal_cb ()->emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3356 case MONO_TYPE_CHAR
:
3357 return get_marshal_cb ()->emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3370 case MONO_TYPE_FNPTR
:
3371 return get_marshal_cb ()->emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3372 case MONO_TYPE_GENERICINST
:
3373 if (mono_type_generic_inst_is_valuetype (t
))
3374 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3376 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3382 #ifndef ENABLE_ILGEN
3384 emit_create_string_hack_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
3389 emit_native_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*pinfo
)
3395 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean set_default
)
3397 MonoMethodSignature
*sig
;
3402 * Under windows, delegates passed to native code must use the STDCALL
3403 * calling convention.
3406 csig
->call_convention
= MONO_CALL_STDCALL
;
3409 sig
= mono_method_signature_internal (method
);
3413 cmod_count
= mono_type_custom_modifier_count (sig
->ret
);
3415 /* Change default calling convention if needed */
3416 /* Why is this a modopt ? */
3417 if (cmod_count
== 0)
3420 for (i
= 0; i
< cmod_count
; ++i
) {
3423 MonoType
*cmod_type
= mono_type_get_custom_modifier (sig
->ret
, i
, &required
, error
);
3424 mono_error_assert_ok (error
);
3425 MonoClass
*cmod_class
= mono_class_from_mono_type_internal (cmod_type
);
3426 if ((m_class_get_image (cmod_class
) == mono_defaults
.corlib
) && !strcmp (m_class_get_name_space (cmod_class
), "System.Runtime.CompilerServices")) {
3427 const char *cmod_class_name
= m_class_get_name (cmod_class
);
3428 if (!strcmp (cmod_class_name
, "CallConvCdecl"))
3429 csig
->call_convention
= MONO_CALL_C
;
3430 else if (!strcmp (cmod_class_name
, "CallConvStdcall"))
3431 csig
->call_convention
= MONO_CALL_STDCALL
;
3432 else if (!strcmp (cmod_class_name
, "CallConvFastcall"))
3433 csig
->call_convention
= MONO_CALL_FASTCALL
;
3434 else if (!strcmp (cmod_class_name
, "CallConvThiscall"))
3435 csig
->call_convention
= MONO_CALL_THISCALL
;
3441 * mono_marshal_get_native_wrapper:
3442 * \param method The \c MonoMethod to wrap.
3443 * \param check_exceptions Whenever to check for pending exceptions
3445 * Generates IL code for the pinvoke wrapper. The generated method
3446 * calls the unmanaged code in \c piinfo->addr.
3449 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
3451 MonoMethodSignature
*sig
, *csig
;
3452 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
3453 MonoMethodBuilder
*mb
;
3454 MonoMarshalSpec
**mspecs
;
3457 gboolean pinvoke
= FALSE
;
3460 ERROR_DECL (emitted_error
);
3463 g_assert (method
!= NULL
);
3464 g_assert (mono_method_signature_internal (method
)->pinvoke
);
3466 GHashTable
**cache_ptr
;
3468 MonoType
*string_type
= m_class_get_byval_arg (mono_defaults
.string_class
);
3471 if (check_exceptions
)
3472 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
3474 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
3476 if (check_exceptions
)
3477 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
3479 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
3482 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
3484 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3487 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
3488 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
3492 return mono_cominterop_get_native_wrapper (method
);
3494 g_assert_not_reached ();
3498 sig
= mono_method_signature_internal (method
);
3500 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3501 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
3504 if (!piinfo
->addr
) {
3506 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
3507 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "Method contains unsupported native code");
3509 mono_lookup_pinvoke_call_internal (method
, emitted_error
);
3511 if (!aot
|| (method
->klass
== mono_defaults
.string_class
))
3512 piinfo
->addr
= mono_lookup_internal_call (method
);
3516 /* hack - redirect certain string constructors to CreateString */
3517 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
3518 g_assert (!pinvoke
);
3519 g_assert (method
->string_ctor
);
3520 g_assert (sig
->hasthis
);
3522 /* CreateString returns a value */
3523 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3524 csig
->ret
= string_type
;
3528 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
3529 if (!strcmp ("CreateString", res
->name
) &&
3530 mono_metadata_signature_equal (csig
, mono_method_signature_internal (res
))) {
3533 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
3534 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
3536 /* create a wrapper to preserve .ctor in stack trace */
3537 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
3539 get_marshal_cb ()->emit_create_string_hack (mb
, csig
, res
);
3541 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
3542 info
->d
.string_ctor
.method
= method
;
3544 /* use native_wrapper_cache because internal calls are looked up there */
3545 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3546 csig
->param_count
+ 1, info
, NULL
);
3553 /* exception will be thrown */
3554 piinfo
->addr
= NULL
;
3555 g_warning ("cannot find CreateString for .ctor");
3558 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3560 mb
->method
->save_lmf
= 1;
3563 * In AOT mode and embedding scenarios, it is possible that the icall is not
3564 * registered in the runtime doing the AOT compilation.
3566 if (!piinfo
->addr
&& !aot
) {
3567 /* if there's no code but the error isn't set, just use a fairly generic exception. */
3568 if (is_ok (emitted_error
))
3569 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "");
3570 get_marshal_cb ()->mb_emit_exception_for_error (mb
, emitted_error
);
3571 mono_error_cleanup (emitted_error
);
3573 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3574 info
->d
.managed_to_native
.method
= method
;
3576 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3578 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3579 csig
->param_count
+ 16, info
, NULL
);
3585 g_assert (is_ok (emitted_error
));
3587 /* internal calls: we simply push all arguments and call the method (no conversions) */
3588 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
3590 csig
= mono_metadata_signature_dup_add_this (get_method_image (method
), sig
, method
->klass
);
3592 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3594 //printf ("%s\n", mono_method_full_name (method, 1));
3596 /* hack - string constructors returns a value */
3597 if (method
->string_ctor
)
3598 csig
->ret
= string_type
;
3600 get_marshal_cb ()->emit_native_icall_wrapper (mb
, method
, csig
, check_exceptions
, aot
, piinfo
);
3602 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3603 info
->d
.managed_to_native
.method
= method
;
3605 csig
= mono_metadata_signature_dup_full (get_method_image (method
), csig
);
3607 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3616 g_assert (piinfo
->addr
);
3618 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3619 mono_marshal_set_callconv_from_modopt (method
, csig
, FALSE
);
3621 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
3622 mono_method_get_marshal_info (method
, mspecs
);
3624 mono_marshal_emit_native_wrapper (get_method_image (mb
->method
), mb
, csig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
);
3625 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
3626 info
->d
.managed_to_native
.method
= method
;
3629 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3633 for (i
= sig
->param_count
; i
>= 0; i
--)
3635 mono_metadata_free_marshal_spec (mspecs
[i
]);
3638 /* mono_method_print_code (res); */
3644 * mono_marshal_get_native_func_wrapper:
3645 * \param image The image to use for memory allocation and for looking up custom marshallers.
3646 * \param sig The signature of the function
3647 * \param func The native function to wrap
3649 * \returns a wrapper method around native functions, similar to the pinvoke
3653 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
3654 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
3656 MonoMethodSignature
*csig
;
3658 SignaturePointerPair key
, *new_key
;
3659 MonoMethodBuilder
*mb
;
3668 // Generic types are not safe to place in MonoImage caches.
3669 g_assert (!sig
->is_inflated
);
3671 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
3672 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
3675 name
= g_strdup_printf ("wrapper_native_%p", func
);
3676 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3677 mb
->method
->save_lmf
= 1;
3679 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
);
3681 csig
= mono_metadata_signature_dup_full (image
, sig
);
3684 new_key
= g_new (SignaturePointerPair
,1);
3685 new_key
->sig
= csig
;
3686 new_key
->pointer
= func
;
3688 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
3694 mono_marshal_set_wrapper_info (res
, NULL
);
3700 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
3704 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
3706 MonoMethodSignature
*sig
, *csig
;
3707 MonoMethodBuilder
*mb
;
3712 MonoMethodPInvoke mpiinfo
;
3713 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
3714 MonoMarshalSpec
**mspecs
;
3715 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
3716 MonoImage
*image
= get_method_image (invoke
);
3719 // FIXME: include UnmanagedFunctionPointerAttribute info
3722 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
3724 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
3726 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
3729 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
3730 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
3732 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3733 mono_method_get_marshal_info (invoke
, mspecs
);
3734 /* Freed below so don't alloc from mempool */
3735 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
3738 name
= g_strdup_printf ("wrapper_aot_native");
3739 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3740 mb
->method
->save_lmf
= 1;
3742 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
);
3744 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
3745 info
->d
.managed_to_native
.method
= invoke
;
3747 g_assert (!sig
->hasthis
);
3748 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
3750 res
= mono_mb_create_and_cache_full (cache
, invoke
,
3751 mb
, csig
, csig
->param_count
+ 16,
3755 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3757 mono_metadata_free_marshal_spec (mspecs
[i
]);
3765 * mono_marshal_emit_managed_wrapper:
3767 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
3768 * the delegate which wraps the managed method to be called. For closed delegates,
3769 * it could have fewer parameters than the method it wraps.
3770 * THIS_LOC is the memory location where the target of the delegate is stored.
3773 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3775 get_marshal_cb ()->emit_managed_wrapper (mb
, invoke_sig
, mspecs
, m
, method
, target_handle
);
3778 #ifndef ENABLE_ILGEN
3780 emit_managed_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3782 MonoMethodSignature
*sig
, *csig
;
3784 MonoType
*int_type
= mono_get_int_type ();
3789 /* we first do all conversions */
3790 for (i
= 0; i
< sig
->param_count
; i
++) {
3791 MonoType
*t
= sig
->params
[i
];
3794 case MONO_TYPE_OBJECT
:
3795 case MONO_TYPE_CLASS
:
3796 case MONO_TYPE_VALUETYPE
:
3797 case MONO_TYPE_ARRAY
:
3798 case MONO_TYPE_SZARRAY
:
3799 case MONO_TYPE_STRING
:
3800 case MONO_TYPE_BOOLEAN
:
3801 mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
3805 if (!sig
->ret
->byref
) {
3806 switch (sig
->ret
->type
) {
3807 case MONO_TYPE_STRING
:
3808 csig
->ret
= int_type
;
3818 * mono_marshal_get_managed_wrapper:
3819 * Generates IL code to call managed methods from unmanaged code
3820 * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
3823 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
, MonoError
*error
)
3825 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
3826 MonoMethodBuilder
*mb
;
3827 MonoMethod
*res
, *invoke
;
3828 MonoMarshalSpec
**mspecs
;
3829 MonoMethodPInvoke piinfo
;
3832 EmitMarshalContext m
;
3834 g_assert (method
!= NULL
);
3837 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3838 mono_error_set_invalid_program (error
, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method
, TRUE
));
3843 * FIXME: Should cache the method+delegate type pair, since the same method
3844 * could be called with different delegates, thus different marshalling
3847 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
3849 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
3852 invoke
= mono_get_delegate_invoke_internal (delegate_klass
);
3853 invoke_sig
= mono_method_signature_internal (invoke
);
3855 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3856 mono_method_get_marshal_info (invoke
, mspecs
);
3858 sig
= mono_method_signature_internal (method
);
3860 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3862 /*the target gchandle must be the first entry after size and the wrapper itself.*/
3863 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
3865 /* we copy the signature, so that we can modify it */
3867 /* Need to free this later */
3868 csig
= mono_metadata_signature_dup (invoke_sig
);
3870 csig
= mono_metadata_signature_dup_full (get_method_image (method
), invoke_sig
);
3874 memset (&m
, 0, sizeof (m
));
3880 m
.image
= get_method_image (method
);
3882 mono_marshal_set_callconv_from_modopt (invoke
, csig
, TRUE
);
3884 /* The attribute is only available in Net 2.0 */
3885 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
3886 MonoCustomAttrInfo
*cinfo
;
3887 MonoCustomAttrEntry
*attr
;
3890 * The pinvoke attributes are stored in a real custom attribute. Obtain the
3891 * contents of the attribute without constructing it, as that might not be
3892 * possible when running in cross-compiling mode.
3894 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, error
);
3895 mono_error_assert_ok (error
);
3898 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3899 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3900 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
3901 attr
= &cinfo
->attrs
[i
];
3907 gpointer
*typed_args
, *named_args
;
3908 CattrNamedArg
*arginfo
;
3911 MonoBoolean set_last_error
= 0;
3915 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
3916 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
3917 g_assert (is_ok (error
));
3920 call_conv
= *(gint32
*)typed_args
[0];
3922 for (i
= 0; i
< num_named_args
; ++i
) {
3923 CattrNamedArg
*narg
= &arginfo
[i
];
3925 g_assert (narg
->field
);
3926 if (!strcmp (narg
->field
->name
, "CharSet")) {
3927 charset
= *(gint32
*)named_args
[i
];
3928 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
3929 set_last_error
= *(MonoBoolean
*)named_args
[i
];
3930 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
3931 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox_internal (o);
3932 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
3933 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox_internal (o);
3935 g_assert_not_reached ();
3937 g_free (named_args
[i
]);
3939 g_free (typed_args
[0]);
3940 g_free (typed_args
);
3941 g_free (named_args
);
3944 memset (&piinfo
, 0, sizeof (piinfo
));
3946 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
3948 csig
->call_convention
= call_conv
- 1;
3951 if (cinfo
&& !cinfo
->cached
)
3952 mono_custom_attrs_free (cinfo
);
3955 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
3957 if (!target_handle
) {
3960 // FIXME: Associate it with the method+delegate_klass pair
3961 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3962 info
->d
.native_to_managed
.method
= method
;
3963 info
->d
.native_to_managed
.klass
= delegate_klass
;
3965 res
= mono_mb_create_and_cache_full (cache
, method
,
3966 mb
, csig
, sig
->param_count
+ 16,
3969 get_marshal_cb ()->mb_set_dynamic (mb
);
3970 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
3974 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3976 mono_metadata_free_marshal_spec (mspecs
[i
]);
3979 /* mono_method_print_code (res); */
3984 #ifndef ENABLE_ILGEN
3986 emit_vtfixup_ftnptr_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
3992 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
3996 MonoMethodSignature
*sig
;
3997 MonoMethodBuilder
*mb
;
4002 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, error
);
4004 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (error
));
4007 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
4008 MonoMethodSignature
*csig
;
4009 MonoMarshalSpec
**mspecs
;
4010 EmitMarshalContext m
;
4012 sig
= mono_method_signature_internal (method
);
4013 g_assert (!sig
->hasthis
);
4015 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
4016 mono_method_get_marshal_info (method
, mspecs
);
4018 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
4019 csig
= mono_metadata_signature_dup_full (image
, sig
);
4023 memset (&m
, 0, sizeof (m
));
4031 mono_marshal_set_callconv_from_modopt (method
, csig
, TRUE
);
4033 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
4035 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
4037 get_marshal_cb ()->mb_set_dynamic (mb
);
4038 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
4041 for (i
= sig
->param_count
; i
>= 0; i
--)
4043 mono_metadata_free_marshal_spec (mspecs
[i
]);
4046 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4047 mono_error_assert_ok (error
);
4048 return compiled_ptr
;
4051 sig
= mono_method_signature_internal (method
);
4052 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4054 param_count
= sig
->param_count
+ sig
->hasthis
;
4055 get_marshal_cb ()->emit_vtfixup_ftnptr (mb
, method
, param_count
, type
);
4056 get_marshal_cb ()->mb_set_dynamic (mb
);
4058 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
4061 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4062 mono_error_assert_ok (error
);
4063 return compiled_ptr
;
4066 #ifndef ENABLE_ILGEN
4068 emit_castclass_noilgen (MonoMethodBuilder
*mb
)
4074 * mono_marshal_get_castclass_with_cache:
4075 * This does the equivalent of \c mono_object_castclass_with_cache.
4078 mono_marshal_get_castclass_with_cache (void)
4080 static MonoMethod
*cached
;
4082 MonoMethodBuilder
*mb
;
4083 MonoMethodSignature
*sig
;
4089 MonoType
*object_type
= mono_get_object_type ();
4090 MonoType
*int_type
= mono_get_int_type ();
4092 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
4093 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4094 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4095 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4096 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4097 sig
->ret
= object_type
;
4100 get_marshal_cb ()->emit_castclass (mb
);
4102 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
4103 res
= mono_mb_create (mb
, sig
, 8, info
);
4106 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4107 mono_free_method (res
);
4108 mono_metadata_free_method_signature (sig
);
4115 /* this is an icall */
4117 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
4120 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, error
);
4121 if (mono_error_set_pending_exception (error
))
4124 if (mono_object_is_transparent_proxy (obj
))
4127 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
4129 cache_update
= cache_update
| 0x1;
4131 *cache
= cache_update
;
4136 #ifndef ENABLE_ILGEN
4138 emit_isinst_noilgen (MonoMethodBuilder
*mb
)
4144 * mono_marshal_get_isinst_with_cache:
4145 * This does the equivalent of \c mono_marshal_isinst_with_cache.
4148 mono_marshal_get_isinst_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
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
4163 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4165 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4167 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4169 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4170 sig
->ret
= object_type
;
4173 get_marshal_cb ()->emit_isinst (mb
);
4175 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
4176 res
= mono_mb_create (mb
, sig
, 8, info
);
4179 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4180 mono_free_method (res
);
4181 mono_metadata_free_method_signature (sig
);
4188 #ifndef ENABLE_ILGEN
4190 emit_struct_to_ptr_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4196 * mono_marshal_get_struct_to_ptr:
4197 * \param klass \c MonoClass
4199 * Generates IL code for <code>StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)</code>
4202 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
4204 MonoMethodBuilder
*mb
;
4205 static MonoMethod
*stoptr
= NULL
;
4209 g_assert (klass
!= NULL
);
4211 mono_marshal_load_type_info (klass
);
4213 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4214 if (marshal_info
->str_to_ptr
)
4215 return marshal_info
->str_to_ptr
;
4219 stoptr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "StructureToPtr", 3, 0, error
);
4220 mono_error_assert_ok (error
);
4224 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_OTHER
);
4226 get_marshal_cb ()->emit_struct_to_ptr (mb
, klass
);
4228 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
4229 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
4232 mono_marshal_lock ();
4233 if (!marshal_info
->str_to_ptr
)
4234 marshal_info
->str_to_ptr
= res
;
4236 res
= marshal_info
->str_to_ptr
;
4237 mono_marshal_unlock ();
4241 #ifndef ENABLE_ILGEN
4243 emit_ptr_to_struct_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4249 * mono_marshal_get_ptr_to_struct:
4250 * \param klass \c MonoClass
4251 * Generates IL code for <code>PtrToStructure (IntPtr src, object structure)</code>
4254 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
4256 MonoMethodBuilder
*mb
;
4257 static MonoMethodSignature
*ptostr
= NULL
;
4261 g_assert (klass
!= NULL
);
4263 mono_marshal_load_type_info (klass
);
4265 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4266 if (marshal_info
->ptr_to_str
)
4267 return marshal_info
->ptr_to_str
;
4270 MonoMethodSignature
*sig
;
4272 /* Create the signature corresponding to
4273 static void PtrToStructure (IntPtr ptr, object structure);
4274 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
4275 sig
= mono_icall_sig_void_ptr_object
;
4276 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4278 mono_memory_barrier ();
4282 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_OTHER
);
4284 get_marshal_cb ()->emit_ptr_to_struct (mb
, klass
);
4286 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
4287 res
= mono_mb_create (mb
, ptostr
, 0, info
);
4290 mono_marshal_lock ();
4291 if (!marshal_info
->ptr_to_str
)
4292 marshal_info
->ptr_to_str
= res
;
4294 res
= marshal_info
->ptr_to_str
;
4295 mono_marshal_unlock ();
4300 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
4301 * This is used to avoid infinite recursion since it is hard to determine where to
4302 * replace a method with its synchronized wrapper, and where not.
4303 * The runtime should execute METHOD instead of the wrapper.
4306 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
4308 MonoMethodBuilder
*mb
;
4310 MonoMethodSignature
*sig
;
4312 MonoGenericContext
*ctx
= NULL
;
4313 MonoGenericContainer
*container
= NULL
;
4315 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4316 ctx
= &((MonoMethodInflated
*)method
)->context
;
4317 method
= ((MonoMethodInflated
*)method
)->declaring
;
4318 container
= mono_method_get_generic_container (method
);
4320 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4321 g_assert (container
);
4324 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4325 get_marshal_cb ()->mb_emit_exception (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
4326 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4328 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4330 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
4331 info
->d
.synchronized_inner
.method
= method
;
4332 res
= mono_mb_create (mb
, sig
, 0, info
);
4336 res
= mono_class_inflate_generic_method_checked (res
, ctx
, error
);
4337 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4342 #ifndef ENABLE_ILGEN
4344 emit_synchronized_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4346 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4347 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4348 mono_class_set_type_load_failure (method
->klass
, "");
4356 * mono_marshal_get_synchronized_wrapper:
4357 * Generates IL code for the synchronized wrapper: the generated method
4358 * calls \p method while locking \c this or the parent type.
4361 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
4363 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
4364 MonoMethodSignature
*sig
;
4365 MonoMethodBuilder
*mb
;
4369 MonoGenericContext
*ctx
= NULL
;
4370 MonoMethod
*orig_method
= NULL
;
4371 MonoGenericContainer
*container
= NULL
;
4375 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
4378 /* FIXME: Support generic methods too */
4379 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4380 orig_method
= method
;
4381 ctx
= &((MonoMethodInflated
*)method
)->context
;
4382 method
= ((MonoMethodInflated
*)method
)->declaring
;
4383 container
= mono_method_get_generic_container (method
);
4385 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4386 g_assert (container
);
4393 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4394 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
4398 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4399 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4403 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4406 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
4408 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4409 info
->d
.synchronized
.method
= method
;
4411 mono_marshal_lock ();
4413 if (!enter_method
) {
4414 MonoMethodDesc
*desc
;
4416 desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
4417 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4418 g_assert (enter_method
);
4419 mono_method_desc_free (desc
);
4421 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
4422 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4423 g_assert (exit_method
);
4424 mono_method_desc_free (desc
);
4426 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
4427 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
4428 g_assert (gettypefromhandle_method
);
4429 mono_method_desc_free (desc
);
4432 mono_marshal_unlock ();
4434 get_marshal_cb ()->mb_skip_visibility (mb
);
4435 get_marshal_cb ()->emit_synchronized_wrapper (mb
, method
, ctx
, container
, enter_method
, exit_method
, gettypefromhandle_method
);
4439 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4440 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4442 res
= mono_mb_create_and_cache_full (cache
, method
,
4443 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4450 #ifndef ENABLE_ILGEN
4452 emit_unbox_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4458 * mono_marshal_get_unbox_wrapper:
4459 * The returned method calls \p method unboxing the \c this argument.
4462 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
4464 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4465 MonoMethodBuilder
*mb
;
4470 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4472 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4475 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
4477 g_assert (sig
->hasthis
);
4479 get_marshal_cb ()->emit_unbox_wrapper (mb
, method
);
4481 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4482 info
->d
.unbox
.method
= method
;
4484 res
= mono_mb_create_and_cache_full (cache
, method
,
4485 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4488 /* mono_method_print_code (res); */
4494 is_monomorphic_array (MonoClass
*klass
)
4496 MonoClass
*element_class
;
4497 if (m_class_get_rank (klass
) != 1)
4500 element_class
= m_class_get_element_class (klass
);
4501 return mono_class_is_sealed (element_class
) || m_class_is_valuetype (element_class
);
4504 static MonoStelemrefKind
4505 get_virtual_stelemref_kind (MonoClass
*element_class
)
4507 if (element_class
== mono_defaults
.object_class
)
4508 return STELEMREF_OBJECT
;
4509 if (is_monomorphic_array (element_class
))
4510 return STELEMREF_SEALED_CLASS
;
4512 /* magic ifaces requires aditional checks for when the element type is an array */
4513 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && m_class_is_array_special_interface (element_class
))
4514 return STELEMREF_COMPLEX
;
4516 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
4517 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && !mono_class_has_variant_generic_params (element_class
))
4518 #ifdef COMPRESSED_INTERFACE_BITMAP
4519 return STELEMREF_COMPLEX
;
4521 return STELEMREF_INTERFACE
;
4523 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
4524 if (mono_class_is_marshalbyref (element_class
) || m_class_get_rank (element_class
) || mono_class_has_variant_generic_params (element_class
))
4525 return STELEMREF_COMPLEX
;
4526 if (mono_class_is_sealed (element_class
))
4527 return STELEMREF_SEALED_CLASS
;
4528 if (m_class_get_idepth (element_class
) <= MONO_DEFAULT_SUPERTABLE_SIZE
)
4529 return STELEMREF_CLASS_SMALL_IDEPTH
;
4531 return STELEMREF_CLASS
;
4536 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
4538 char *name
= mono_type_get_full_name (m_class_element_class (mono_object_class (array
)));
4539 printf ("slow vstore of %s\n", name
);
4544 #ifndef ENABLE_ILGEN
4546 emit_virtual_stelemref_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
4551 static const char *strelemref_wrapper_name
[] = {
4552 "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
4555 static const gchar
*
4556 mono_marshal_get_strelemref_wrapper_name (MonoStelemrefKind kind
)
4558 return strelemref_wrapper_name
[kind
];
4563 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
4564 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
4565 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
4566 * - Add a case for arrays of arrays.
4569 get_virtual_stelemref_wrapper (MonoStelemrefKind kind
)
4571 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
4572 static MonoMethodSignature
*signature
;
4573 MonoMethodBuilder
*mb
;
4576 const char *param_names
[16];
4579 if (cached_methods
[kind
])
4580 return cached_methods
[kind
];
4582 MonoType
*void_type
= mono_get_void_type ();
4583 MonoType
*object_type
= mono_get_object_type ();
4584 MonoType
*int_type
= mono_get_int_type ();
4586 name
= g_strdup_printf ("virt_stelemref_%s", mono_marshal_get_strelemref_wrapper_name (kind
));
4587 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
4591 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
4593 /* void this::stelemref (size_t idx, void* value) */
4594 sig
->ret
= void_type
;
4595 sig
->hasthis
= TRUE
;
4596 sig
->params
[0] = int_type
; /* this is a natural sized int */
4597 sig
->params
[1] = object_type
;
4601 param_names
[0] = "index";
4602 param_names
[1] = "value";
4603 get_marshal_cb ()->emit_virtual_stelemref (mb
, param_names
, kind
);
4605 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
4606 info
->d
.virtual_stelemref
.kind
= kind
;
4607 res
= mono_mb_create (mb
, signature
, 4, info
);
4608 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
4610 mono_marshal_lock ();
4611 if (!cached_methods
[kind
]) {
4612 cached_methods
[kind
] = res
;
4613 mono_marshal_unlock ();
4615 mono_marshal_unlock ();
4616 mono_free_method (res
);
4620 return cached_methods
[kind
];
4624 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
4626 MonoStelemrefKind kind
;
4628 g_assert (m_class_get_rank (array_class
) == 1);
4629 kind
= get_virtual_stelemref_kind (m_class_get_element_class (array_class
));
4631 return get_virtual_stelemref_wrapper (kind
);
4635 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
4640 *nwrappers
= STELEMREF_KIND_COUNT
;
4641 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
4642 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
4643 res
[i
] = get_virtual_stelemref_wrapper ((MonoStelemrefKind
)i
);
4647 #ifndef ENABLE_ILGEN
4649 emit_stelemref_noilgen (MonoMethodBuilder
*mb
)
4655 * mono_marshal_get_stelemref:
4658 mono_marshal_get_stelemref (void)
4660 static MonoMethod
* ret
= NULL
;
4661 MonoMethodSignature
*sig
;
4662 MonoMethodBuilder
*mb
;
4668 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
4671 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4673 MonoType
*void_type
= mono_get_void_type ();
4674 MonoType
*object_type
= mono_get_object_type ();
4675 MonoType
*int_type
= mono_get_int_type ();
4678 /* void stelemref (void* array, int idx, void* value) */
4679 sig
->ret
= void_type
;
4680 sig
->params
[0] = object_type
;
4681 sig
->params
[1] = int_type
; /* this is a natural sized int */
4682 sig
->params
[2] = object_type
;
4684 get_marshal_cb ()->emit_stelemref (mb
);
4686 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4687 ret
= mono_mb_create (mb
, sig
, 4, info
);
4693 #ifndef ENABLE_ILGEN
4695 mb_emit_byte_noilgen (MonoMethodBuilder
*mb
, guint8 op
)
4701 * mono_marshal_get_gsharedvt_in_wrapper:
4703 * This wrapper handles calls from normal code to gsharedvt code.
4706 mono_marshal_get_gsharedvt_in_wrapper (void)
4708 static MonoMethod
* ret
= NULL
;
4709 MonoMethodSignature
*sig
;
4710 MonoMethodBuilder
*mb
;
4716 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_OTHER
);
4718 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4719 sig
->ret
= mono_get_void_type ();
4722 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4724 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4726 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
4727 ret
= mono_mb_create (mb
, sig
, 4, info
);
4734 * mono_marshal_get_gsharedvt_out_wrapper:
4736 * This wrapper handles calls from gsharedvt code to normal code.
4739 mono_marshal_get_gsharedvt_out_wrapper (void)
4741 static MonoMethod
* ret
= NULL
;
4742 MonoMethodSignature
*sig
;
4743 MonoMethodBuilder
*mb
;
4749 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_OTHER
);
4751 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4752 sig
->ret
= mono_get_void_type ();
4755 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4757 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4759 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
4760 ret
= mono_mb_create (mb
, sig
, 4, info
);
4766 #ifndef ENABLE_ILGEN
4768 emit_array_address_noilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
4779 /* LOCKING: vars accessed under the marshal lock */
4780 static ArrayElemAddr
*elem_addr_cache
= NULL
;
4781 static int elem_addr_cache_size
= 0;
4782 static int elem_addr_cache_next
= 0;
4785 * mono_marshal_get_array_address:
4786 * \param rank rank of the array type
4787 * \param elem_size size in bytes of an element of an array.
4789 * Returns a MonoMethod that implements the code to get the address
4790 * of an element in a multi-dimenasional array of \p rank dimensions.
4791 * The returned method takes an array as the first argument and then
4792 * \p rank indexes for the \p rank dimensions.
4793 * If ELEM_SIZE is 0, read the array size from the array object.
4796 mono_marshal_get_array_address (int rank
, int elem_size
)
4799 MonoMethodBuilder
*mb
;
4800 MonoMethodSignature
*sig
;
4806 mono_marshal_lock ();
4807 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4808 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4809 ret
= elem_addr_cache
[i
].method
;
4813 mono_marshal_unlock ();
4817 MonoType
*object_type
= mono_get_object_type ();
4818 MonoType
*int_type
= mono_get_int_type ();
4819 MonoType
*int32_type
= mono_get_int32_type ();
4821 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
4823 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
4824 sig
->ret
= int_type
;
4825 sig
->params
[0] = object_type
;
4826 for (int i
= 0; i
< rank
; ++i
) {
4827 sig
->params
[i
+ 1] = int32_type
;
4830 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
4831 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4834 get_marshal_cb ()->emit_array_address (mb
, rank
, elem_size
);
4836 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
4837 info
->d
.element_addr
.rank
= rank
;
4838 info
->d
.element_addr
.elem_size
= elem_size
;
4839 ret
= mono_mb_create (mb
, sig
, 4, info
);
4842 /* cache the result */
4844 mono_marshal_lock ();
4845 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4846 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4847 /* FIXME: free ret */
4848 ret
= elem_addr_cache
[i
].method
;
4854 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
4855 int new_size
= elem_addr_cache_size
+ 4;
4856 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
4857 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
4858 g_free (elem_addr_cache
);
4859 elem_addr_cache
= new_array
;
4860 elem_addr_cache_size
= new_size
;
4862 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
4863 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
4864 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
4865 elem_addr_cache_next
++;
4867 mono_marshal_unlock ();
4871 #ifndef ENABLE_ILGEN
4873 emit_array_accessor_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4879 * mono_marshal_get_array_accessor_wrapper:
4881 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
4884 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
4886 MonoMethodSignature
*sig
;
4887 MonoMethodBuilder
*mb
;
4890 MonoGenericContext
*ctx
= NULL
;
4891 MonoMethod
*orig_method
= NULL
;
4895 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
4896 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
4897 * FIXME: Use generic methods.
4904 g_assert_not_reached ();
4906 cache
= get_cache (&get_method_image (method
)->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
4907 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4911 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4914 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4916 get_marshal_cb ()->emit_array_accessor_wrapper (mb
, method
, sig
, ctx
);
4918 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
4919 info
->d
.array_accessor
.method
= method
;
4923 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4924 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4926 res
= mono_mb_create_and_cache_full (cache
, method
,
4927 mb
, sig
, sig
->param_count
+ 16,
4937 mono_marshal_alloc_co_task_mem (size_t size
)
4940 /* This returns a valid pointer for size 0 on MS.NET */
4943 return g_try_malloc (size
);
4948 * mono_marshal_alloc:
4951 mono_marshal_alloc (gsize size
, MonoError
*error
)
4957 res
= mono_marshal_alloc_co_task_mem (size
);
4959 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
" bytes", size
);
4964 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
4966 ves_icall_marshal_alloc_impl (gsize size
, MonoError
*error
)
4968 return mono_marshal_alloc (size
, error
);
4973 mono_marshal_free_co_task_mem (void *ptr
)
4980 * mono_marshal_free:
4983 mono_marshal_free (gpointer ptr
)
4985 mono_marshal_free_co_task_mem (ptr
);
4989 * mono_marshal_free_array:
4992 mono_marshal_free_array (gpointer
*ptr
, int size
)
4999 for (i
= 0; i
< size
; i
++)
5004 mono_marshal_string_to_utf16 (MonoString
*s
)
5006 // FIXME This should be an intrinsic.
5007 // FIXMEcoop The input parameter is easy to deal with,
5008 // but what happens with the result?
5009 // See https://github.com/mono/mono/issues/12165.
5010 return s
? mono_string_chars_internal (s
) : NULL
;
5013 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
5015 mono_marshal_string_to_utf16_copy_impl (MonoStringHandle s
, MonoError
*error
)
5017 if (MONO_HANDLE_IS_NULL (s
))
5020 gsize
const length
= mono_string_handle_length (s
);
5021 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((length
+ 1) * sizeof (*res
), error
);
5022 return_val_if_nok (error
, NULL
);
5023 gchandle_t gchandle
= 0;
5024 memcpy (res
, mono_string_handle_pin_chars (s
, &gchandle
), length
* sizeof (*res
));
5025 mono_gchandle_free_internal (gchandle
);
5031 * mono_marshal_set_last_error:
5033 * This function is invoked to set the last error value from a P/Invoke call
5034 * which has \c SetLastError set.
5037 mono_marshal_set_last_error (void)
5039 /* This icall is called just after a P/Invoke call before the P/Invoke
5040 * wrapper transitions the runtime back to running mode. */
5042 MONO_REQ_GC_SAFE_MODE
;
5043 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
5045 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
5050 mono_marshal_set_last_error_windows (int error
)
5053 /* This icall is called just after a P/Invoke call before the P/Invoke
5054 * wrapper transitions the runtime back to running mode. */
5055 MONO_REQ_GC_SAFE_MODE
;
5056 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
5061 mono_marshal_clear_last_error (void)
5063 /* This icall is called just before a P/Invoke call. */
5065 SetLastError (ERROR_SUCCESS
);
5072 copy_managed_common (MonoArrayHandle managed
, gconstpointer native
, gint32 start_index
,
5073 gint32 length
, gpointer
*managed_addr
, guint32
*gchandle
, MonoError
*error
)
5075 MONO_CHECK_ARG_NULL_HANDLE (managed
, 0);
5076 MONO_CHECK_ARG_NULL (native
, 0);
5078 MonoClass
*klass
= mono_handle_class (managed
);
5080 // FIXME? move checks to managed
5081 if (m_class_get_rank (klass
) != 1) {
5082 mono_error_set_argument (error
, "array", "array is multi-dimensional");
5085 if (start_index
< 0) {
5086 mono_error_set_argument (error
, "startIndex", "Must be >= 0");
5090 mono_error_set_argument (error
, "length", "Must be >= 0");
5093 if (start_index
+ length
> mono_array_handle_length (managed
)) {
5094 mono_error_set_argument (error
, "length", "start_index + length > array length");
5098 gsize
const element_size
= mono_array_element_size (klass
);
5100 // Handle generic arrays, which do not allow fixed.
5102 *managed_addr
= mono_array_handle_pin_with_size (managed
, element_size
, start_index
, gchandle
);
5104 return element_size
* length
;
5108 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArrayHandle src
, gint32 start_index
,
5109 gpointer dest
, gint32 length
, gconstpointer managed_source_addr
, MonoError
*error
)
5111 guint32 gchandle
= 0;
5112 gsize
const bytes
= copy_managed_common (src
, dest
, start_index
, length
, (gpointer
*)&managed_source_addr
, &gchandle
, error
);
5114 memmove (dest
, managed_source_addr
, bytes
); // no references should be involved
5115 mono_gchandle_free_internal (gchandle
);
5119 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gconstpointer src
, gint32 start_index
,
5120 MonoArrayHandle dest
, gint32 length
, gpointer managed_dest_addr
, MonoError
*error
)
5122 guint32 gchandle
= 0;
5123 gsize
const bytes
= copy_managed_common (dest
, src
, start_index
, length
, &managed_dest_addr
, &gchandle
, error
);
5125 memmove (managed_dest_addr
, src
, bytes
); // no references should be involved
5126 mono_gchandle_free_internal (gchandle
);
5130 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (const char *ptr
, MonoError
*error
)
5133 return NULL_HANDLE_STRING
;
5134 return mono_string_new_handle (mono_domain_get (), ptr
, error
);
5138 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (const char *ptr
, gint32 len
, MonoError
*error
)
5141 mono_error_set_argument_null (error
, "ptr", "");
5142 return NULL_HANDLE_STRING
;
5144 return mono_string_new_utf8_len (mono_domain_get (), ptr
, len
, error
);
5148 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (const gunichar2
*ptr
, MonoError
*error
)
5151 const gunichar2
*t
= ptr
;
5154 return NULL_HANDLE_STRING
;
5159 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5160 return_val_if_nok (error
, NULL_HANDLE_STRING
);
5166 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (const gunichar2
*ptr
, gint32 len
, MonoError
*error
)
5169 mono_error_set_argument_null (error
, "ptr", "");
5170 return NULL_HANDLE_STRING
;
5172 return mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5176 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5178 return GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
));
5182 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype
, MonoError
*error
)
5184 if (MONO_HANDLE_IS_NULL (rtype
)) {
5185 mono_error_set_argument_null (error
, "type", "");
5189 MonoType
* const type
= MONO_HANDLE_GETVAL (rtype
, type
);
5190 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
5191 if (!mono_class_init_checked (klass
, error
))
5194 guint32
const layout
= (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
);
5196 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
5197 return sizeof (gpointer
);
5198 } else if (type
->type
== MONO_TYPE_VOID
) {
5200 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5201 mono_error_set_argument_format (error
, "t", "Type %s cannot be marshaled as an unmanaged structure.", m_class_get_name (klass
));
5206 return (guint32
)mono_marshal_type_size (type
, NULL
, &align
, FALSE
, m_class_is_unicode (klass
));
5210 ves_icall_System_Runtime_InteropServices_Marshal_SizeOfHelper (MonoReflectionTypeHandle rtype
, MonoBoolean throwIfNotMarshalable
, MonoError
*error
)
5212 return ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (rtype
, error
);
5216 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObjectHandle obj
, gpointer dst
, MonoBoolean delete_old
, MonoError
*error
)
5218 MONO_CHECK_ARG_NULL_HANDLE_NAMED (obj
, "structure",);
5219 MONO_CHECK_ARG_NULL_NAMED (dst
, "ptr",);
5221 #ifdef ENABLE_NETCORE
5222 MonoClass
*klass
= mono_handle_class (obj
);
5223 if (m_class_is_auto_layout (klass
)) {
5224 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5227 if (m_class_is_ginst (klass
)) {
5228 mono_error_set_argument (error
, "structure", "The specified object must not be an instance of a generic type.");
5233 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (obj
));
5235 gpointer pa
[ ] = { MONO_HANDLE_RAW (obj
), &dst
, &delete_old
};
5237 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
5241 ptr_to_structure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5243 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (dst
));
5245 gpointer pa
[ ] = { &src
, MONO_HANDLE_RAW (dst
) };
5247 // FIXMEcoop? mono_runtime_invoke_handle causes a GC assertion failure in marshal2 with interpreter
5248 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5251 #ifdef ENABLE_NETCORE
5254 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructureInternal (gconstpointer src
, MonoObjectHandle dst
, MonoBoolean allow_vtypes
, MonoError
*error
)
5259 t
= m_class_get_byval_arg (mono_handle_class (dst
));
5260 if (!allow_vtypes
&& MONO_TYPE_ISSTRUCT (t
)) {
5261 mono_error_set_argument (error
, "structure", "The structure must not be a value class.");
5265 klass
= mono_class_from_mono_type_internal (t
);
5266 if (m_class_is_auto_layout (klass
)) {
5267 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5271 ptr_to_structure (src
, dst
, error
);
5277 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5281 MONO_CHECK_ARG_NULL (src
,);
5282 MONO_CHECK_ARG_NULL_HANDLE (dst
,);
5284 t
= mono_type_get_underlying_type (m_class_get_byval_arg (mono_handle_class (dst
)));
5286 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5287 mono_error_set_argument (error
, "dst", "Destination is a boxed value type.");
5291 ptr_to_structure (src
, dst
, error
);
5295 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gconstpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5300 MONO_CHECK_ARG_NULL_HANDLE (type
, NULL_HANDLE
);
5302 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5303 if (!mono_class_init_checked (klass
, error
))
5306 MonoObjectHandle res
= mono_object_new_handle (mono_domain_get (), klass
, error
);
5307 return_val_if_nok (error
, NULL_HANDLE
);
5309 ptr_to_structure (src
, res
, error
);
5310 return_val_if_nok (error
, NULL_HANDLE
);
5317 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type
, MonoStringHandle field_name
, MonoError
*error
)
5320 if (MONO_HANDLE_IS_NULL (ref_type
)) {
5321 mono_error_set_argument_null (error
, "t", "");
5324 if (MONO_HANDLE_IS_NULL (field_name
)) {
5325 #ifdef ENABLE_NETCORE
5326 mono_error_set_argument_null (error
, NULL
, "");
5328 mono_error_set_argument_null (error
, "fieldName", "");
5333 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (ref_type
))) {
5334 #ifdef ENABLE_NETCORE
5335 mono_error_set_argument (error
, "fieldName", "");
5337 mono_error_set_argument (error
, "type", "");
5342 char *fname
= mono_string_handle_to_utf8 (field_name
, error
);
5343 return_val_if_nok (error
, 0);
5345 MonoType
*type
= MONO_HANDLE_GETVAL (ref_type
, type
);
5346 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
5347 if (!mono_class_init_checked (klass
, error
))
5349 #ifdef ENABLE_NETCORE
5350 if (m_class_is_auto_layout (klass
)) {
5351 mono_error_set_argument (error
, NULL
, "");
5355 int match_index
= -1;
5356 while (klass
&& match_index
== -1) {
5357 MonoClassField
* field
;
5359 gpointer iter
= NULL
;
5360 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5361 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5363 if (!strcmp (fname
, mono_field_get_name (field
))) {
5370 if (match_index
== -1)
5371 klass
= m_class_get_parent (klass
);
5376 if(match_index
== -1) {
5377 /* Get back original class instance */
5378 klass
= mono_class_from_mono_type_internal (type
);
5380 mono_error_set_argument_format (error
, "fieldName", "Field passed in is not a marshaled member of the type %s", m_class_get_name (klass
));
5384 MonoMarshalType
*info
= mono_marshal_load_type_info (klass
);
5385 return info
->fields
[match_index
].offset
;
5390 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2
*s
, int length
, MonoError
*error
)
5392 return mono_utf16_to_utf8 (s
, length
, error
);
5396 mono_marshal_alloc_hglobal (size_t size
, MonoError
*error
)
5398 void* p
= g_try_malloc (size
);
5400 mono_error_set_out_of_memory (error
, "");
5403 #endif /* !HOST_WIN32 */
5406 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2
*s
, int length
, MonoError
*error
)
5411 gsize
const len
= ((gsize
)length
+ 1) * 2;
5412 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc_hglobal (len
, error
);
5414 memcpy (res
, s
, length
* 2);
5421 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
5423 MonoMarshalType
*info
;
5426 info
= mono_marshal_load_type_info (klass
);
5428 for (i
= 0; i
< info
->num_fields
; i
++) {
5429 MonoMarshalConv conv
;
5430 MonoType
*ftype
= info
->fields
[i
].field
->type
;
5433 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5436 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
5437 m_class_is_unicode (klass
), &conv
);
5439 cpos
= ptr
+ info
->fields
[i
].offset
;
5442 case MONO_MARSHAL_CONV_NONE
:
5443 if (MONO_TYPE_ISSTRUCT (ftype
)) {
5444 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
5448 case MONO_MARSHAL_CONV_STR_LPWSTR
:
5449 /* We assume this field points inside a MonoString */
5451 case MONO_MARSHAL_CONV_STR_LPTSTR
:
5453 /* We assume this field points inside a MonoString
5457 case MONO_MARSHAL_CONV_STR_LPSTR
:
5458 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
5459 case MONO_MARSHAL_CONV_STR_TBSTR
:
5460 case MONO_MARSHAL_CONV_STR_UTF8STR
:
5461 mono_marshal_free (*(gpointer
*)cpos
);
5463 case MONO_MARSHAL_CONV_STR_BSTR
:
5464 mono_free_bstr (*(gpointer
*)cpos
);
5473 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5475 MONO_CHECK_ARG_NULL_NAMED (src
, "ptr",);
5476 MONO_CHECK_ARG_NULL_HANDLE_NAMED (type
, "structureType",);
5478 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (type
))) {
5479 mono_error_set_argument (error
, "structureType", "");
5483 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5484 if (!mono_class_init_checked (klass
, error
))
5486 #ifdef ENABLE_NETCORE
5487 if (m_class_is_auto_layout (klass
)) {
5488 mono_error_set_argument (error
, "structureType", "The specified structure must be blittable or have layout information.");
5494 mono_struct_delete_old (klass
, (char *)src
);
5498 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gsize size
, MonoError
*error
)
5501 /* This returns a valid pointer for size 0 on MS.NET */
5504 return mono_marshal_alloc_hglobal (size
, error
);
5509 mono_marshal_realloc_hglobal (gpointer ptr
, size_t size
)
5511 return g_try_realloc (ptr
, size
);
5516 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gsize size
, MonoError
*error
)
5519 mono_error_set_out_of_memory (error
, "");
5523 gpointer
const res
= mono_marshal_realloc_hglobal (ptr
, size
);
5526 mono_error_set_out_of_memory (error
, "");
5533 mono_marshal_free_hglobal (gpointer ptr
)
5540 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
5542 mono_marshal_free_hglobal (ptr
);
5546 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
, MonoError
*error
)
5548 void *res
= mono_marshal_alloc_co_task_mem (size
);
5551 mono_error_set_out_of_memory (error
, "");
5557 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gsize size
, MonoError
*error
)
5559 void *res
= mono_marshal_alloc_co_task_mem (size
);
5562 mono_error_set_out_of_memory (error
, "");
5568 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
5570 mono_marshal_free_co_task_mem (ptr
);
5575 mono_marshal_realloc_co_task_mem (gpointer ptr
, size_t size
)
5577 return g_try_realloc (ptr
, size
);
5582 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
, MonoError
*error
)
5584 void *res
= mono_marshal_realloc_co_task_mem (ptr
, size
);
5587 mono_error_set_out_of_memory (error
, "");
5593 #ifndef ENABLE_NETCORE
5595 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArrayHandle arrayobj
, int index
, MonoError
*error
)
5597 int esize
= mono_array_element_size (mono_handle_class (arrayobj
));
5598 return mono_array_addr_with_size_fast (MONO_HANDLE_RAW (arrayobj
), esize
, index
);
5603 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionTypeHandle type
, MonoError
*error
)
5605 MonoClass
*klass
= mono_type_get_class (MONO_HANDLE_GETVAL (type
, type
));
5606 if (!mono_class_init_checked (klass
, error
))
5607 return MONO_HANDLE_CAST (MonoDelegate
, NULL_HANDLE
);
5609 return mono_ftnptr_to_delegate_impl (klass
, ftn
, error
);
5613 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate
, MonoError
*error
)
5615 return mono_delegate_to_ftnptr_impl (delegate
, error
);
5619 ves_icall_System_Runtime_InteropServices_Marshal_GetArrayElementSize (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5621 MonoClass
*eklass
= mono_type_get_class (MONO_HANDLE_GETVAL (type_h
, type
));
5623 mono_class_init_internal (eklass
);
5625 if (m_class_has_references (eklass
)) {
5626 mono_error_set_argument (error
, NULL
, NULL
);
5629 return mono_class_array_element_size (eklass
);
5633 ves_icall_System_Runtime_InteropServices_Marshal_IsPinnableType (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5635 MonoClass
*klass
= mono_class_from_mono_type_internal (MONO_HANDLE_GETVAL (type_h
, type
));
5637 if (m_class_get_rank (klass
)) {
5638 MonoClass
*eklass
= m_class_get_element_class (klass
);
5639 if (m_class_is_primitive (eklass
))
5641 return eklass
!= mono_defaults
.object_class
&& m_class_is_blittable (eklass
);
5643 return m_class_is_blittable (klass
);
5647 * mono_marshal_is_loading_type_info:
5649 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
5653 mono_marshal_is_loading_type_info (MonoClass
*klass
)
5655 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5657 return g_slist_find (loads_list
, klass
) != NULL
;
5661 * mono_marshal_load_type_info:
5663 * Initialize \c klass::marshal_info using information from metadata. This function can
5664 * recursively call itself, and the caller is responsible to avoid that by calling
5665 * \c mono_marshal_is_loading_type_info beforehand.
5667 * LOCKING: Acquires the loader lock.
5670 mono_marshal_load_type_info (MonoClass
* klass
)
5673 guint32 native_size
= 0, min_align
= 1, packing
;
5674 MonoMarshalType
*info
;
5675 MonoClassField
* field
;
5680 g_assert (klass
!= NULL
);
5682 info
= mono_class_get_marshal_info (klass
);
5686 if (!m_class_is_inited (klass
))
5687 mono_class_init_internal (klass
);
5689 info
= mono_class_get_marshal_info (klass
);
5694 * This function can recursively call itself, so we keep the list of classes which are
5695 * under initialization in a TLS list.
5697 g_assert (!mono_marshal_is_loading_type_info (klass
));
5698 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5699 loads_list
= g_slist_prepend (loads_list
, klass
);
5700 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5703 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5704 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5706 if (mono_field_is_deleted (field
))
5711 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
5713 info
= (MonoMarshalType
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
5714 info
->num_fields
= count
;
5716 /* Try to find a size for this type in metadata */
5717 mono_metadata_packing_from_typedef (m_class_get_image (klass
), m_class_get_type_token (klass
), NULL
, &native_size
);
5719 if (m_class_get_parent (klass
)) {
5720 int parent_size
= mono_class_native_size (m_class_get_parent (klass
), NULL
);
5722 /* Add parent size to real size */
5723 native_size
+= parent_size
;
5724 info
->native_size
= parent_size
;
5727 packing
= m_class_get_packing_size (klass
) ? m_class_get_packing_size (klass
) : 8;
5730 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5734 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5737 if (mono_field_is_deleted (field
))
5739 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
5740 mono_metadata_field_info_with_mempool (m_class_get_image (klass
), mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
5741 NULL
, NULL
, &info
->fields
[j
].mspec
);
5743 info
->fields
[j
].field
= field
;
5745 if ((mono_class_num_fields (klass
) == 1) && (m_class_get_instance_size (klass
) == MONO_ABI_SIZEOF (MonoObject
)) &&
5746 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
5747 /* This field is a hack inserted by MCS to empty structures */
5752 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
5753 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
5754 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5755 &align
, TRUE
, m_class_is_unicode (klass
));
5756 align
= m_class_get_packing_size (klass
) ? MIN (m_class_get_packing_size (klass
), align
): align
;
5757 min_align
= MAX (align
, min_align
);
5758 info
->fields
[j
].offset
= info
->native_size
;
5759 info
->fields
[j
].offset
+= align
- 1;
5760 info
->fields
[j
].offset
&= ~(align
- 1);
5761 info
->native_size
= info
->fields
[j
].offset
+ size
;
5763 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
5764 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5765 &align
, TRUE
, m_class_is_unicode (klass
));
5766 min_align
= MAX (align
, min_align
);
5767 info
->fields
[j
].offset
= field
->offset
- MONO_ABI_SIZEOF (MonoObject
);
5768 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
5774 if (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_PTR
)
5775 info
->native_size
= TARGET_SIZEOF_VOID_P
;
5777 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5778 info
->native_size
= MAX (native_size
, info
->native_size
);
5780 * If the provided Size is equal or larger than the calculated size, and there
5781 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
5783 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
5784 if (native_size
&& native_size
== info
->native_size
&& m_class_get_packing_size (klass
) == 0)
5787 min_align
= MIN (min_align
, packing
);
5791 if (info
->native_size
& (min_align
- 1)) {
5792 info
->native_size
+= min_align
- 1;
5793 info
->native_size
&= ~(min_align
- 1);
5796 info
->min_align
= min_align
;
5798 /* Update the class's blittable info, if the layouts don't match */
5799 if (info
->native_size
!= mono_class_value_size (klass
, NULL
)) {
5800 mono_class_set_nonblittable (klass
); /* FIXME - how is this justified? what if we previously thought the class was blittable? */
5803 /* If this is an array type, ensure that we have element info */
5804 if (m_class_get_rank (klass
) && !mono_marshal_is_loading_type_info (m_class_get_element_class (klass
))) {
5805 mono_marshal_load_type_info (m_class_get_element_class (klass
));
5808 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5809 loads_list
= g_slist_remove (loads_list
, klass
);
5810 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5812 mono_marshal_lock ();
5813 MonoMarshalType
*info2
= mono_class_get_marshal_info (klass
);
5815 /*We do double-checking locking on marshal_info */
5816 mono_memory_barrier ();
5817 mono_class_set_marshal_info (klass
, info
);
5818 ++class_marshal_info_count
;
5821 mono_marshal_unlock ();
5827 * mono_class_native_size:
5828 * \param klass a class
5829 * \returns the native size of an object instance (when marshaled
5830 * to unmanaged code)
5833 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
5835 MonoMarshalType
*info
= mono_class_get_marshal_info (klass
);
5837 if (mono_marshal_is_loading_type_info (klass
)) {
5842 mono_marshal_load_type_info (klass
);
5844 info
= mono_class_get_marshal_info (klass
);
5848 *align
= info
->min_align
;
5850 return info
->native_size
;
5854 * mono_type_native_stack_size:
5855 * @t: the type to return the size it uses on the stack
5857 * Returns: the number of bytes required to hold an instance of this
5858 * type on the native stack
5861 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
5865 g_assert (t
!= NULL
);
5871 *align
= TARGET_SIZEOF_VOID_P
;
5872 return TARGET_SIZEOF_VOID_P
;
5876 case MONO_TYPE_BOOLEAN
:
5877 case MONO_TYPE_CHAR
:
5888 case MONO_TYPE_STRING
:
5889 case MONO_TYPE_OBJECT
:
5890 case MONO_TYPE_CLASS
:
5891 case MONO_TYPE_SZARRAY
:
5893 case MONO_TYPE_FNPTR
:
5894 case MONO_TYPE_ARRAY
:
5895 *align
= TARGET_SIZEOF_VOID_P
;
5896 return TARGET_SIZEOF_VOID_P
;
5901 *align
= MONO_ABI_ALIGNOF (double);
5905 *align
= MONO_ABI_ALIGNOF (gint64
);
5907 case MONO_TYPE_GENERICINST
:
5908 if (!mono_type_generic_inst_is_valuetype (t
)) {
5909 *align
= TARGET_SIZEOF_VOID_P
;
5910 return TARGET_SIZEOF_VOID_P
;
5913 case MONO_TYPE_TYPEDBYREF
:
5914 case MONO_TYPE_VALUETYPE
: {
5916 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
5918 if (m_class_is_enumtype (klass
))
5919 return mono_type_native_stack_size (mono_class_enum_basetype_internal (klass
), align
);
5921 size
= mono_class_native_size (klass
, align
);
5922 *align
= *align
+ 3;
5932 g_error ("type 0x%02x unknown", t
->type
);
5938 * mono_marshal_type_size:
5941 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
5942 gboolean as_field
, gboolean unicode
)
5945 MonoMarshalNative native_type
= (MonoMarshalNative
)mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
5948 switch (native_type
) {
5949 case MONO_NATIVE_BOOLEAN
:
5952 case MONO_NATIVE_I1
:
5953 case MONO_NATIVE_U1
:
5956 case MONO_NATIVE_I2
:
5957 case MONO_NATIVE_U2
:
5958 case MONO_NATIVE_VARIANTBOOL
:
5961 case MONO_NATIVE_I4
:
5962 case MONO_NATIVE_U4
:
5963 case MONO_NATIVE_ERROR
:
5966 case MONO_NATIVE_I8
:
5967 case MONO_NATIVE_U8
:
5968 *align
= MONO_ABI_ALIGNOF (gint64
);
5970 case MONO_NATIVE_R4
:
5973 case MONO_NATIVE_R8
:
5974 *align
= MONO_ABI_ALIGNOF (double);
5976 case MONO_NATIVE_INT
:
5977 case MONO_NATIVE_UINT
:
5978 case MONO_NATIVE_LPSTR
:
5979 case MONO_NATIVE_LPWSTR
:
5980 case MONO_NATIVE_LPTSTR
:
5981 case MONO_NATIVE_BSTR
:
5982 case MONO_NATIVE_ANSIBSTR
:
5983 case MONO_NATIVE_TBSTR
:
5984 case MONO_NATIVE_UTF8STR
:
5985 case MONO_NATIVE_LPARRAY
:
5986 case MONO_NATIVE_SAFEARRAY
:
5987 case MONO_NATIVE_IUNKNOWN
:
5988 case MONO_NATIVE_IDISPATCH
:
5989 case MONO_NATIVE_INTERFACE
:
5990 case MONO_NATIVE_ASANY
:
5991 case MONO_NATIVE_FUNC
:
5992 case MONO_NATIVE_LPSTRUCT
:
5993 *align
= MONO_ABI_ALIGNOF (gpointer
);
5994 return TARGET_SIZEOF_VOID_P
;
5995 case MONO_NATIVE_STRUCT
:
5996 klass
= mono_class_from_mono_type_internal (type
);
5997 if (klass
== mono_defaults
.object_class
&&
5998 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
6002 #ifdef ENABLE_NETCORE
6003 else if (strcmp (m_class_get_name_space (klass
), "System") == 0 &&
6004 strcmp (m_class_get_name (klass
), "Decimal") == 0) {
6006 // Special case: Managed Decimal consists of 4 int32 fields, the alignment should be 8 on x64 to follow
6007 // https://github.com/dotnet/coreclr/blob/4450e5ca663b9e66c20e6f9751c941efa3716fde/src/vm/methodtablebuilder.cpp#L9753
6008 *align
= MONO_ABI_ALIGNOF (gpointer
);
6009 return mono_class_native_size (klass
, NULL
);
6012 padded_size
= mono_class_native_size (klass
, align
);
6013 if (padded_size
== 0)
6016 case MONO_NATIVE_BYVALTSTR
: {
6017 int esize
= unicode
? 2: 1;
6020 return mspec
->data
.array_data
.num_elem
* esize
;
6022 case MONO_NATIVE_BYVALARRAY
: {
6023 // FIXME: Have to consider ArraySubType
6025 klass
= mono_class_from_mono_type_internal (type
);
6026 if (m_class_get_element_class (klass
) == mono_defaults
.char_class
) {
6027 esize
= unicode
? 2 : 1;
6030 esize
= mono_class_native_size (m_class_get_element_class (klass
), align
);
6033 return mspec
->data
.array_data
.num_elem
* esize
;
6035 case MONO_NATIVE_CUSTOM
:
6036 *align
= TARGET_SIZEOF_VOID_P
;
6037 return TARGET_SIZEOF_VOID_P
;
6039 case MONO_NATIVE_CURRENCY
:
6040 case MONO_NATIVE_VBBYREFSTR
:
6042 g_error ("native type %02x not implemented", native_type
);
6045 g_assert_not_reached ();
6050 * mono_marshal_asany:
6051 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
6054 mono_marshal_asany_impl (MonoObjectHandle o
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6056 if (MONO_HANDLE_IS_NULL (o
))
6059 MonoType
*t
= m_class_get_byval_arg (mono_handle_class (o
));
6066 case MONO_TYPE_BOOLEAN
:
6069 case MONO_TYPE_CHAR
:
6074 return mono_handle_unbox_unsafe (o
);
6075 case MONO_TYPE_STRING
:
6076 switch (string_encoding
) {
6077 case MONO_NATIVE_LPWSTR
:
6078 return mono_marshal_string_to_utf16_copy_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6079 case MONO_NATIVE_LPSTR
:
6080 case MONO_NATIVE_UTF8STR
:
6081 // Same code path, because in Mono, we treated strings as Utf8
6082 return mono_string_to_utf8str_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6084 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6085 g_assert_not_reached ();
6088 case MONO_TYPE_CLASS
:
6089 case MONO_TYPE_VALUETYPE
: {
6091 MonoClass
*klass
= t
->data
.klass
;
6093 if (mono_class_is_auto_layout (klass
))
6096 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6097 return mono_handle_unbox_unsafe (o
);
6099 gpointer res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), error
);
6100 return_val_if_nok (error
, NULL
);
6102 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6103 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (o
));
6104 MonoBoolean delete_old
= FALSE
;
6105 gpointer pa
[ ] = { MONO_HANDLE_RAW (o
), &res
, &delete_old
};
6107 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
6108 return_val_if_nok (error
, NULL
);
6116 mono_error_set_argument (error
, "", "No PInvoke conversion exists for value passed to Object-typed parameter.");
6121 * mono_marshal_free_asany:
6122 * This is a JIT icall, it sets the pending exception (in wrapper)
6125 mono_marshal_free_asany_impl (MonoObjectHandle o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6130 if (MONO_HANDLE_IS_NULL (o
))
6133 t
= m_class_get_byval_arg (mono_handle_class (o
));
6135 case MONO_TYPE_STRING
:
6136 switch (string_encoding
) {
6137 case MONO_NATIVE_LPWSTR
:
6138 case MONO_NATIVE_LPSTR
:
6139 case MONO_NATIVE_UTF8STR
:
6140 mono_marshal_free (ptr
);
6143 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6144 g_assert_not_reached ();
6147 case MONO_TYPE_CLASS
:
6148 case MONO_TYPE_VALUETYPE
: {
6149 klass
= t
->data
.klass
;
6151 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6154 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
6155 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (o
));
6159 pa
[1] = MONO_HANDLE_RAW (o
);
6161 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
6166 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6167 mono_struct_delete_old (klass
, (char *)ptr
);
6170 mono_marshal_free (ptr
);
6178 #ifndef ENABLE_ILGEN
6180 emit_generic_array_helper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6186 * mono_marshal_get_generic_array_helper:
6188 * Return a wrapper which is used to implement the implicit interfaces on arrays.
6189 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
6192 mono_marshal_get_generic_array_helper (MonoClass
*klass
, const gchar
*name
, MonoMethod
*method
)
6194 MonoMethodSignature
*sig
, *csig
;
6195 MonoMethodBuilder
*mb
;
6199 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
6200 mb
->method
->slot
= -1;
6202 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
6203 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
6205 sig
= mono_method_signature_internal (method
);
6206 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
6207 csig
->generic_param_count
= 0;
6209 get_marshal_cb ()->emit_generic_array_helper (mb
, method
, csig
);
6211 /* We can corlib internal methods */
6212 get_marshal_cb ()->mb_skip_visibility (mb
);
6214 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
6215 info
->d
.generic_array_helper
.method
= method
;
6216 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
6224 * The mono_win32_compat_* functions are implementations of inline
6225 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
6226 * although not exported by kernel32.
6228 * We map the appropiate kernel32 entries to these functions using
6229 * dllmaps declared in the global etc/mono/config.
6233 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
6235 if (!dest
|| !source
)
6238 memcpy (dest
, source
, length
);
6242 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
6244 memset (dest
, fill
, length
);
6248 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
6250 if (!dest
|| !source
)
6253 memmove (dest
, source
, length
);
6257 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
6259 memset (dest
, 0, length
);
6263 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
6268 for (i
= 0; i
< len
; ++i
)
6275 while (byte
&& !(byte
& 1))
6277 g_assert (byte
== 1);
6283 #ifndef ENABLE_ILGEN
6285 emit_thunk_invoke_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6291 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
6293 MonoMethodBuilder
*mb
;
6294 MonoMethodSignature
*sig
, *csig
;
6299 int i
, param_count
, sig_size
;
6303 klass
= method
->klass
;
6304 image
= m_class_get_image (klass
);
6306 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
6308 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
6311 MonoType
*object_type
= mono_get_object_type ();
6313 sig
= mono_method_signature_internal (method
);
6314 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
6316 /* add "this" and exception param */
6317 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
6319 /* dup & extend signature */
6320 csig
= mono_metadata_signature_alloc (image
, param_count
);
6321 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
6322 memcpy (csig
, sig
, sig_size
);
6323 csig
->param_count
= param_count
;
6326 csig
->call_convention
= MONO_CALL_DEFAULT
;
6330 csig
->params
[0] = m_class_get_byval_arg (klass
);
6331 /* move params up by one */
6332 for (i
= 0; i
< sig
->param_count
; i
++)
6333 csig
->params
[i
+ 1] = sig
->params
[i
];
6336 /* setup exception param as byref+[out] */
6337 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
, m_class_get_byval_arg (mono_defaults
.exception_class
));
6338 csig
->params
[param_count
- 1]->byref
= 1;
6339 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
6341 /* convert struct return to object */
6342 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6343 csig
->ret
= object_type
;
6345 get_marshal_cb ()->emit_thunk_invoke_wrapper (mb
, method
, csig
);
6347 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
6354 clear_runtime_invoke_method_cache (GHashTable
*table
, MonoMethod
*method
)
6356 MonoWrapperMethodCacheKey hash_key
= {method
, FALSE
, FALSE
};
6358 * Since we have a small set of possible keys, remove each one separately, thus
6359 * avoiding the traversal of the entire hash table, when using foreach_remove.
6361 g_hash_table_remove (table
, &hash_key
);
6362 hash_key
.need_direct_wrapper
= TRUE
;
6363 g_hash_table_remove (table
, &hash_key
);
6364 hash_key
.virtual_
= TRUE
;
6365 g_hash_table_remove (table
, &hash_key
);
6366 hash_key
.need_direct_wrapper
= FALSE
;
6367 g_hash_table_remove (table
, &hash_key
);
6371 * mono_marshal_free_dynamic_wrappers:
6373 * Free wrappers of the dynamic method METHOD.
6376 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
6381 MonoImage
*image
= get_method_image (method
);
6383 g_assert (method_is_dynamic (method
));
6385 /* This could be called during shutdown */
6386 if (marshal_mutex_initialized
)
6387 mono_marshal_lock ();
6389 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
6390 * they could be shared with other methods ?
6392 if (image
->wrapper_caches
.runtime_invoke_method_cache
)
6393 clear_runtime_invoke_method_cache (image
->wrapper_caches
.runtime_invoke_method_cache
, method
);
6394 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
6395 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
6396 // FIXME: Need to clear the caches in other images as well
6397 if (image
->delegate_bound_static_invoke_cache
)
6398 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature_internal (method
));
6400 if (marshal_mutex_initialized
)
6401 mono_marshal_unlock ();
6405 mono_marshal_get_type_object (MonoClass
*klass
)
6408 MonoType
*type
= m_class_get_byval_arg (klass
);
6409 MonoObject
*result
= (MonoObject
*)mono_type_get_object_checked (mono_domain_get (), type
, error
);
6410 mono_error_set_pending_exception (error
);
6415 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
)
6417 get_marshal_cb ()->emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, aot
, check_exceptions
, func_param
);
6420 #ifndef ENABLE_ILGEN
6422 emit_native_wrapper_noilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
)
6427 static MonoMarshalCallbacks marshal_cb
;
6428 static gboolean cb_inited
= FALSE
;
6431 mono_install_marshal_callbacks (MonoMarshalCallbacks
*cb
)
6433 g_assert (!cb_inited
);
6434 g_assert (cb
->version
== MONO_MARSHAL_CALLBACKS_VERSION
);
6435 memcpy (&marshal_cb
, cb
, sizeof (MonoMarshalCallbacks
));
6439 #ifndef ENABLE_ILGEN
6441 install_noilgen (void)
6443 MonoMarshalCallbacks cb
;
6444 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6445 cb
.emit_marshal_array
= emit_marshal_array_noilgen
;
6446 cb
.emit_marshal_boolean
= emit_marshal_boolean_noilgen
;
6447 cb
.emit_marshal_ptr
= emit_marshal_ptr_noilgen
;
6448 cb
.emit_marshal_char
= emit_marshal_char_noilgen
;
6449 cb
.emit_marshal_scalar
= emit_marshal_scalar_noilgen
;
6450 cb
.emit_marshal_custom
= emit_marshal_custom_noilgen
;
6451 cb
.emit_marshal_asany
= emit_marshal_asany_noilgen
;
6452 cb
.emit_marshal_vtype
= emit_marshal_vtype_noilgen
;
6453 cb
.emit_marshal_string
= emit_marshal_string_noilgen
;
6454 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_noilgen
;
6455 cb
.emit_marshal_handleref
= emit_marshal_handleref_noilgen
;
6456 cb
.emit_marshal_object
= emit_marshal_object_noilgen
;
6457 cb
.emit_marshal_variant
= emit_marshal_variant_noilgen
;
6458 cb
.emit_castclass
= emit_castclass_noilgen
;
6459 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_noilgen
;
6460 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_noilgen
;
6461 cb
.emit_isinst
= emit_isinst_noilgen
;
6462 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_noilgen
;
6463 cb
.emit_stelemref
= emit_stelemref_noilgen
;
6464 cb
.emit_array_address
= emit_array_address_noilgen
;
6465 cb
.emit_native_wrapper
= emit_native_wrapper_noilgen
;
6466 cb
.emit_managed_wrapper
= emit_managed_wrapper_noilgen
;
6467 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_noilgen
;
6468 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_noilgen
;
6469 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_noilgen
;
6470 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_noilgen
;
6471 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_noilgen
;
6472 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_noilgen
;
6473 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_noilgen
;
6474 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_noilgen
;
6475 cb
.emit_generic_array_helper
= emit_generic_array_helper_noilgen
;
6476 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_noilgen
;
6477 cb
.emit_create_string_hack
= emit_create_string_hack_noilgen
;
6478 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_noilgen
;
6479 cb
.emit_icall_wrapper
= emit_icall_wrapper_noilgen
;
6480 cb
.emit_return
= emit_return_noilgen
;
6481 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_noilgen
;
6482 cb
.mb_skip_visibility
= mb_skip_visibility_noilgen
;
6483 cb
.mb_set_dynamic
= mb_set_dynamic_noilgen
;
6484 cb
.mb_emit_exception
= mb_emit_exception_noilgen
;
6485 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_noilgen
;
6486 cb
.mb_emit_byte
= mb_emit_byte_noilgen
;
6487 mono_install_marshal_callbacks (&cb
);
6491 static MonoMarshalCallbacks
*
6492 get_marshal_cb (void)
6494 if (G_UNLIKELY (!cb_inited
)) {
6496 mono_marshal_ilgen_init ();