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 (MonoObject
*obj
, MonoClass
*klass
)
154 /* This is called from stelemref so it is expected to succeed */
156 if (mono_class_is_interface (klass
)) {
157 MonoVTable
*vt
= obj
->vtable
;
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
)))
167 MonoObject
*result
= mono_object_isinst_checked (obj
, klass
, error
);
168 mono_error_set_pending_exception (error
);
173 ves_icall_mono_string_from_utf16_impl (const gunichar2
*data
, MonoError
*error
)
175 MonoString
*s
= mono_string_from_utf16_checked (data
, error
);
176 return_val_if_nok (error
, NULL_HANDLE_STRING
);
177 return MONO_HANDLE_NEW (MonoString
, s
);
181 ves_icall_mono_string_to_utf8_impl (MonoStringHandle str
, MonoError
*error
)
183 return mono_string_handle_to_utf8 (str
, error
);
187 ves_icall_string_new_wrapper_impl (const char *text
, MonoError
*error
)
189 return text
? mono_string_new_handle (mono_domain_get (), text
, error
) : NULL_HANDLE_STRING
;
193 mono_marshal_init (void)
195 static gboolean module_initialized
= FALSE
;
197 if (!module_initialized
) {
198 module_initialized
= TRUE
;
199 mono_coop_mutex_init_recursive (&marshal_mutex
);
200 marshal_mutex_initialized
= TRUE
;
202 register_icall (mono_marshal_string_to_utf16
, mono_icall_sig_ptr_obj
, FALSE
);
203 register_icall (mono_marshal_string_to_utf16_copy
, mono_icall_sig_ptr_obj
, FALSE
);
204 register_icall (mono_string_to_utf16_internal
, mono_icall_sig_ptr_obj
, FALSE
);
205 register_icall (ves_icall_mono_string_from_utf16
, mono_icall_sig_obj_ptr
, FALSE
);
206 register_icall (mono_string_from_byvalstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
207 register_icall (mono_string_from_byvalwstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
208 register_icall (mono_string_new_wrapper_internal
, mono_icall_sig_obj_ptr
, FALSE
);
209 register_icall (ves_icall_string_new_wrapper
, mono_icall_sig_obj_ptr
, FALSE
);
210 register_icall (mono_string_new_len_wrapper
, mono_icall_sig_obj_ptr_int
, FALSE
);
211 register_icall (ves_icall_mono_string_to_utf8
, mono_icall_sig_ptr_obj
, FALSE
);
212 register_icall (mono_string_to_utf8str
, mono_icall_sig_ptr_obj
, FALSE
);
213 register_icall (mono_string_to_ansibstr
, mono_icall_sig_ptr_object
, FALSE
);
214 register_icall (mono_string_builder_to_utf8
, mono_icall_sig_ptr_object
, FALSE
);
215 register_icall (mono_string_builder_to_utf16
, mono_icall_sig_ptr_object
, FALSE
);
216 register_icall (mono_array_to_savearray
, mono_icall_sig_ptr_object
, FALSE
);
217 register_icall (mono_array_to_lparray
, mono_icall_sig_ptr_object
, FALSE
);
218 register_icall (mono_free_lparray
, mono_icall_sig_void_object_ptr
, FALSE
);
219 register_icall (mono_byvalarray_to_byte_array
, mono_icall_sig_void_object_ptr_int32
, FALSE
);
220 register_icall (mono_array_to_byte_byvalarray
, mono_icall_sig_void_ptr_object_int32
, FALSE
);
221 register_icall (mono_delegate_to_ftnptr
, mono_icall_sig_ptr_object
, FALSE
);
222 register_icall (mono_ftnptr_to_delegate
, mono_icall_sig_object_ptr_ptr
, FALSE
);
223 register_icall (mono_marshal_asany
, mono_icall_sig_ptr_object_int32_int32
, FALSE
);
224 register_icall (mono_marshal_free_asany
, mono_icall_sig_void_object_ptr_int32_int32
, FALSE
);
225 register_icall (ves_icall_marshal_alloc
, mono_icall_sig_ptr_ptr
, FALSE
);
226 register_icall (mono_marshal_free
, mono_icall_sig_void_ptr
, FALSE
);
227 register_icall (mono_marshal_set_last_error
, mono_icall_sig_void
, TRUE
);
228 register_icall (mono_marshal_set_last_error_windows
, mono_icall_sig_void_int32
, TRUE
);
229 register_icall (mono_marshal_clear_last_error
, mono_icall_sig_void
, TRUE
);
230 register_icall (mono_string_utf8_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
231 register_icall (mono_string_utf8_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
232 register_icall (mono_string_utf16_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
233 register_icall (mono_string_utf16_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
234 register_icall (mono_marshal_free_array
, mono_icall_sig_void_ptr_int32
, FALSE
);
235 register_icall (mono_string_to_byvalstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
236 register_icall (mono_string_to_byvalwstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
237 // Because #define g_free monoeg_g_free.
238 register_icall (monoeg_g_free
, mono_icall_sig_void_ptr
, FALSE
);
239 register_icall (mono_object_isinst_icall
, mono_icall_sig_object_object_ptr
, TRUE
);
240 register_icall (mono_struct_delete_old
, mono_icall_sig_void_ptr_ptr
, FALSE
);
241 register_icall (mono_delegate_begin_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
242 register_icall (mono_delegate_end_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
243 register_icall (mono_gc_wbarrier_generic_nostore_internal
, mono_icall_sig_void_ptr
, FALSE
);
244 register_icall (mono_gchandle_get_target_internal
, mono_icall_sig_object_int32
, TRUE
);
245 register_icall (mono_marshal_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
246 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
247 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
248 register_icall (mono_threads_enter_gc_unsafe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
249 register_icall (mono_threads_exit_gc_unsafe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
250 register_icall (mono_threads_attach_coop
, mono_icall_sig_ptr_ptr_ptr
, TRUE
);
251 register_icall (mono_threads_detach_coop
, mono_icall_sig_void_ptr_ptr
, TRUE
);
252 register_icall (mono_marshal_get_type_object
, mono_icall_sig_object_ptr
, TRUE
);
254 mono_cominterop_init ();
255 mono_remoting_init ();
257 mono_counters_register ("MonoClass::class_marshal_info_count count",
258 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_marshal_info_count
);
263 mono_marshal_cleanup (void)
265 mono_cominterop_cleanup ();
267 mono_native_tls_free (load_type_info_tls_id
);
268 mono_native_tls_free (last_error_tls_id
);
269 mono_coop_mutex_destroy (&marshal_mutex
);
270 marshal_mutex_initialized
= FALSE
;
274 mono_marshal_lock_internal (void)
276 mono_marshal_lock ();
280 mono_marshal_unlock_internal (void)
282 mono_marshal_unlock ();
285 // This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error.
287 mono_delegate_to_ftnptr_impl (MonoDelegateHandle delegate
, MonoError
*error
)
289 gpointer result
= NULL
;
290 MonoMethod
*method
, *wrapper
;
292 uint32_t target_handle
= 0;
294 if (MONO_HANDLE_IS_NULL (delegate
))
297 if (MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
)) {
298 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
302 klass
= mono_handle_class (delegate
);
303 g_assert (m_class_is_delegate (klass
));
305 method
= MONO_HANDLE_GETVAL (delegate
, method
);
306 if (MONO_HANDLE_GETVAL (delegate
, method_is_virtual
)) {
307 MonoObjectHandle delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
308 method
= mono_object_handle_get_virtual_method (delegate_target
, method
, error
);
309 goto_if_nok (error
, leave
);
312 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
315 ftnptr
= mono_lookup_pinvoke_call_internal (method
, error
);
317 g_assert (!is_ok (error
));
324 MonoObjectHandle delegate_target
;
325 delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
326 if (!MONO_HANDLE_IS_NULL (delegate_target
)) {
327 /* Produce a location which can be embedded in JITted code */
328 target_handle
= mono_gchandle_new_weakref_from_handle (delegate_target
);
331 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
, error
);
332 goto_if_nok (error
, leave
);
334 MONO_HANDLE_SETVAL (delegate
, delegate_trampoline
, gpointer
, mono_compile_method_checked (wrapper
, error
));
335 goto_if_nok (error
, leave
);
337 // Add the delegate to the delegate hash table
338 delegate_hash_table_add (delegate
);
340 /* when the object is collected, collect the dynamic method, too */
341 mono_object_register_finalizer ((MonoObject
*) MONO_HANDLE_RAW (delegate
));
343 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
346 if (!is_ok (error
) && target_handle
!= 0)
347 mono_gchandle_free_internal (target_handle
);
352 * this hash table maps from a delegate trampoline object to a weak reference
353 * of the delegate. As an optimizations with a non-moving GC we store the
354 * object pointer itself, otherwise we use a GC handle.
356 static GHashTable
*delegate_hash_table
;
359 delegate_hash_table_new (void) {
360 return g_hash_table_new (NULL
, NULL
);
364 delegate_hash_table_remove (MonoDelegate
*d
)
366 guint32 gchandle
= 0;
371 mono_marshal_lock ();
372 if (delegate_hash_table
== NULL
)
373 delegate_hash_table
= delegate_hash_table_new ();
374 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
375 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
376 mono_marshal_unlock ();
378 mono_gchandle_free_internal (gchandle
);
382 delegate_hash_table_add (MonoDelegateHandle d
)
384 mono_marshal_lock ();
385 if (delegate_hash_table
== NULL
)
386 delegate_hash_table
= delegate_hash_table_new ();
387 gpointer delegate_trampoline
= MONO_HANDLE_GETVAL (d
, delegate_trampoline
);
388 gboolean has_target
= MONO_HANDLE_GETVAL (d
, target
) != NULL
;
390 // If the delegate has an instance method there is 1 to 1 mapping between
391 // the delegate object and the delegate_trampoline
392 guint32 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
));
394 // Somehow, some other thread beat us to it ?
395 g_assert (mono_gchandle_target_equal (gchandle
, MONO_HANDLE_CAST (MonoObject
, d
)));
397 gchandle
= mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, d
));
398 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
401 if (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
) == NULL
) {
402 guint32 gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, d
), FALSE
);
403 // This delegate will always be associated with its delegate_trampoline in the table.
404 // We don't free this delegate object because it is too expensive to keep track of these
405 // pairs and avoid races with the delegate finalization.
406 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
409 mono_marshal_unlock ();
413 * mono_marshal_use_aot_wrappers:
415 * Instructs this module to use AOT compatible wrappers.
418 mono_marshal_use_aot_wrappers (gboolean use
)
420 use_aot_wrappers
= use
;
424 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
427 MonoCustomAttrInfo
*cinfo
;
428 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
430 /* The attribute is only available in Net 2.0 */
431 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
433 * The pinvoke attributes are stored in a real custom attribute so we have to
436 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
437 if (!mono_error_ok (error
)) {
438 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
439 mono_error_cleanup (error
);
441 if (cinfo
&& !mono_runtime_get_no_exec ()) {
442 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), error
);
444 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
446 if (!mono_error_ok (error
)) {
447 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
448 mono_error_cleanup (error
);
452 mono_custom_attrs_free (cinfo
);
457 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
459 mono_ftnptr_to_delegate_impl (MonoClass
*klass
, gpointer ftn
, MonoError
*error
)
462 MonoDelegateHandle d
= MONO_HANDLE_NEW (MonoDelegate
, NULL
);
467 mono_marshal_lock ();
468 if (delegate_hash_table
== NULL
)
469 delegate_hash_table
= delegate_hash_table_new ();
470 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
471 mono_marshal_unlock ();
473 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_CAST (MonoDelegate
, mono_gchandle_get_target_handle (gchandle
)));
475 if (MONO_HANDLE_IS_NULL (d
)) {
476 /* This is a native function, so construct a delegate for it */
477 MonoMethodSignature
*sig
;
479 MonoMarshalSpec
**mspecs
;
480 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
481 MonoMethodPInvoke piinfo
;
482 MonoObjectHandle this_obj
;
485 if (use_aot_wrappers
) {
486 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
487 this_obj
= MONO_HANDLE_NEW (MonoObject
, mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, error
));
488 goto_if_nok (error
, leave
);
490 memset (&piinfo
, 0, sizeof (piinfo
));
491 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
493 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
494 mono_method_get_marshal_info (invoke
, mspecs
);
495 /* Freed below so don't alloc from mempool */
496 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
499 wrapper
= mono_marshal_get_native_func_wrapper (m_class_get_image (klass
), sig
, &piinfo
, mspecs
, ftn
);
500 this_obj
= MONO_HANDLE_NEW (MonoObject
, NULL
);
502 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
504 mono_metadata_free_marshal_spec (mspecs
[i
]);
509 MONO_HANDLE_ASSIGN (d
, mono_object_new_handle (mono_domain_get (), klass
, error
));
510 goto_if_nok (error
, leave
);
511 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, error
);
512 goto_if_nok (error
, leave
);
514 mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject
, d
), this_obj
, compiled_ptr
, wrapper
, error
);
515 goto_if_nok (error
, leave
);
518 g_assert (!MONO_HANDLE_IS_NULL (d
));
519 if (MONO_HANDLE_DOMAIN (d
) != mono_domain_get ())
520 mono_error_set_not_supported (error
, "Delegates cannot be marshalled from native code into a domain other than their home domain");
526 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
531 delegate_hash_table_remove (delegate
);
533 ptr
= (gpointer
)mono_atomic_xchg_ptr (&delegate
->delegate_trampoline
, NULL
);
535 if (!delegate
->target
) {
536 /* The wrapper method is shared between delegates -> no need to free it */
545 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
546 /* FIXME we leak wrapper with the interpreter */
550 method
= mono_jit_info_get_method (ji
);
551 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
553 /*the target gchandle is the first entry after size and the wrapper itself.*/
554 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
557 mono_gchandle_free_internal (gchandle
);
559 mono_runtime_free_method (mono_object_domain (delegate
), method
);
563 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
565 mono_string_from_byvalstr_impl (const char *data
, int max_len
, MonoError
*error
)
567 // FIXME This optimization ok to miss before wrapper? Or null is rare?
569 return NULL_HANDLE_STRING
;
572 while (len
< max_len
- 1 && data
[len
])
576 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), data
, len
, error
);
577 return_val_if_nok (error
, NULL_HANDLE_STRING
);
578 return MONO_HANDLE_NEW (MonoString
, s
);
581 /* This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error */
583 mono_string_from_byvalwstr_impl (const gunichar2
*data
, int max_len
, MonoError
*error
)
585 // FIXME This optimization ok to miss before wrapper? Or null is rare?
587 return NULL_HANDLE_STRING
;
589 // FIXME Check max_len while scanning data? mono_string_from_byvalstr does.
590 const int len
= g_utf16_len (data
);
592 return mono_string_new_utf16_handle (mono_domain_get (), data
, MIN (len
, max_len
), error
);
596 mono_array_to_savearray_impl (MonoArrayHandle array
, MonoError
*error
)
598 if (!MONO_HANDLE_BOOL (array
))
601 g_assert_not_reached ();
606 mono_array_to_lparray_impl (MonoArrayHandle array_handle
, MonoError
*error
)
608 if (!MONO_HANDLE_BOOL (array_handle
))
611 MonoArray
*array
= MONO_HANDLE_RAW (array_handle
); // FIXMEcoop
614 gpointer
*nativeArray
= NULL
;
615 int nativeArraySize
= 0;
617 MonoClass
*klass
= array
->obj
.vtable
->klass
;
618 MonoClass
*klass_element_class
= m_class_get_element_class (klass
);
620 switch (m_class_get_byval_arg (klass_element_class
)->type
) {
622 g_assert_not_reached ();
624 case MONO_TYPE_CLASS
:
625 nativeArraySize
= array
->max_length
;
626 nativeArray
= g_new (gpointer
, nativeArraySize
);
627 for (i
= 0; i
< nativeArraySize
; ++i
) {
628 nativeArray
[i
] = mono_cominterop_get_com_interface (((MonoObject
**)array
->vector
)[i
], klass_element_class
, error
);
629 if (!is_ok (error
)) {
630 // FIXME? Returns uninitialized.
636 case MONO_TYPE_BOOLEAN
:
649 case MONO_TYPE_VALUETYPE
:
653 case MONO_TYPE_GENERICINST
:
654 case MONO_TYPE_OBJECT
:
655 case MONO_TYPE_ARRAY
:
656 case MONO_TYPE_SZARRAY
:
657 case MONO_TYPE_STRING
:
659 g_warning ("type 0x%x not handled", m_class_get_byval_arg (klass_element_class
)->type
);
660 g_assert_not_reached ();
663 return array
->vector
;
667 mono_free_lparray_impl (MonoArrayHandle array
, gpointer
* nativeArray
, MonoError
*error
)
670 if (!nativeArray
|| MONO_HANDLE_IS_NULL (array
))
673 MonoClass
* const klass
= mono_handle_class (array
);
675 if (m_class_get_byval_arg (m_class_get_element_class (klass
))->type
== MONO_TYPE_CLASS
)
676 g_free (nativeArray
);
680 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
682 mono_byvalarray_to_byte_array_impl (MonoArrayHandle arr
, const char *native_arr
, guint32 elnum
, MonoError
*error
)
684 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
686 GError
*gerror
= NULL
;
688 gunichar2
*ut
= g_utf8_to_utf16 (native_arr
, elnum
, NULL
, &items_written
, &gerror
);
691 g_error_free (gerror
);
694 gchandle_t gchandle
= 0;
695 memcpy (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), ut
, items_written
* sizeof (gunichar2
));
696 mono_gchandle_free_internal (gchandle
);
700 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
702 mono_array_to_byte_byvalarray_impl (gpointer native_arr
, MonoArrayHandle arr
, guint32 elnum
, MonoError
*error
)
704 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
706 GError
*gerror
= NULL
;
708 gchandle_t gchandle
= 0;
709 char *as
= g_utf16_to_utf8 (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), mono_array_handle_length (arr
), NULL
, NULL
, &gerror
);
710 mono_gchandle_free_internal (gchandle
);
712 mono_error_set_argument (error
, "string", gerror
->message
);
713 g_error_free (gerror
);
716 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
720 static MonoStringBuilderHandle
721 mono_string_builder_new (int starting_string_length
, MonoError
*error
)
723 static MonoClass
*string_builder_class
;
724 static MonoMethod
*sb_ctor
;
727 int initial_len
= starting_string_length
;
733 MonoMethodDesc
*desc
;
736 string_builder_class
= mono_class_try_get_stringbuilder_class ();
737 g_assert (string_builder_class
); //TODO don't swallow the error
738 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
739 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
741 mono_method_desc_free (desc
);
742 mono_memory_barrier ();
746 // We make a new array in the _to_builder function, so this
747 // array will always be garbage collected.
748 args
[0] = &initial_len
;
750 MonoStringBuilderHandle sb
= MONO_HANDLE_CAST (MonoStringBuilder
, mono_object_new_handle (mono_domain_get (), string_builder_class
, error
));
751 mono_error_assert_ok (error
);
753 mono_runtime_try_invoke_handle (sb_ctor
, MONO_HANDLE_CAST (MonoObject
, sb
), args
, error
);
754 mono_error_assert_ok (error
);
756 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW_GET (MonoArray
, sb
, chunkChars
);
757 g_assert (MONO_HANDLE_GETVAL (chunkChars
, max_length
) >= initial_len
);
763 mono_string_utf16_to_builder_copy (MonoStringBuilderHandle sb
, const gunichar2
*text
, size_t string_len
, MonoError
*error
)
765 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
766 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
768 guint capacity
= mono_string_builder_capacity (sb
);
770 g_assert (capacity
>= string_len
);
772 MONO_ENTER_NO_SAFEPOINTS
;
775 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
776 const int maxLength
= MONO_HANDLE_GETVAL (chunkChars
, max_length
);
777 g_assert (maxLength
>= 0);
778 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
779 g_assert (chunkOffset
>= 0);
780 if (maxLength
> 0 && chunkOffset
< string_len
) {
781 // Check that we will not overrun our boundaries.
782 int charsToCopy
= MIN (string_len
- chunkOffset
, maxLength
);
783 memcpy (MONO_HANDLE_RAW (chunkChars
)->vector
, text
+ chunkOffset
, charsToCopy
* sizeof (gunichar2
));
784 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, charsToCopy
);
786 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, 0);
788 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
789 } while (MONO_HANDLE_BOOL (chunk
));
791 MONO_EXIT_NO_SAFEPOINTS
;
794 MonoStringBuilderHandle
795 mono_string_utf16_to_builder2_impl (const gunichar2
*text
, MonoError
*error
)
798 return NULL_HANDLE_STRING_BUILDER
;
800 const gsize len
= g_utf16_len (text
);
802 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
803 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
805 mono_string_utf16len_to_builder (sb
, text
, len
, error
);
806 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
812 mono_string_utf8len_to_builder (MonoStringBuilderHandle sb
, const char *text
, gsize len
, MonoError
*error
)
814 if (!MONO_HANDLE_BOOL (sb
) || !text
)
817 GError
*gerror
= NULL
;
819 gunichar2
* ut
= g_utf8_to_utf16 (text
, len
, NULL
, &copied
, &gerror
);
820 int capacity
= mono_string_builder_capacity (sb
);
822 if (copied
> capacity
)
826 MONO_HANDLE_SETRAW (sb
, chunkPrevious
, NULL
);
827 mono_string_utf16_to_builder_copy (sb
, ut
, copied
, error
);
830 g_error_free (gerror
);
837 mono_string_utf8_to_builder_impl (MonoStringBuilderHandle sb
, const char *text
, MonoError
*error
)
839 mono_string_utf8len_to_builder (sb
, text
, text
? strlen (text
) : 0, error
);
842 MonoStringBuilderHandle
843 mono_string_utf8_to_builder2_impl (const char *text
, MonoError
*error
)
846 return NULL_HANDLE_STRING_BUILDER
;
848 const gsize len
= strlen (text
);
850 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
851 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
853 mono_string_utf8len_to_builder (sb
, text
, len
, error
);
854 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
860 mono_string_utf16len_to_builder (MonoStringBuilderHandle sb
, const gunichar2
*text
, gsize len
, MonoError
*error
)
862 if (!MONO_HANDLE_BOOL (sb
) || !text
)
864 len
= MIN (len
, mono_string_builder_capacity (sb
));
865 mono_string_utf16_to_builder_copy (sb
, text
, len
, error
);
869 mono_string_utf16_to_builder_impl (MonoStringBuilderHandle sb
, const gunichar2
*text
, MonoError
*error
)
871 mono_string_utf16len_to_builder (sb
, text
, text
? g_utf16_len (text
) : 0, error
);
875 * mono_string_builder_to_utf8:
876 * \param sb the string builder
878 * Converts to utf8 the contents of the \c MonoStringBuilder .
880 * \returns a utf8 string with the contents of the \c StringBuilder .
882 * The return value must be released with mono_marshal_free.
884 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
887 mono_string_builder_to_utf8_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
890 GError
*gerror
= NULL
;
892 gunichar2
*str_utf16
= NULL
;
896 if (!MONO_HANDLE_BOOL (sb
))
899 str_utf16
= mono_string_builder_to_utf16_impl (sb
, error
);
900 goto_if_nok (error
, exit
);
902 tmp
= g_utf16_to_utf8 (str_utf16
, mono_string_builder_string_length (sb
), NULL
, &byte_count
, &gerror
);
904 mono_error_set_execution_engine (error
, "Failed to convert StringBuilder from utf16 to utf8");
908 len
= mono_string_builder_capacity (sb
) + 1;
909 res
= (char *)mono_marshal_alloc (MAX (byte_count
+ 1, len
), error
);
910 if (!is_ok (error
)) {
915 memcpy (res
, tmp
, byte_count
);
916 res
[byte_count
] = 0;
918 g_error_free (gerror
);
919 mono_marshal_free (str_utf16
);
925 * mono_string_builder_to_utf16:
926 * \param sb the string builder
928 * Converts to utf16 the contents of the \c MonoStringBuilder .
930 * Returns: a utf16 string with the contents of the \c StringBuilder .
932 * The return value must be released with mono_marshal_free.
934 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
937 mono_string_builder_to_utf16_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
939 if (!MONO_HANDLE_BOOL (sb
))
942 g_assert (MONO_HANDLE_GET_BOOL (sb
, chunkChars
));
944 guint capacity
= mono_string_builder_capacity (sb
);
945 guint length
= mono_string_builder_string_length (sb
);
947 // Follow CoreCLR and double NULL terminate the buffer so we have more protection
948 // against native code putting garbage in there.
950 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((capacity
+ 2) * sizeof (gunichar2
), error
);
951 return_val_if_nok (error
, NULL
);
954 str
[capacity
+ 1] = 0;
956 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
957 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
959 MONO_ENTER_NO_SAFEPOINTS
;
962 const int chunkLength
= MONO_HANDLE_GETVAL (chunk
, chunkLength
);
963 g_assert (chunkLength
>= 0);
964 if (chunkLength
> 0) {
965 // Check that we will not overrun our boundaries.
966 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
967 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
968 g_assert (chunkOffset
>= 0);
969 g_assertf ((chunkOffset
+ chunkLength
) >= chunkLength
, "integer overflow");
970 g_assertf ((chunkOffset
+ chunkLength
) <= capacity
, "A chunk in the StringBuilder had a length longer than expected from the offset.");
971 memcpy (str
+ chunkOffset
, MONO_HANDLE_RAW (chunkChars
)->vector
, chunkLength
* sizeof (gunichar2
));
973 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
974 } while (MONO_HANDLE_BOOL (chunk
));
978 MONO_EXIT_NO_SAFEPOINTS
;
985 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
987 mono_string_to_utf8str_impl (MonoStringHandle s
, MonoError
*error
)
989 return mono_string_handle_to_utf8 (s
, error
);
995 mono_string_to_ansibstr_impl (MonoStringHandle string_obj
, MonoError
*error
)
997 g_error ("UnmanagedMarshal.BStr is not implemented.");
1002 * mono_string_to_byvalstr:
1003 * \param dst Where to store the null-terminated utf8 decoded string.
1004 * \param src the \c MonoString to copy.
1005 * \param size the maximum number of bytes to copy.
1007 * Copies the \c MonoString pointed to by \p src as a utf8 string
1008 * into \p dst, it copies at most \p size bytes into the destination.
1011 mono_string_to_byvalstr_impl (char *dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1013 g_assert (dst
!= NULL
);
1014 g_assert (size
> 0);
1016 memset (dst
, 0, size
);
1017 if (!MONO_HANDLE_BOOL (src
))
1020 // FIXME convert right into dst instead of the double copy.
1022 char *s
= mono_string_handle_to_utf8 (src
, error
);
1023 return_if_nok (error
);
1024 int len
= MIN (size
, strlen (s
));
1025 len
-= (len
>= size
);
1026 memcpy (dst
, s
, len
);
1032 * mono_string_to_byvalwstr:
1033 * \param dst Where to store the null-terminated utf16 decoded string.
1034 * \param src the \c MonoString to copy.
1035 * \param size the maximum number of wide characters to copy (each consumes 2 bytes)
1037 * Copies the \c MonoString pointed to by \p src as a utf16 string into
1038 * \p dst, it copies at most \p size gunichar2s into the destination (including
1039 * a terminating 16-bit zero terminator).
1042 mono_string_to_byvalwstr_impl (gunichar2
*dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1045 g_assert (size
> 0);
1047 if (!MONO_HANDLE_BOOL (src
)) {
1048 memset (dst
, 0, size
* sizeof (gunichar2
));
1052 gchandle_t gchandle
= 0;
1053 int len
= MIN (size
, mono_string_handle_length (src
));
1054 memcpy (dst
, mono_string_handle_pin_chars (src
, &gchandle
), len
* sizeof (gunichar2
));
1055 mono_gchandle_free_internal (gchandle
);
1056 len
-= (size
<= mono_string_handle_length (src
));
1060 /* this is an icall, it sets the pending exception and returns NULL on error */
1062 mono_string_new_len_wrapper_impl (const char *text
, guint length
, MonoError
*error
)
1064 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), text
, length
, error
);
1065 return_val_if_nok (error
, NULL_HANDLE_STRING
);
1066 return MONO_HANDLE_NEW (MonoString
, s
);
1070 mono_type_to_ldind (MonoType
*type
)
1076 switch (type
->type
) {
1078 return CEE_LDIND_I1
;
1080 case MONO_TYPE_BOOLEAN
:
1081 return CEE_LDIND_U1
;
1083 return CEE_LDIND_I2
;
1085 case MONO_TYPE_CHAR
:
1086 return CEE_LDIND_U2
;
1088 return CEE_LDIND_I4
;
1090 return CEE_LDIND_U4
;
1094 case MONO_TYPE_FNPTR
:
1096 case MONO_TYPE_CLASS
:
1097 case MONO_TYPE_STRING
:
1098 case MONO_TYPE_OBJECT
:
1099 case MONO_TYPE_SZARRAY
:
1100 case MONO_TYPE_ARRAY
:
1101 return CEE_LDIND_REF
;
1104 return CEE_LDIND_I8
;
1106 return CEE_LDIND_R4
;
1108 return CEE_LDIND_R8
;
1109 case MONO_TYPE_VALUETYPE
:
1110 if (m_class_is_enumtype (type
->data
.klass
)) {
1111 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1115 case MONO_TYPE_TYPEDBYREF
:
1117 case MONO_TYPE_GENERICINST
:
1118 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1121 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1127 mono_type_to_stind (MonoType
*type
)
1130 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1133 switch (type
->type
) {
1136 case MONO_TYPE_BOOLEAN
:
1137 return CEE_STIND_I1
;
1140 case MONO_TYPE_CHAR
:
1141 return CEE_STIND_I2
;
1144 return CEE_STIND_I4
;
1148 case MONO_TYPE_FNPTR
:
1150 case MONO_TYPE_CLASS
:
1151 case MONO_TYPE_STRING
:
1152 case MONO_TYPE_OBJECT
:
1153 case MONO_TYPE_SZARRAY
:
1154 case MONO_TYPE_ARRAY
:
1155 return CEE_STIND_REF
;
1158 return CEE_STIND_I8
;
1160 return CEE_STIND_R4
;
1162 return CEE_STIND_R8
;
1163 case MONO_TYPE_VALUETYPE
:
1164 if (m_class_is_enumtype (type
->data
.klass
)) {
1165 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1169 case MONO_TYPE_TYPEDBYREF
:
1171 case MONO_TYPE_GENERICINST
:
1172 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1175 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1180 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1182 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1185 MonoMulticastDelegate
*mcast_delegate
;
1189 g_assert (delegate
);
1190 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
1191 if (mcast_delegate
->delegates
!= NULL
) {
1192 mono_error_set_argument (error
, NULL
, "The delegate must have only one target");
1193 mono_error_set_pending_exception (error
);
1197 #ifndef DISABLE_REMOTING
1198 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1199 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1200 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
1201 /* If the target is a proxy, make a direct call. Is proxy's work
1202 // to make the call asynchronous.
1204 MonoMethodMessage
*msg
;
1205 MonoDelegate
*async_callback
;
1207 MonoAsyncResult
*ares
;
1209 MonoArray
*out_args
;
1210 method
= delegate
->method
;
1212 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, error
);
1213 if (mono_error_set_pending_exception (error
))
1215 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, error
);
1216 if (mono_error_set_pending_exception (error
))
1218 MONO_OBJECT_SETREF_INTERNAL (ares
, async_delegate
, (MonoObject
*)delegate
);
1219 MONO_OBJECT_SETREF_INTERNAL (ares
, async_callback
, (MonoObject
*)async_callback
);
1220 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1221 msg
->call_type
= CallType_BeginInvoke
;
1224 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1225 if (!mono_error_ok (error
)) {
1226 mono_error_set_pending_exception (error
);
1230 mono_set_pending_exception ((MonoException
*) exc
);
1236 klass
= delegate
->object
.vtable
->klass
;
1238 ERROR_DECL (begin_invoke_error
);
1239 method
= mono_get_delegate_begin_invoke_checked (klass
, begin_invoke_error
);
1240 mono_error_cleanup (begin_invoke_error
); /* if we can't call BeginInvoke, fall back on Invoke */
1242 method
= mono_get_delegate_invoke_internal (klass
);
1245 MonoAsyncResult
*result
= mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, error
);
1246 mono_error_set_pending_exception (error
);
1251 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
1253 GString
*res
= g_string_new ("");
1256 g_string_append (res
, prefix
);
1257 g_string_append_c (res
, '_');
1260 mono_type_get_desc (res
, sig
->ret
, FALSE
);
1263 g_string_append (res
, "__this__");
1265 for (int i
= 0; i
< sig
->param_count
; ++i
) {
1266 g_string_append_c (res
, '_');
1267 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
1269 char *result
= res
->str
;
1270 g_string_free (res
, FALSE
);
1275 * mono_marshal_get_string_encoding:
1277 * Return the string encoding which should be used for a given parameter.
1280 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1282 /* First try the parameter marshal info */
1284 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
1285 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
1286 return spec
->data
.array_data
.elem_type
;
1289 return spec
->native
;
1293 return MONO_NATIVE_LPSTR
;
1295 /* Then try the method level marshal info */
1296 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1297 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1298 return MONO_NATIVE_LPSTR
;
1299 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1300 return MONO_NATIVE_LPWSTR
;
1301 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1303 return MONO_NATIVE_LPWSTR
;
1305 return MONO_NATIVE_LPSTR
;
1308 return MONO_NATIVE_LPSTR
;
1313 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1315 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1318 case MONO_NATIVE_LPWSTR
:
1319 return MONO_MARSHAL_CONV_STR_LPWSTR
;
1320 case MONO_NATIVE_LPSTR
:
1321 case MONO_NATIVE_VBBYREFSTR
:
1322 return MONO_MARSHAL_CONV_STR_LPSTR
;
1323 case MONO_NATIVE_LPTSTR
:
1324 return MONO_MARSHAL_CONV_STR_LPTSTR
;
1325 case MONO_NATIVE_BSTR
:
1326 return MONO_MARSHAL_CONV_STR_BSTR
;
1327 case MONO_NATIVE_UTF8STR
:
1328 return MONO_MARSHAL_CONV_STR_UTF8STR
;
1330 return MONO_MARSHAL_CONV_INVALID
;
1335 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1337 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1340 case MONO_NATIVE_LPWSTR
:
1341 return MONO_MARSHAL_CONV_SB_LPWSTR
;
1342 case MONO_NATIVE_LPSTR
:
1343 return MONO_MARSHAL_CONV_SB_LPSTR
;
1344 case MONO_NATIVE_UTF8STR
:
1345 return MONO_MARSHAL_CONV_SB_UTF8STR
;
1346 case MONO_NATIVE_LPTSTR
:
1347 return MONO_MARSHAL_CONV_SB_LPTSTR
;
1349 return MONO_MARSHAL_CONV_INVALID
;
1354 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1356 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1361 case MONO_NATIVE_LPWSTR
:
1363 return MONO_MARSHAL_CONV_LPWSTR_STR
;
1364 case MONO_NATIVE_UTF8STR
:
1365 return MONO_MARSHAL_CONV_UTF8STR_STR
;
1366 case MONO_NATIVE_LPSTR
:
1367 case MONO_NATIVE_VBBYREFSTR
:
1368 return MONO_MARSHAL_CONV_LPSTR_STR
;
1369 case MONO_NATIVE_LPTSTR
:
1373 return MONO_MARSHAL_CONV_LPTSTR_STR
;
1374 case MONO_NATIVE_BSTR
:
1375 return MONO_MARSHAL_CONV_BSTR_STR
;
1377 return MONO_MARSHAL_CONV_INVALID
;
1382 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1384 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1389 case MONO_NATIVE_LPWSTR
:
1390 return MONO_MARSHAL_CONV_LPWSTR_SB
;
1391 case MONO_NATIVE_UTF8STR
:
1392 return MONO_MARSHAL_CONV_UTF8STR_SB
;
1393 case MONO_NATIVE_LPSTR
:
1394 return MONO_MARSHAL_CONV_LPSTR_SB
;
1396 case MONO_NATIVE_LPTSTR
:
1397 return MONO_MARSHAL_CONV_LPTSTR_SB
;
1400 return MONO_MARSHAL_CONV_INVALID
;
1405 * Return whenever a field of a native structure or an array member needs to
1409 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1411 MonoMarshalNative encoding
;
1414 case MONO_TYPE_VALUETYPE
:
1415 /* FIXME: Optimize this */
1417 case MONO_TYPE_OBJECT
:
1418 case MONO_TYPE_CLASS
:
1419 if (t
->data
.klass
== mono_class_try_get_stringbuilder_class ()) {
1421 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
1425 case MONO_TYPE_STRING
:
1426 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1427 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
1434 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
1437 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1440 mono_marshal_lock ();
1443 g_hash_table_new (hash_func
, equal_func
);
1444 mono_memory_barrier ();
1447 mono_marshal_unlock ();
1453 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1455 return get_cache (var
, hash_func
, equal_func
);
1459 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
1463 mono_marshal_lock ();
1464 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1465 mono_marshal_unlock ();
1472 * Create a MonoMethod from MB, set INFO as wrapper info.
1475 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1476 int max_stack
, WrapperInfo
*info
)
1480 res
= mono_mb_create_method (mb
, sig
, max_stack
);
1482 mono_marshal_set_wrapper_info (res
, info
);
1486 /* Create the method from the builder and place it in the cache */
1488 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
1489 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1490 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
1497 mono_marshal_lock ();
1498 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1499 mono_marshal_unlock ();
1502 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
1503 mono_marshal_lock ();
1504 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1507 g_hash_table_insert (cache
, key
, res
);
1508 mono_marshal_set_wrapper_info (res
, info
);
1509 mono_marshal_unlock ();
1513 mono_marshal_unlock ();
1514 mono_free_method (newm
);
1522 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
1523 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1526 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
1530 * mono_marshal_method_from_wrapper:
1533 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
1536 int wrapper_type
= wrapper
->wrapper_type
;
1539 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1542 info
= mono_marshal_get_wrapper_info (wrapper
);
1544 switch (wrapper_type
) {
1545 case MONO_WRAPPER_REMOTING_INVOKE
:
1546 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
1547 case MONO_WRAPPER_XDOMAIN_INVOKE
:
1548 m
= info
->d
.remoting
.method
;
1549 if (wrapper
->is_inflated
) {
1553 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
1554 * contains an uninflated method.
1556 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1557 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1561 case MONO_WRAPPER_SYNCHRONIZED
:
1562 m
= info
->d
.synchronized
.method
;
1563 if (wrapper
->is_inflated
) {
1566 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1567 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1571 case MONO_WRAPPER_UNBOX
:
1572 return info
->d
.unbox
.method
;
1573 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
1574 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
1575 return info
->d
.managed_to_native
.method
;
1578 case MONO_WRAPPER_RUNTIME_INVOKE
:
1579 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
1580 return info
->d
.runtime_invoke
.method
;
1583 case MONO_WRAPPER_DELEGATE_INVOKE
:
1585 return info
->d
.delegate_invoke
.method
;
1594 * mono_marshal_get_wrapper_info:
1596 * Retrieve the WrapperInfo structure associated with WRAPPER.
1599 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
1601 g_assert (wrapper
->wrapper_type
);
1603 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
1607 * mono_marshal_set_wrapper_info:
1609 * Set the WrapperInfo structure associated with the wrapper
1610 * method METHOD to INFO.
1613 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
1617 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1620 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
1625 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
1629 info
= (WrapperInfo
*)mono_image_alloc0 (get_method_image (mb
->method
), sizeof (WrapperInfo
));
1630 info
->subtype
= subtype
;
1635 * get_wrapper_target_class:
1637 * Return the class where a wrapper method should be placed.
1640 get_wrapper_target_class (MonoImage
*image
)
1647 * - can't put all wrappers into an mscorlib class, because they reference
1648 * metadata (signature) so they should be put into the same image as the
1649 * method they wrap, so they are unloaded together.
1650 * - putting them into a class with a type initalizer could cause the
1651 * initializer to be executed which can be a problem if the wrappers are
1653 * - putting them into an inflated class can cause problems if the the
1654 * class is deleted because it references an image which is unloaded.
1655 * To avoid these problems, we put the wrappers into the <Module> class of
1658 if (image_is_dynamic (image
)) {
1659 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
1661 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), error
);
1662 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1670 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
1671 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
1675 * check_generic_wrapper_cache:
1677 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
1678 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
1679 * generic method definition.
1682 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
1685 MonoMethod
*inst
, *def
;
1686 MonoGenericContext
*ctx
;
1688 g_assert (orig_method
->is_inflated
);
1689 ctx
= mono_method_get_context (orig_method
);
1692 * Look for the instance
1694 res
= mono_marshal_find_in_cache (cache
, key
);
1699 * Look for the definition
1701 def
= mono_marshal_find_in_cache (cache
, def_key
);
1704 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1705 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1707 mono_memory_barrier ();
1708 mono_marshal_lock ();
1709 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1711 g_hash_table_insert (cache
, key
, inst
);
1714 mono_marshal_unlock ();
1721 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
1724 MonoMethod
*inst
, *res
;
1727 * We use the same cache for the generic definition and the instances.
1729 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1730 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1731 mono_memory_barrier ();
1732 mono_marshal_lock ();
1733 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1735 g_hash_table_insert (cache
, key
, inst
);
1738 mono_marshal_unlock ();
1743 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
1747 MonoMethod
*inst
, *def
;
1750 * Look for the instance
1752 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
1757 * Look for the definition
1759 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
1761 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1762 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1765 mono_memory_barrier ();
1766 mono_marshal_lock ();
1767 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1769 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1772 mono_marshal_unlock ();
1779 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
1782 MonoMethod
*inst
, *res
;
1783 WrapperInfo
*ginfo
, *info
;
1786 * We use the same cache for the generic definition and the instances.
1788 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1789 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1791 ginfo
= mono_marshal_get_wrapper_info (def
);
1793 info
= (WrapperInfo
*)mono_image_alloc0 (m_class_get_image (def
->klass
), sizeof (WrapperInfo
));
1794 info
->subtype
= ginfo
->subtype
;
1795 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
1796 info
->d
.delegate_invoke
.method
= mono_class_inflate_generic_method_checked (ginfo
->d
.delegate_invoke
.method
, ctx
, error
);
1797 mono_error_assert_ok (error
);
1801 mono_memory_barrier ();
1802 mono_marshal_lock ();
1803 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1805 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1808 mono_marshal_unlock ();
1812 #ifndef ENABLE_ILGEN
1814 emit_delegate_begin_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1820 * mono_marshal_get_delegate_begin_invoke:
1823 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
1825 MonoMethodSignature
*sig
;
1826 MonoMethodBuilder
*mb
;
1830 MonoGenericContext
*ctx
= NULL
;
1831 MonoMethod
*orig_method
= NULL
;
1833 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
1834 !strcmp (method
->name
, "BeginInvoke"));
1837 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
1839 if (method
->is_inflated
) {
1840 orig_method
= method
;
1841 ctx
= &((MonoMethodInflated
*)method
)->context
;
1842 method
= ((MonoMethodInflated
*)method
)->declaring
;
1845 sig
= mono_signature_no_pinvoke (method
);
1851 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1852 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
1856 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_begin_invoke_cache
,
1857 (GHashFunc
)mono_signature_hash
,
1858 (GCompareFunc
)mono_metadata_signature_equal
);
1859 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
1863 g_assert (sig
->hasthis
);
1865 name
= mono_signature_to_name (sig
, "begin_invoke");
1867 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1869 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1872 get_marshal_cb ()->emit_delegate_begin_invoke (mb
, sig
);
1874 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
1875 info
->d
.delegate_invoke
.method
= method
;
1879 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1880 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
1882 res
= mono_mb_create_and_cache_full (cache
, sig
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1889 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1891 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1894 MonoDomain
*domain
= mono_domain_get ();
1895 MonoAsyncResult
*ares
;
1896 MonoMethod
*method
= NULL
;
1897 MonoMethodSignature
*sig
;
1898 MonoMethodMessage
*msg
;
1899 MonoObject
*res
, *exc
;
1900 MonoArray
*out_args
;
1903 g_assert (delegate
);
1905 if (!delegate
->method_info
) {
1906 g_assert (delegate
->method
);
1907 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, error
);
1908 if (!mono_error_ok (error
)) {
1909 mono_error_set_pending_exception (error
);
1912 MONO_OBJECT_SETREF_INTERNAL (delegate
, method_info
, rm
);
1915 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
1916 g_assert_not_reached ();
1918 klass
= delegate
->object
.vtable
->klass
;
1920 method
= mono_get_delegate_end_invoke_checked (klass
, error
);
1921 mono_error_assert_ok (error
);
1922 g_assert (method
!= NULL
);
1924 sig
= mono_signature_no_pinvoke (method
);
1926 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, error
);
1927 if (mono_error_set_pending_exception (error
))
1930 ares
= (MonoAsyncResult
*)mono_array_get_internal (msg
->args
, gpointer
, sig
->param_count
- 1);
1932 mono_error_set_remoting (error
, "The async result object is null or of an unexpected type.");
1933 mono_error_set_pending_exception (error
);
1937 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
1938 mono_error_set_invalid_operation (error
,
1939 "%s", "The IAsyncResult object provided does not match this delegate.");
1940 mono_error_set_pending_exception (error
);
1944 #ifndef DISABLE_REMOTING
1945 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1946 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1947 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
1948 if (!mono_error_ok (error
)) {
1949 mono_error_set_pending_exception (error
);
1952 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, error
);
1953 if (mono_error_set_pending_exception (error
))
1955 msg
->call_type
= CallType_EndInvoke
;
1956 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1957 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1958 if (!mono_error_ok (error
)) {
1959 mono_error_set_pending_exception (error
);
1965 res
= mono_threadpool_end_invoke (ares
, &out_args
, &exc
, error
);
1966 if (mono_error_set_pending_exception (error
))
1971 if (((MonoException
*)exc
)->stack_trace
) {
1972 ERROR_DECL (inner_error
);
1973 char *strace
= mono_string_to_utf8_checked_internal (((MonoException
*)exc
)->stack_trace
, inner_error
);
1974 if (is_ok (inner_error
)) {
1976 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
1978 MonoString
*tmp_str
= mono_string_new_checked (domain
, tmp
, inner_error
);
1980 if (is_ok (inner_error
))
1981 MONO_OBJECT_SETREF_INTERNAL (((MonoException
*)exc
), stack_trace
, tmp_str
);
1983 if (!is_ok (inner_error
))
1984 mono_error_cleanup (inner_error
); /* no stack trace, but at least throw the original exception */
1986 mono_set_pending_exception ((MonoException
*)exc
);
1989 mono_method_return_message_restore (method
, params
, out_args
, error
);
1990 mono_error_set_pending_exception (error
);
1994 #ifndef ENABLE_ILGEN
1996 emit_delegate_end_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
2002 * mono_marshal_get_delegate_end_invoke:
2005 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
2007 MonoMethodSignature
*sig
;
2008 MonoMethodBuilder
*mb
;
2012 MonoGenericContext
*ctx
= NULL
;
2013 MonoMethod
*orig_method
= NULL
;
2015 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2016 !strcmp (method
->name
, "EndInvoke"));
2019 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
2021 if (method
->is_inflated
) {
2022 orig_method
= method
;
2023 ctx
= &((MonoMethodInflated
*)method
)->context
;
2024 method
= ((MonoMethodInflated
*)method
)->declaring
;
2027 sig
= mono_signature_no_pinvoke (method
);
2033 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2034 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2038 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_end_invoke_cache
,
2039 (GHashFunc
)mono_signature_hash
,
2040 (GCompareFunc
)mono_metadata_signature_equal
);
2041 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2045 g_assert (sig
->hasthis
);
2047 name
= mono_signature_to_name (sig
, "end_invoke");
2049 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2051 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2054 get_marshal_cb ()->emit_delegate_end_invoke (mb
, sig
);
2056 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
2057 info
->d
.delegate_invoke
.method
= method
;
2061 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2062 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2064 res
= mono_mb_create_and_cache_full (cache
, sig
,
2065 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2074 MonoMethodSignature
*sig
;
2076 } SignaturePointerPair
;
2079 signature_pointer_pair_hash (gconstpointer data
)
2081 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
2083 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
2087 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
2089 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
2090 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
2094 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
2096 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
2098 return pair
->pointer
== user_data
;
2102 free_signature_pointer_pair (SignaturePointerPair
*pair
)
2107 #ifndef ENABLE_ILGEN
2109 mb_skip_visibility_noilgen (MonoMethodBuilder
*mb
)
2114 mb_set_dynamic_noilgen (MonoMethodBuilder
*mb
)
2119 mb_emit_exception_noilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
2124 mb_emit_exception_for_error_noilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
2129 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
)
2135 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
2137 MonoMethodSignature
*sig
, *invoke_sig
;
2138 MonoMethodBuilder
*mb
;
2141 gpointer cache_key
= NULL
;
2142 SignaturePointerPair key
= { NULL
, NULL
};
2143 SignaturePointerPair
*new_key
;
2145 MonoClass
*target_class
= NULL
;
2146 gboolean closed_over_null
= FALSE
;
2147 MonoGenericContext
*ctx
= NULL
;
2148 MonoGenericContainer
*container
= NULL
;
2149 MonoMethod
*orig_method
= method
;
2151 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
2154 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2155 !strcmp (method
->name
, "Invoke"));
2157 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2160 * If the delegate target is null, and the target method is not static, a virtual
2161 * call is made to that method with the first delegate argument as this. This is
2162 * a non-documented .NET feature.
2165 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
2166 if (target_method
->is_inflated
) {
2168 MonoType
*target_type
;
2170 g_assert (method
->signature
->hasthis
);
2171 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
2172 mono_method_get_context (method
), error
);
2173 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
2174 target_class
= mono_class_from_mono_type_internal (target_type
);
2176 target_class
= target_method
->klass
;
2179 closed_over_null
= sig
->param_count
== mono_method_signature_internal (target_method
)->param_count
;
2182 if (static_method_with_first_arg_bound
) {
2183 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
2184 g_assert (!callvirt
);
2185 invoke_sig
= mono_method_signature_internal (target_method
);
2187 * The wrapper has a different lifetime from the method to be invoked.
2188 * If the method is dynamic we don't want to be using its signature
2189 * in the wrapper since it could get freed early.
2191 if (method_is_dynamic (target_method
))
2192 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (target_method
), invoke_sig
);
2196 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
2198 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
2199 ctx
= &((MonoMethodInflated
*)method
)->context
;
2200 method
= ((MonoMethodInflated
*)method
)->declaring
;
2202 container
= mono_method_get_generic_container (method
);
2204 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
2205 g_assert (container
);
2207 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2214 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2215 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2218 cache_key
= method
->klass
;
2219 } else if (static_method_with_first_arg_bound
) {
2220 cache
= get_cache (&get_method_image (target_method
)->delegate_bound_static_invoke_cache
,
2221 (GHashFunc
)mono_signature_hash
,
2222 (GCompareFunc
)mono_metadata_signature_equal
);
2224 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
2226 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
2229 cache_key
= invoke_sig
;
2230 } else if (callvirt
) {
2231 GHashTable
**cache_ptr
;
2233 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
2235 /* We need to cache the signature+method pair */
2236 mono_marshal_lock ();
2238 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
2240 key
.sig
= invoke_sig
;
2241 key
.pointer
= target_method
;
2242 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
2243 mono_marshal_unlock ();
2247 // Inflated methods should not be in this cache because it's not stored on the imageset.
2248 g_assert (!method
->is_inflated
);
2249 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_invoke_cache
,
2250 (GHashFunc
)mono_signature_hash
,
2251 (GCompareFunc
)mono_metadata_signature_equal
);
2252 res
= mono_marshal_find_in_cache (cache
, sig
);
2258 if (!static_method_with_first_arg_bound
) {
2259 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
2260 invoke_sig
->hasthis
= 0;
2263 if (static_method_with_first_arg_bound
)
2264 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
2265 else if (closed_over_null
)
2266 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
2268 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
2270 name
= mono_signature_to_name (invoke_sig
, "invoke");
2272 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2274 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2277 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
);
2279 get_marshal_cb ()->mb_skip_visibility (mb
);
2281 info
= mono_wrapper_info_create (mb
, subtype
);
2282 info
->d
.delegate_invoke
.method
= method
;
2287 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2288 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2289 } else if (callvirt
) {
2290 new_key
= g_new0 (SignaturePointerPair
, 1);
2293 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
2297 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2301 /* mono_method_print_code (res); */
2307 * mono_marshal_get_delegate_invoke:
2308 * The returned method invokes all methods in a multicast delegate.
2311 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
2313 gboolean callvirt
= FALSE
;
2314 gboolean static_method_with_first_arg_bound
= FALSE
;
2315 MonoMethod
*target_method
= NULL
;
2316 MonoMethodSignature
*sig
;
2318 sig
= mono_signature_no_pinvoke (method
);
2320 if (del
&& !del
->target
&& del
->method
&& mono_method_signature_internal (del
->method
)->hasthis
) {
2322 target_method
= del
->method
;
2325 if (del
&& del
->method
&& mono_method_signature_internal (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2326 static_method_with_first_arg_bound
= TRUE
;
2327 target_method
= del
->method
;
2330 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
2334 MonoMethodSignature
*ctor_sig
;
2335 MonoMethodSignature
*sig
;
2338 /* protected by the marshal lock, contains CtorSigPair pointers */
2339 static GSList
*strsig_list
= NULL
;
2341 static MonoMethodSignature
*
2342 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
2344 MonoMethodSignature
*callsig
;
2348 mono_marshal_lock ();
2350 for (item
= strsig_list
; item
; item
= item
->next
) {
2351 cs
= (CtorSigPair
*)item
->data
;
2352 /* mono_metadata_signature_equal () is safe to call with the marshal lock
2353 * because it is lock-free.
2355 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
2360 mono_marshal_unlock ();
2364 static MonoMethodSignature
*
2365 add_string_ctor_signature (MonoMethod
*method
)
2367 MonoMethodSignature
*callsig
;
2370 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2371 callsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2372 cs
= g_new (CtorSigPair
, 1);
2374 cs
->ctor_sig
= mono_method_signature_internal (method
);
2376 mono_marshal_lock ();
2377 strsig_list
= g_slist_prepend (strsig_list
, cs
);
2378 mono_marshal_unlock ();
2383 * mono_marshal_get_string_ctor_signature:
2385 * Return the modified signature used by string ctors (they return the newly created
2388 MonoMethodSignature
*
2389 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
2391 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2393 sig
= add_string_ctor_signature (method
);
2399 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
2402 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2405 /* The result needs loaded indirectly */
2409 /* Can't share this with 'I' as that needs another indirection */
2410 return m_class_get_this_arg (mono_defaults
.int_class
);
2413 if (MONO_TYPE_IS_REFERENCE (t
))
2414 return mono_get_object_type ();
2417 /* The result needs to be boxed */
2422 /* Can't share these as the argument needs to be loaded using sign/zero extension */
2425 return m_class_get_byval_arg (mono_defaults.sbyte_class);
2427 return m_class_get_byval_arg (mono_defaults.int16_class);
2429 return mono_get_int32_type ();
2432 return m_class_get_byval_arg (mono_defaults
.int64_class
);
2433 case MONO_TYPE_BOOLEAN
:
2434 return m_class_get_byval_arg (mono_defaults
.byte_class
);
2435 case MONO_TYPE_CHAR
:
2436 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
2438 return mono_get_int_type ();
2439 case MONO_TYPE_VALUETYPE
:
2440 if (m_class_is_enumtype (t
->data
.klass
)) {
2441 t
= mono_class_enum_basetype_internal (t
->data
.klass
);
2451 * mono_marshal_get_runtime_invoke_sig:
2453 * Return a common signature used for sharing runtime invoke wrappers.
2455 static MonoMethodSignature
*
2456 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
2458 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
2461 res
->generic_param_count
= 0;
2462 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
2463 for (i
= 0; i
< res
->param_count
; ++i
)
2464 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
2470 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
2472 /* Can't share wrappers which return a vtype since it needs to be boxed */
2473 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
))
2476 return mono_metadata_signature_equal (sig1
, sig2
);
2479 struct _MonoWrapperMethodCacheKey
{
2482 gboolean need_direct_wrapper
;
2485 struct _MonoWrapperSignatureCacheKey
{
2486 MonoMethodSignature
*signature
;
2490 typedef struct _MonoWrapperMethodCacheKey MonoWrapperMethodCacheKey
;
2491 typedef struct _MonoWrapperSignatureCacheKey MonoWrapperSignatureCacheKey
;
2494 wrapper_cache_method_key_hash (MonoWrapperMethodCacheKey
*key
)
2496 return mono_aligned_addr_hash (key
->method
) ^ (((!!key
->virtual_
) << 17) | ((!!key
->need_direct_wrapper
) << 19) * 17);
2500 wrapper_cache_signature_key_hash (MonoWrapperSignatureCacheKey
*key
)
2502 return mono_signature_hash (key
->signature
) ^ (((!!key
->valuetype
) << 18) * 17);
2506 wrapper_cache_method_key_equal (MonoWrapperMethodCacheKey
*key1
, MonoWrapperMethodCacheKey
*key2
)
2508 if (key1
->virtual_
!= key2
->virtual_
|| key1
->need_direct_wrapper
!= key2
->need_direct_wrapper
)
2510 return key1
->method
== key2
->method
;
2514 wrapper_cache_signature_key_equal (MonoWrapperSignatureCacheKey
*key1
, MonoWrapperSignatureCacheKey
*key2
)
2516 if (key1
->valuetype
!= key2
->valuetype
)
2518 return runtime_invoke_signature_equal (key1
->signature
, key2
->signature
);
2522 * mono_marshal_get_runtime_invoke:
2523 * Generates IL code for the runtime invoke function:
2525 * <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
2527 * We also catch exceptions if \p exc is not NULL.
2528 * If \p virtual is TRUE, then \p method is invoked virtually on \p this. This is useful since
2529 * it means that the compiled code for \p method does not have to be looked up
2530 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
2531 * its \p method argument.
2534 mono_marshal_get_runtime_invoke_full (MonoMethod
*method
, gboolean virtual_
, gboolean need_direct_wrapper
)
2536 MonoMethodSignature
*sig
, *csig
, *callsig
;
2537 MonoMethodBuilder
*mb
;
2538 GHashTable
*method_cache
= NULL
, *sig_cache
= NULL
;
2539 GHashTable
**cache_table
= NULL
;
2540 MonoClass
*target_klass
;
2541 MonoMethod
*res
= NULL
;
2542 static MonoMethodSignature
*cctor_signature
= NULL
;
2543 static MonoMethodSignature
*finalize_signature
= NULL
;
2545 const char *param_names
[16];
2547 MonoWrapperMethodCacheKey
*method_key
;
2548 MonoWrapperMethodCacheKey method_key_lookup_only
;
2549 memset (&method_key_lookup_only
, 0, sizeof (method_key_lookup_only
));
2550 method_key_lookup_only
.method
= method
;
2551 method_key_lookup_only
.virtual_
= virtual_
;
2552 method_key_lookup_only
.need_direct_wrapper
= need_direct_wrapper
;
2553 method_key
= &method_key_lookup_only
;
2557 if (!cctor_signature
) {
2558 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2559 cctor_signature
->ret
= mono_get_void_type ();
2561 if (!finalize_signature
) {
2562 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2563 finalize_signature
->ret
= mono_get_void_type ();
2564 finalize_signature
->hasthis
= 1;
2567 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_method_cache
;
2568 method_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_method_key_hash
, (GCompareFunc
) wrapper_cache_method_key_equal
);
2570 res
= mono_marshal_find_in_cache (method_cache
, method_key
);
2574 if (method
->string_ctor
) {
2575 callsig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2577 callsig
= add_string_ctor_signature (method
);
2579 if (method_is_dynamic (method
))
2580 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2582 callsig
= mono_method_signature_internal (method
);
2585 sig
= mono_method_signature_internal (method
);
2587 target_klass
= get_wrapper_target_class (m_class_get_image (method
->klass
));
2589 /* Try to share wrappers for non-corlib methods with simple signatures */
2590 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
2591 callsig
= cctor_signature
;
2592 target_klass
= mono_defaults
.object_class
;
2593 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
2594 callsig
= finalize_signature
;
2595 target_klass
= mono_defaults
.object_class
;
2598 if (need_direct_wrapper
|| virtual_
) {
2599 /* Already searched at the start. We cannot cache those wrappers based
2600 * on signatures because they contain a reference to the method */
2602 MonoMethodSignature
*tmp_sig
;
2604 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
2605 MonoWrapperSignatureCacheKey sig_key
;
2606 memset (&sig_key
, 0, sizeof (sig_key
));
2607 sig_key
.signature
= callsig
;
2608 sig_key
.valuetype
= m_class_is_valuetype (method
->klass
);
2610 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_signature_cache
;
2611 sig_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_signature_key_hash
, (GCompareFunc
) wrapper_cache_signature_key_equal
);
2613 /* from mono_marshal_find_in_cache */
2614 mono_marshal_lock ();
2615 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, &sig_key
);
2616 mono_marshal_unlock ();
2623 /* Make a copy of the signature from the image mempool */
2625 callsig
= mono_metadata_signature_dup_full (m_class_get_image (target_klass
), callsig
);
2629 csig
= mono_metadata_signature_alloc (m_class_get_image (target_klass
), 4);
2631 MonoType
*object_type
= mono_get_object_type ();
2632 MonoType
*int_type
= mono_get_int_type ();
2634 csig
->ret
= object_type
;
2635 if (m_class_is_valuetype (method
->klass
) && mono_method_signature_internal (method
)->hasthis
)
2636 csig
->params
[0] = get_runtime_invoke_type (m_class_get_this_arg (method
->klass
), FALSE
);
2638 csig
->params
[0] = object_type
;
2639 csig
->params
[1] = int_type
;
2640 csig
->params
[2] = int_type
;
2641 csig
->params
[3] = int_type
;
2644 /* This is called from runtime code so it has to be cdecl */
2645 csig
->call_convention
= MONO_CALL_C
;
2648 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : (need_direct_wrapper
? "runtime_invoke_direct" : "runtime_invoke"));
2649 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2652 param_names
[0] = "this";
2653 param_names
[1] = "params";
2654 param_names
[2] = "exc";
2655 param_names
[3] = "method";
2657 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, m_class_get_image (target_klass
), method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
2659 method_key
= g_new (MonoWrapperMethodCacheKey
, 1);
2660 memcpy (method_key
, &method_key_lookup_only
, sizeof (MonoWrapperMethodCacheKey
));
2662 if (need_direct_wrapper
|| virtual_
) {
2663 get_marshal_cb ()->mb_skip_visibility (mb
);
2664 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
2665 info
->d
.runtime_invoke
.method
= method
;
2666 res
= mono_mb_create_and_cache_full (method_cache
, method_key
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
2668 MonoWrapperSignatureCacheKey
*sig_key
= g_new0 (MonoWrapperSignatureCacheKey
, 1);
2669 sig_key
->signature
= callsig
;
2670 sig_key
->valuetype
= m_class_is_valuetype (method
->klass
);
2672 /* taken from mono_mb_create_and_cache */
2673 mono_marshal_lock ();
2674 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2675 mono_marshal_unlock ();
2677 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2678 info
->d
.runtime_invoke
.sig
= callsig
;
2680 /* Somebody may have created it before us */
2683 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2685 mono_marshal_lock ();
2686 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2689 g_hash_table_insert (sig_cache
, sig_key
, res
);
2690 g_hash_table_insert (method_cache
, method_key
, res
);
2692 mono_free_method (newm
);
2694 g_free (method_key
);
2696 mono_marshal_unlock ();
2699 g_free (method_key
);
2702 /* end mono_mb_create_and_cache */
2711 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
2713 gboolean need_direct_wrapper
= FALSE
;
2716 need_direct_wrapper
= TRUE
;
2718 if (method
->dynamic
)
2719 need_direct_wrapper
= TRUE
;
2721 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2722 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2724 * Array Get/Set/Address methods. The JIT implements them using inline code
2725 * so we need to create an invoke wrapper which calls the method directly.
2727 need_direct_wrapper
= TRUE
;
2730 if (method
->string_ctor
) {
2731 /* Can't share this as we push a string as this */
2732 need_direct_wrapper
= TRUE
;
2735 return mono_marshal_get_runtime_invoke_full (method
, virtual_
, need_direct_wrapper
);
2738 #ifndef ENABLE_ILGEN
2740 emit_runtime_invoke_body_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
2741 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
2742 gboolean virtual_
, gboolean need_direct_wrapper
)
2747 emit_runtime_invoke_dynamic_noilgen (MonoMethodBuilder
*mb
)
2753 * mono_marshal_get_runtime_invoke_dynamic:
2755 * Return a method which can be used to invoke managed methods from native code
2757 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
2758 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
2759 * ARGS should point to an architecture specific structure containing
2760 * the arguments and space for the return value.
2761 * The other arguments are the same as for runtime_invoke (), except that
2762 * ARGS should contain the this argument too.
2763 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
2764 * is only one copy of it, which is useful in full-aot.
2767 mono_marshal_get_runtime_invoke_dynamic (void)
2769 static MonoMethod
*method
;
2770 MonoMethodSignature
*csig
;
2771 MonoMethodBuilder
*mb
;
2778 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
2780 MonoType
*void_type
= mono_get_void_type ();
2781 MonoType
*int_type
= mono_get_int_type ();
2783 csig
->ret
= void_type
;
2784 csig
->params
[0] = int_type
;
2785 csig
->params
[1] = int_type
;
2786 csig
->params
[2] = int_type
;
2787 csig
->params
[3] = int_type
;
2789 name
= g_strdup ("runtime_invoke_dynamic");
2790 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2793 get_marshal_cb ()->emit_runtime_invoke_dynamic (mb
);
2795 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
2797 mono_marshal_lock ();
2798 /* double-checked locking */
2800 method
= mono_mb_create (mb
, csig
, 16, info
);
2802 mono_marshal_unlock ();
2810 * mono_marshal_get_runtime_invoke_for_sig:
2812 * Return a runtime invoke wrapper for a given signature.
2815 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
2817 MonoMethodSignature
*csig
, *callsig
;
2818 MonoMethodBuilder
*mb
;
2820 GHashTable
*cache
= NULL
;
2821 GHashTable
**cache_table
= NULL
;
2822 MonoMethod
*res
= NULL
;
2824 const char *param_names
[16];
2827 /* A simplified version of mono_marshal_get_runtime_invoke */
2829 image
= mono_defaults
.corlib
;
2831 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
2833 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
2835 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
2836 (GCompareFunc
)runtime_invoke_signature_equal
);
2838 /* from mono_marshal_find_in_cache */
2839 mono_marshal_lock ();
2840 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2841 mono_marshal_unlock ();
2848 /* Make a copy of the signature from the image mempool */
2849 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
2851 MonoType
*object_type
= mono_get_object_type ();
2852 MonoType
*int_type
= mono_get_int_type ();
2853 csig
= mono_metadata_signature_alloc (image
, 4);
2854 csig
->ret
= object_type
;
2855 csig
->params
[0] = object_type
;
2856 csig
->params
[1] = int_type
;
2857 csig
->params
[2] = int_type
;
2858 csig
->params
[3] = int_type
;
2861 /* This is called from runtime code so it has to be cdecl */
2862 csig
->call_convention
= MONO_CALL_C
;
2865 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
2866 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2869 param_names
[0] = "this";
2870 param_names
[1] = "params";
2871 param_names
[2] = "exc";
2872 param_names
[3] = "method";
2874 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
2876 /* taken from mono_mb_create_and_cache */
2877 mono_marshal_lock ();
2878 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2879 mono_marshal_unlock ();
2881 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2882 info
->d
.runtime_invoke
.sig
= callsig
;
2884 /* Somebody may have created it before us */
2887 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2889 mono_marshal_lock ();
2890 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2893 g_hash_table_insert (cache
, callsig
, res
);
2895 mono_free_method (newm
);
2897 mono_marshal_unlock ();
2900 /* end mono_mb_create_and_cache */
2907 #ifndef ENABLE_ILGEN
2909 emit_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
2914 emit_return_noilgen (MonoMethodBuilder
*mb
)
2920 * mono_marshal_get_icall_wrapper:
2921 * Generates IL code for the JIT icall wrapper. The generated method
2922 * calls the unmanaged code in \p callinfo->func.
2925 mono_marshal_get_icall_wrapper (MonoJitICallInfo
*callinfo
, gboolean check_exceptions
)
2927 MonoMethodSignature
*csig
, *csig2
;
2928 MonoMethodBuilder
*mb
;
2932 gconstpointer
const func
= callinfo
->func
;
2934 GHashTable
*cache
= get_cache (& m_class_get_image (mono_defaults
.object_class
)->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
2935 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
2938 MonoMethodSignature
*const sig
= callinfo
->sig
;
2939 g_assert (sig
->pinvoke
);
2941 char *const name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
2942 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
2944 mb
->method
->save_lmf
= 1;
2946 /* Add an explicit this argument */
2948 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
2950 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2952 get_marshal_cb ()->emit_icall_wrapper (mb
, callinfo
, csig2
, check_exceptions
);
2954 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2956 if (csig
->call_convention
== MONO_CALL_VARARG
)
2957 csig
->call_convention
= 0;
2959 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
2960 info
->d
.icall
.jit_icall_id
= mono_jit_icall_info_id (callinfo
);
2961 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
2969 mono_marshal_get_aot_init_wrapper_name (MonoAotInitSubtype subtype
)
2971 const char *name
= NULL
;
2973 case AOT_INIT_METHOD
:
2974 name
= "init_method";
2976 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
2977 name
= "init_method_gshared_mrgctx";
2979 case AOT_INIT_METHOD_GSHARED_THIS
:
2980 name
= "init_method_gshared_this";
2982 case AOT_INIT_METHOD_GSHARED_VTABLE
:
2983 name
= "init_method_gshared_vtable";
2986 g_assert_not_reached ();
2992 mono_marshal_get_aot_init_wrapper (MonoAotInitSubtype subtype
)
2994 MonoMethodBuilder
*mb
;
2997 MonoMethodSignature
*csig
= NULL
;
2998 MonoType
*void_type
= mono_get_void_type ();
2999 MonoType
*int_type
= mono_get_int_type ();
3000 const char *name
= mono_marshal_get_aot_init_wrapper_name (subtype
);
3003 case AOT_INIT_METHOD
:
3004 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
3005 csig
->ret
= void_type
;
3006 csig
->params
[0] = int_type
;
3007 csig
->params
[1] = int_type
;
3009 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
3010 case AOT_INIT_METHOD_GSHARED_THIS
:
3011 case AOT_INIT_METHOD_GSHARED_VTABLE
:
3012 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3013 csig
->ret
= void_type
;
3014 csig
->params
[0] = int_type
;
3015 csig
->params
[1] = int_type
;
3016 csig
->params
[2] = int_type
;
3019 g_assert_not_reached ();
3022 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
3024 // Just stub out the method with a "CEE_RET"
3025 // Our codegen backend generates other code here
3026 get_marshal_cb ()->emit_return (mb
);
3028 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_AOT_INIT
);
3029 info
->d
.aot_init
.subtype
= subtype
;
3030 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
3036 #ifndef ENABLE_ILGEN
3038 emit_marshal_custom_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3039 MonoMarshalSpec
*spec
,
3040 int conv_arg
, MonoType
**conv_arg_type
,
3041 MarshalAction action
)
3043 MonoType
*int_type
= mono_get_int_type ();
3044 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
3045 *conv_arg_type
= int_type
;
3050 emit_marshal_asany_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3051 MonoMarshalSpec
*spec
,
3052 int conv_arg
, MonoType
**conv_arg_type
,
3053 MarshalAction action
)
3059 emit_marshal_vtype_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3060 MonoMarshalSpec
*spec
,
3061 int conv_arg
, MonoType
**conv_arg_type
,
3062 MarshalAction action
)
3068 emit_marshal_string_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3069 MonoMarshalSpec
*spec
,
3070 int conv_arg
, MonoType
**conv_arg_type
,
3071 MarshalAction action
)
3073 MonoType
*int_type
= mono_get_int_type ();
3075 case MARSHAL_ACTION_CONV_IN
:
3076 *conv_arg_type
= int_type
;
3078 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3079 *conv_arg_type
= int_type
;
3087 emit_marshal_safehandle_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3088 MonoMarshalSpec
*spec
, int conv_arg
,
3089 MonoType
**conv_arg_type
, MarshalAction action
)
3091 MonoType
*int_type
= mono_get_int_type ();
3092 if (action
== MARSHAL_ACTION_CONV_IN
)
3093 *conv_arg_type
= int_type
;
3099 emit_marshal_handleref_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3100 MonoMarshalSpec
*spec
, int conv_arg
,
3101 MonoType
**conv_arg_type
, MarshalAction action
)
3103 MonoType
*int_type
= mono_get_int_type ();
3104 if (action
== MARSHAL_ACTION_CONV_IN
)
3105 *conv_arg_type
= int_type
;
3111 emit_marshal_object_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3112 MonoMarshalSpec
*spec
,
3113 int conv_arg
, MonoType
**conv_arg_type
,
3114 MarshalAction action
)
3116 MonoType
*int_type
= mono_get_int_type ();
3117 if (action
== MARSHAL_ACTION_CONV_IN
)
3118 *conv_arg_type
= int_type
;
3123 emit_marshal_variant_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3124 MonoMarshalSpec
*spec
,
3125 int conv_arg
, MonoType
**conv_arg_type
,
3126 MarshalAction action
)
3128 g_assert_not_reached ();
3133 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
3135 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
3136 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
3138 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
3140 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
3150 #ifndef ENABLE_ILGEN
3152 emit_marshal_array_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3153 MonoMarshalSpec
*spec
,
3154 int conv_arg
, MonoType
**conv_arg_type
,
3155 MarshalAction action
)
3157 MonoType
*int_type
= mono_get_int_type ();
3158 MonoType
*object_type
= mono_get_object_type ();
3160 case MARSHAL_ACTION_CONV_IN
:
3161 *conv_arg_type
= object_type
;
3163 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3164 *conv_arg_type
= int_type
;
3172 mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
3175 return mono_get_int32_type ();
3177 switch (spec
->native
) {
3178 case MONO_NATIVE_I1
:
3179 case MONO_NATIVE_U1
:
3180 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3181 case MONO_NATIVE_VARIANTBOOL
:
3182 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
3183 return m_class_get_byval_arg (mono_defaults
.int16_class
);
3184 case MONO_NATIVE_BOOLEAN
:
3185 return mono_get_int32_type ();
3187 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3188 return mono_get_int32_type ();
3194 mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
3196 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3198 switch (spec
->native
) {
3199 case MONO_NATIVE_I1
:
3200 case MONO_NATIVE_U1
:
3201 conv_arg_class
= mono_defaults
.byte_class
;
3202 if (ldop
) *ldop
= CEE_LDIND_I1
;
3204 case MONO_NATIVE_VARIANTBOOL
:
3205 conv_arg_class
= mono_defaults
.int16_class
;
3206 if (ldop
) *ldop
= CEE_LDIND_I2
;
3208 case MONO_NATIVE_BOOLEAN
:
3211 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3214 return conv_arg_class
;
3217 #ifndef ENABLE_ILGEN
3219 emit_marshal_boolean_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3220 MonoMarshalSpec
*spec
,
3221 int conv_arg
, MonoType
**conv_arg_type
,
3222 MarshalAction action
)
3224 MonoType
*int_type
= mono_get_int_type ();
3226 case MARSHAL_ACTION_CONV_IN
:
3228 *conv_arg_type
= int_type
;
3230 *conv_arg_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, NULL
);
3233 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3234 MonoClass
* conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
3236 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3238 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3247 emit_marshal_ptr_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3248 MonoMarshalSpec
*spec
, int conv_arg
,
3249 MonoType
**conv_arg_type
, MarshalAction action
)
3255 emit_marshal_char_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3256 MonoMarshalSpec
*spec
, int conv_arg
,
3257 MonoType
**conv_arg_type
, MarshalAction action
)
3263 emit_marshal_scalar_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3264 MonoMarshalSpec
*spec
, int conv_arg
,
3265 MonoType
**conv_arg_type
, MarshalAction action
)
3272 mono_emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3273 MonoMarshalSpec
*spec
, int conv_arg
,
3274 MonoType
**conv_arg_type
, MarshalAction action
)
3276 /* Ensure that we have marshalling info for this param */
3277 mono_marshal_load_type_info (mono_class_from_mono_type_internal (t
));
3279 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
3280 return get_marshal_cb ()->emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3282 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
3283 return get_marshal_cb ()->emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3286 case MONO_TYPE_VALUETYPE
:
3287 if (t
->data
.klass
== mono_class_try_get_handleref_class ())
3288 return get_marshal_cb ()->emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3290 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3291 case MONO_TYPE_STRING
:
3292 return get_marshal_cb ()->emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3293 case MONO_TYPE_CLASS
:
3294 case MONO_TYPE_OBJECT
:
3295 #if !defined(DISABLE_COM)
3296 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
3297 return get_marshal_cb ()->emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3300 #if !defined(DISABLE_COM)
3301 if ((spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
3302 spec
->native
== MONO_NATIVE_IDISPATCH
||
3303 spec
->native
== MONO_NATIVE_INTERFACE
)) ||
3304 (t
->type
== MONO_TYPE_CLASS
&& mono_cominterop_is_interface(t
->data
.klass
)))
3305 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3306 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
3307 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
3308 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
3309 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3312 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
3313 mono_class_is_subclass_of_internal (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
3314 return get_marshal_cb ()->emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3316 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3317 case MONO_TYPE_ARRAY
:
3318 case MONO_TYPE_SZARRAY
:
3319 return get_marshal_cb ()->emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3320 case MONO_TYPE_BOOLEAN
:
3321 return get_marshal_cb ()->emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3323 return get_marshal_cb ()->emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3324 case MONO_TYPE_CHAR
:
3325 return get_marshal_cb ()->emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3338 case MONO_TYPE_FNPTR
:
3339 return get_marshal_cb ()->emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3340 case MONO_TYPE_GENERICINST
:
3341 if (mono_type_generic_inst_is_valuetype (t
))
3342 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3344 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3350 #ifndef ENABLE_ILGEN
3352 emit_create_string_hack_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
3357 emit_native_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*pinfo
)
3363 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean set_default
)
3365 MonoMethodSignature
*sig
;
3370 * Under windows, delegates passed to native code must use the STDCALL
3371 * calling convention.
3374 csig
->call_convention
= MONO_CALL_STDCALL
;
3377 sig
= mono_method_signature_internal (method
);
3381 cmod_count
= mono_type_custom_modifier_count (sig
->ret
);
3383 /* Change default calling convention if needed */
3384 /* Why is this a modopt ? */
3385 if (cmod_count
== 0)
3388 for (i
= 0; i
< cmod_count
; ++i
) {
3391 MonoType
*cmod_type
= mono_type_get_custom_modifier (sig
->ret
, i
, &required
, error
);
3392 mono_error_assert_ok (error
);
3393 MonoClass
*cmod_class
= mono_class_from_mono_type_internal (cmod_type
);
3394 if ((m_class_get_image (cmod_class
) == mono_defaults
.corlib
) && !strcmp (m_class_get_name_space (cmod_class
), "System.Runtime.CompilerServices")) {
3395 const char *cmod_class_name
= m_class_get_name (cmod_class
);
3396 if (!strcmp (cmod_class_name
, "CallConvCdecl"))
3397 csig
->call_convention
= MONO_CALL_C
;
3398 else if (!strcmp (cmod_class_name
, "CallConvStdcall"))
3399 csig
->call_convention
= MONO_CALL_STDCALL
;
3400 else if (!strcmp (cmod_class_name
, "CallConvFastcall"))
3401 csig
->call_convention
= MONO_CALL_FASTCALL
;
3402 else if (!strcmp (cmod_class_name
, "CallConvThiscall"))
3403 csig
->call_convention
= MONO_CALL_THISCALL
;
3409 * mono_marshal_get_native_wrapper:
3410 * \param method The \c MonoMethod to wrap.
3411 * \param check_exceptions Whenever to check for pending exceptions
3413 * Generates IL code for the pinvoke wrapper. The generated method
3414 * calls the unmanaged code in \c piinfo->addr.
3417 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
3419 MonoMethodSignature
*sig
, *csig
;
3420 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
3421 MonoMethodBuilder
*mb
;
3422 MonoMarshalSpec
**mspecs
;
3425 gboolean pinvoke
= FALSE
;
3428 ERROR_DECL (emitted_error
);
3431 g_assert (method
!= NULL
);
3432 g_assert (mono_method_signature_internal (method
)->pinvoke
);
3434 GHashTable
**cache_ptr
;
3436 MonoType
*string_type
= m_class_get_byval_arg (mono_defaults
.string_class
);
3439 if (check_exceptions
)
3440 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
3442 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
3444 if (check_exceptions
)
3445 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
3447 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
3450 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
3452 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3455 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
3456 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
3460 return mono_cominterop_get_native_wrapper (method
);
3462 g_assert_not_reached ();
3466 sig
= mono_method_signature_internal (method
);
3468 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3469 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
3472 if (!piinfo
->addr
) {
3474 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
3475 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "Method contains unsupported native code");
3477 mono_lookup_pinvoke_call_internal (method
, emitted_error
);
3479 if (!aot
|| (method
->klass
== mono_defaults
.string_class
))
3480 piinfo
->addr
= mono_lookup_internal_call (method
);
3484 /* hack - redirect certain string constructors to CreateString */
3485 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
3486 g_assert (!pinvoke
);
3487 g_assert (method
->string_ctor
);
3488 g_assert (sig
->hasthis
);
3490 /* CreateString returns a value */
3491 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3492 csig
->ret
= string_type
;
3496 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
3497 if (!strcmp ("CreateString", res
->name
) &&
3498 mono_metadata_signature_equal (csig
, mono_method_signature_internal (res
))) {
3501 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
3502 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
3504 /* create a wrapper to preserve .ctor in stack trace */
3505 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
3507 get_marshal_cb ()->emit_create_string_hack (mb
, csig
, res
);
3509 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
3510 info
->d
.string_ctor
.method
= method
;
3512 /* use native_wrapper_cache because internal calls are looked up there */
3513 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3514 csig
->param_count
+ 1, info
, NULL
);
3521 /* exception will be thrown */
3522 piinfo
->addr
= NULL
;
3523 g_warning ("cannot find CreateString for .ctor");
3526 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3528 mb
->method
->save_lmf
= 1;
3531 * In AOT mode and embedding scenarios, it is possible that the icall is not
3532 * registered in the runtime doing the AOT compilation.
3534 if (!piinfo
->addr
&& !aot
) {
3535 /* if there's no code but the error isn't set, just use a fairly generic exception. */
3536 if (is_ok (emitted_error
))
3537 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "");
3538 get_marshal_cb ()->mb_emit_exception_for_error (mb
, emitted_error
);
3539 mono_error_cleanup (emitted_error
);
3541 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3542 info
->d
.managed_to_native
.method
= method
;
3544 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3546 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3547 csig
->param_count
+ 16, info
, NULL
);
3553 g_assert (is_ok (emitted_error
));
3555 /* internal calls: we simply push all arguments and call the method (no conversions) */
3556 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
3558 csig
= mono_metadata_signature_dup_add_this (get_method_image (method
), sig
, method
->klass
);
3560 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3562 //printf ("%s\n", mono_method_full_name (method, 1));
3564 /* hack - string constructors returns a value */
3565 if (method
->string_ctor
)
3566 csig
->ret
= string_type
;
3568 get_marshal_cb ()->emit_native_icall_wrapper (mb
, method
, csig
, check_exceptions
, aot
, piinfo
);
3570 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3571 info
->d
.managed_to_native
.method
= method
;
3573 csig
= mono_metadata_signature_dup_full (get_method_image (method
), csig
);
3575 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3584 g_assert (piinfo
->addr
);
3586 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3587 mono_marshal_set_callconv_from_modopt (method
, csig
, FALSE
);
3589 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
3590 mono_method_get_marshal_info (method
, mspecs
);
3592 mono_marshal_emit_native_wrapper (get_method_image (mb
->method
), mb
, csig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
);
3593 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
3594 info
->d
.managed_to_native
.method
= method
;
3597 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3601 for (i
= sig
->param_count
; i
>= 0; i
--)
3603 mono_metadata_free_marshal_spec (mspecs
[i
]);
3606 /* mono_method_print_code (res); */
3612 * mono_marshal_get_native_func_wrapper:
3613 * \param image The image to use for memory allocation and for looking up custom marshallers.
3614 * \param sig The signature of the function
3615 * \param func The native function to wrap
3617 * \returns a wrapper method around native functions, similar to the pinvoke
3621 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
3622 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
3624 MonoMethodSignature
*csig
;
3626 SignaturePointerPair key
, *new_key
;
3627 MonoMethodBuilder
*mb
;
3636 // Generic types are not safe to place in MonoImage caches.
3637 g_assert (!sig
->is_inflated
);
3639 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
3640 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
3643 name
= g_strdup_printf ("wrapper_native_%p", func
);
3644 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3645 mb
->method
->save_lmf
= 1;
3647 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
);
3649 csig
= mono_metadata_signature_dup_full (image
, sig
);
3652 new_key
= g_new (SignaturePointerPair
,1);
3653 new_key
->sig
= csig
;
3654 new_key
->pointer
= func
;
3656 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
3662 mono_marshal_set_wrapper_info (res
, NULL
);
3668 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
3672 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
3674 MonoMethodSignature
*sig
, *csig
;
3675 MonoMethodBuilder
*mb
;
3680 MonoMethodPInvoke mpiinfo
;
3681 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
3682 MonoMarshalSpec
**mspecs
;
3683 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
3684 MonoImage
*image
= get_method_image (invoke
);
3687 // FIXME: include UnmanagedFunctionPointerAttribute info
3690 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
3692 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
3694 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
3697 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
3698 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
3700 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3701 mono_method_get_marshal_info (invoke
, mspecs
);
3702 /* Freed below so don't alloc from mempool */
3703 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
3706 name
= g_strdup_printf ("wrapper_aot_native");
3707 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3708 mb
->method
->save_lmf
= 1;
3710 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
);
3712 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
3713 info
->d
.managed_to_native
.method
= invoke
;
3715 g_assert (!sig
->hasthis
);
3716 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
3718 res
= mono_mb_create_and_cache_full (cache
, invoke
,
3719 mb
, csig
, csig
->param_count
+ 16,
3723 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3725 mono_metadata_free_marshal_spec (mspecs
[i
]);
3733 * mono_marshal_emit_managed_wrapper:
3735 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
3736 * the delegate which wraps the managed method to be called. For closed delegates,
3737 * it could have fewer parameters than the method it wraps.
3738 * THIS_LOC is the memory location where the target of the delegate is stored.
3741 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3743 get_marshal_cb ()->emit_managed_wrapper (mb
, invoke_sig
, mspecs
, m
, method
, target_handle
);
3746 #ifndef ENABLE_ILGEN
3748 emit_managed_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3750 MonoMethodSignature
*sig
, *csig
;
3752 MonoType
*int_type
= mono_get_int_type ();
3757 /* we first do all conversions */
3758 for (i
= 0; i
< sig
->param_count
; i
++) {
3759 MonoType
*t
= sig
->params
[i
];
3762 case MONO_TYPE_OBJECT
:
3763 case MONO_TYPE_CLASS
:
3764 case MONO_TYPE_VALUETYPE
:
3765 case MONO_TYPE_ARRAY
:
3766 case MONO_TYPE_SZARRAY
:
3767 case MONO_TYPE_STRING
:
3768 case MONO_TYPE_BOOLEAN
:
3769 mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
3773 if (!sig
->ret
->byref
) {
3774 switch (sig
->ret
->type
) {
3775 case MONO_TYPE_STRING
:
3776 csig
->ret
= int_type
;
3786 * mono_marshal_get_managed_wrapper:
3787 * Generates IL code to call managed methods from unmanaged code
3788 * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
3791 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
, MonoError
*error
)
3793 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
3794 MonoMethodBuilder
*mb
;
3795 MonoMethod
*res
, *invoke
;
3796 MonoMarshalSpec
**mspecs
;
3797 MonoMethodPInvoke piinfo
;
3800 EmitMarshalContext m
;
3802 g_assert (method
!= NULL
);
3805 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3806 mono_error_set_invalid_program (error
, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method
, TRUE
));
3811 * FIXME: Should cache the method+delegate type pair, since the same method
3812 * could be called with different delegates, thus different marshalling
3815 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
3817 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
3820 invoke
= mono_get_delegate_invoke_internal (delegate_klass
);
3821 invoke_sig
= mono_method_signature_internal (invoke
);
3823 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3824 mono_method_get_marshal_info (invoke
, mspecs
);
3826 sig
= mono_method_signature_internal (method
);
3828 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3830 /*the target gchandle must be the first entry after size and the wrapper itself.*/
3831 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
3833 /* we copy the signature, so that we can modify it */
3835 /* Need to free this later */
3836 csig
= mono_metadata_signature_dup (invoke_sig
);
3838 csig
= mono_metadata_signature_dup_full (get_method_image (method
), invoke_sig
);
3842 memset (&m
, 0, sizeof (m
));
3848 m
.image
= get_method_image (method
);
3850 mono_marshal_set_callconv_from_modopt (invoke
, csig
, TRUE
);
3852 /* The attribute is only available in Net 2.0 */
3853 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
3854 MonoCustomAttrInfo
*cinfo
;
3855 MonoCustomAttrEntry
*attr
;
3858 * The pinvoke attributes are stored in a real custom attribute. Obtain the
3859 * contents of the attribute without constructing it, as that might not be
3860 * possible when running in cross-compiling mode.
3862 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, error
);
3863 mono_error_assert_ok (error
);
3866 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3867 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3868 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
3869 attr
= &cinfo
->attrs
[i
];
3875 gpointer
*typed_args
, *named_args
;
3876 CattrNamedArg
*arginfo
;
3879 MonoBoolean set_last_error
= 0;
3883 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
3884 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
3885 g_assert (mono_error_ok (error
));
3888 call_conv
= *(gint32
*)typed_args
[0];
3890 for (i
= 0; i
< num_named_args
; ++i
) {
3891 CattrNamedArg
*narg
= &arginfo
[i
];
3893 g_assert (narg
->field
);
3894 if (!strcmp (narg
->field
->name
, "CharSet")) {
3895 charset
= *(gint32
*)named_args
[i
];
3896 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
3897 set_last_error
= *(MonoBoolean
*)named_args
[i
];
3898 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
3899 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox_internal (o);
3900 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
3901 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox_internal (o);
3903 g_assert_not_reached ();
3906 g_free (typed_args
);
3907 g_free (named_args
);
3910 memset (&piinfo
, 0, sizeof (piinfo
));
3912 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
3914 csig
->call_convention
= call_conv
- 1;
3917 if (cinfo
&& !cinfo
->cached
)
3918 mono_custom_attrs_free (cinfo
);
3921 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
3923 if (!target_handle
) {
3926 // FIXME: Associate it with the method+delegate_klass pair
3927 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3928 info
->d
.native_to_managed
.method
= method
;
3929 info
->d
.native_to_managed
.klass
= delegate_klass
;
3931 res
= mono_mb_create_and_cache_full (cache
, method
,
3932 mb
, csig
, sig
->param_count
+ 16,
3935 get_marshal_cb ()->mb_set_dynamic (mb
);
3936 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
3940 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3942 mono_metadata_free_marshal_spec (mspecs
[i
]);
3945 /* mono_method_print_code (res); */
3950 #ifndef ENABLE_ILGEN
3952 emit_vtfixup_ftnptr_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
3958 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
3962 MonoMethodSignature
*sig
;
3963 MonoMethodBuilder
*mb
;
3968 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, error
);
3970 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (error
));
3973 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
3974 MonoMethodSignature
*csig
;
3975 MonoMarshalSpec
**mspecs
;
3976 EmitMarshalContext m
;
3978 sig
= mono_method_signature_internal (method
);
3979 g_assert (!sig
->hasthis
);
3981 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
3982 mono_method_get_marshal_info (method
, mspecs
);
3984 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3985 csig
= mono_metadata_signature_dup_full (image
, sig
);
3989 memset (&m
, 0, sizeof (m
));
3997 mono_marshal_set_callconv_from_modopt (method
, csig
, TRUE
);
3999 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
4001 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
4003 get_marshal_cb ()->mb_set_dynamic (mb
);
4004 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
4007 for (i
= sig
->param_count
; i
>= 0; i
--)
4009 mono_metadata_free_marshal_spec (mspecs
[i
]);
4012 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4013 mono_error_assert_ok (error
);
4014 return compiled_ptr
;
4017 sig
= mono_method_signature_internal (method
);
4018 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4020 param_count
= sig
->param_count
+ sig
->hasthis
;
4021 get_marshal_cb ()->emit_vtfixup_ftnptr (mb
, method
, param_count
, type
);
4022 get_marshal_cb ()->mb_set_dynamic (mb
);
4024 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
4027 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4028 mono_error_assert_ok (error
);
4029 return compiled_ptr
;
4032 #ifndef ENABLE_ILGEN
4034 emit_castclass_noilgen (MonoMethodBuilder
*mb
)
4040 * mono_marshal_get_castclass_with_cache:
4041 * This does the equivalent of \c mono_object_castclass_with_cache.
4044 mono_marshal_get_castclass_with_cache (void)
4046 static MonoMethod
*cached
;
4048 MonoMethodBuilder
*mb
;
4049 MonoMethodSignature
*sig
;
4055 MonoType
*object_type
= mono_get_object_type ();
4056 MonoType
*int_type
= mono_get_int_type ();
4058 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
4059 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4060 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4061 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4062 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4063 sig
->ret
= object_type
;
4066 get_marshal_cb ()->emit_castclass (mb
);
4068 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
4069 res
= mono_mb_create (mb
, sig
, 8, info
);
4072 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4073 mono_free_method (res
);
4074 mono_metadata_free_method_signature (sig
);
4081 /* this is an icall */
4083 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
4086 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, error
);
4087 if (mono_error_set_pending_exception (error
))
4090 if (mono_object_is_transparent_proxy (obj
))
4093 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
4095 cache_update
= cache_update
| 0x1;
4097 *cache
= cache_update
;
4102 #ifndef ENABLE_ILGEN
4104 emit_isinst_noilgen (MonoMethodBuilder
*mb
)
4110 * mono_marshal_get_isinst_with_cache:
4111 * This does the equivalent of \c mono_marshal_isinst_with_cache.
4114 mono_marshal_get_isinst_with_cache (void)
4116 static MonoMethod
*cached
;
4118 MonoMethodBuilder
*mb
;
4119 MonoMethodSignature
*sig
;
4125 MonoType
*object_type
= mono_get_object_type ();
4126 MonoType
*int_type
= mono_get_int_type ();
4128 mb
= mono_mb_new (mono_defaults
.object_class
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
4129 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4131 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4133 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4135 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4136 sig
->ret
= object_type
;
4139 get_marshal_cb ()->emit_isinst (mb
);
4141 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
4142 res
= mono_mb_create (mb
, sig
, 8, info
);
4145 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4146 mono_free_method (res
);
4147 mono_metadata_free_method_signature (sig
);
4154 #ifndef ENABLE_ILGEN
4156 emit_struct_to_ptr_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4162 * mono_marshal_get_struct_to_ptr:
4163 * \param klass \c MonoClass
4165 * Generates IL code for <code>StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)</code>
4168 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
4170 MonoMethodBuilder
*mb
;
4171 static MonoMethod
*stoptr
= NULL
;
4175 g_assert (klass
!= NULL
);
4177 mono_marshal_load_type_info (klass
);
4179 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4180 if (marshal_info
->str_to_ptr
)
4181 return marshal_info
->str_to_ptr
;
4185 stoptr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "StructureToPtr", 3, 0, error
);
4186 mono_error_assert_ok (error
);
4190 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_OTHER
);
4192 get_marshal_cb ()->emit_struct_to_ptr (mb
, klass
);
4194 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
4195 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
4198 mono_marshal_lock ();
4199 if (!marshal_info
->str_to_ptr
)
4200 marshal_info
->str_to_ptr
= res
;
4202 res
= marshal_info
->str_to_ptr
;
4203 mono_marshal_unlock ();
4207 #ifndef ENABLE_ILGEN
4209 emit_ptr_to_struct_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4215 * mono_marshal_get_ptr_to_struct:
4216 * \param klass \c MonoClass
4217 * Generates IL code for <code>PtrToStructure (IntPtr src, object structure)</code>
4220 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
4222 MonoMethodBuilder
*mb
;
4223 static MonoMethodSignature
*ptostr
= NULL
;
4227 g_assert (klass
!= NULL
);
4229 mono_marshal_load_type_info (klass
);
4231 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4232 if (marshal_info
->ptr_to_str
)
4233 return marshal_info
->ptr_to_str
;
4236 MonoMethodSignature
*sig
;
4238 /* Create the signature corresponding to
4239 static void PtrToStructure (IntPtr ptr, object structure);
4240 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
4241 sig
= mono_icall_sig_void_ptr_object
;
4242 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4244 mono_memory_barrier ();
4248 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_OTHER
);
4250 get_marshal_cb ()->emit_ptr_to_struct (mb
, klass
);
4252 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
4253 res
= mono_mb_create (mb
, ptostr
, 0, info
);
4256 mono_marshal_lock ();
4257 if (!marshal_info
->ptr_to_str
)
4258 marshal_info
->ptr_to_str
= res
;
4260 res
= marshal_info
->ptr_to_str
;
4261 mono_marshal_unlock ();
4266 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
4267 * This is used to avoid infinite recursion since it is hard to determine where to
4268 * replace a method with its synchronized wrapper, and where not.
4269 * The runtime should execute METHOD instead of the wrapper.
4272 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
4274 MonoMethodBuilder
*mb
;
4276 MonoMethodSignature
*sig
;
4278 MonoGenericContext
*ctx
= NULL
;
4279 MonoGenericContainer
*container
= NULL
;
4281 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4282 ctx
= &((MonoMethodInflated
*)method
)->context
;
4283 method
= ((MonoMethodInflated
*)method
)->declaring
;
4284 container
= mono_method_get_generic_container (method
);
4286 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4287 g_assert (container
);
4290 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4291 get_marshal_cb ()->mb_emit_exception (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
4292 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4294 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4296 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
4297 info
->d
.synchronized_inner
.method
= method
;
4298 res
= mono_mb_create (mb
, sig
, 0, info
);
4302 res
= mono_class_inflate_generic_method_checked (res
, ctx
, error
);
4303 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
4308 #ifndef ENABLE_ILGEN
4310 emit_synchronized_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4312 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4313 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4314 mono_class_set_type_load_failure (method
->klass
, "");
4322 * mono_marshal_get_synchronized_wrapper:
4323 * Generates IL code for the synchronized wrapper: the generated method
4324 * calls \p method while locking \c this or the parent type.
4327 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
4329 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
4330 MonoMethodSignature
*sig
;
4331 MonoMethodBuilder
*mb
;
4335 MonoGenericContext
*ctx
= NULL
;
4336 MonoMethod
*orig_method
= NULL
;
4337 MonoGenericContainer
*container
= NULL
;
4341 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
4344 /* FIXME: Support generic methods too */
4345 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4346 orig_method
= method
;
4347 ctx
= &((MonoMethodInflated
*)method
)->context
;
4348 method
= ((MonoMethodInflated
*)method
)->declaring
;
4349 container
= mono_method_get_generic_container (method
);
4351 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4352 g_assert (container
);
4359 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4360 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
4364 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4365 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4369 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4372 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
4374 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4375 info
->d
.synchronized
.method
= method
;
4377 mono_marshal_lock ();
4379 if (!enter_method
) {
4380 MonoMethodDesc
*desc
;
4382 desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
4383 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4384 g_assert (enter_method
);
4385 mono_method_desc_free (desc
);
4387 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
4388 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4389 g_assert (exit_method
);
4390 mono_method_desc_free (desc
);
4392 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
4393 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
4394 g_assert (gettypefromhandle_method
);
4395 mono_method_desc_free (desc
);
4398 mono_marshal_unlock ();
4400 get_marshal_cb ()->mb_skip_visibility (mb
);
4401 get_marshal_cb ()->emit_synchronized_wrapper (mb
, method
, ctx
, container
, enter_method
, exit_method
, gettypefromhandle_method
);
4405 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4406 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4408 res
= mono_mb_create_and_cache_full (cache
, method
,
4409 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4416 #ifndef ENABLE_ILGEN
4418 emit_unbox_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4424 * mono_marshal_get_unbox_wrapper:
4425 * The returned method calls \p method unboxing the \c this argument.
4428 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
4430 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4431 MonoMethodBuilder
*mb
;
4436 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4438 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4441 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
4443 g_assert (sig
->hasthis
);
4445 get_marshal_cb ()->emit_unbox_wrapper (mb
, method
);
4447 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4448 info
->d
.unbox
.method
= method
;
4450 res
= mono_mb_create_and_cache_full (cache
, method
,
4451 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4454 /* mono_method_print_code (res); */
4460 is_monomorphic_array (MonoClass
*klass
)
4462 MonoClass
*element_class
;
4463 if (m_class_get_rank (klass
) != 1)
4466 element_class
= m_class_get_element_class (klass
);
4467 return mono_class_is_sealed (element_class
) || m_class_is_valuetype (element_class
);
4470 static MonoStelemrefKind
4471 get_virtual_stelemref_kind (MonoClass
*element_class
)
4473 if (element_class
== mono_defaults
.object_class
)
4474 return STELEMREF_OBJECT
;
4475 if (is_monomorphic_array (element_class
))
4476 return STELEMREF_SEALED_CLASS
;
4478 /* magic ifaces requires aditional checks for when the element type is an array */
4479 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && m_class_is_array_special_interface (element_class
))
4480 return STELEMREF_COMPLEX
;
4482 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
4483 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && !mono_class_has_variant_generic_params (element_class
))
4484 #ifdef COMPRESSED_INTERFACE_BITMAP
4485 return STELEMREF_COMPLEX
;
4487 return STELEMREF_INTERFACE
;
4489 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
4490 if (mono_class_is_marshalbyref (element_class
) || m_class_get_rank (element_class
) || mono_class_has_variant_generic_params (element_class
))
4491 return STELEMREF_COMPLEX
;
4492 if (mono_class_is_sealed (element_class
))
4493 return STELEMREF_SEALED_CLASS
;
4494 if (m_class_get_idepth (element_class
) <= MONO_DEFAULT_SUPERTABLE_SIZE
)
4495 return STELEMREF_CLASS_SMALL_IDEPTH
;
4497 return STELEMREF_CLASS
;
4502 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
4504 char *name
= mono_type_get_full_name (m_class_element_class (mono_object_class (array
)));
4505 printf ("slow vstore of %s\n", name
);
4510 #ifndef ENABLE_ILGEN
4512 emit_virtual_stelemref_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
4517 static const char *strelemref_wrapper_name
[] = {
4518 "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
4521 static const gchar
*
4522 mono_marshal_get_strelemref_wrapper_name (MonoStelemrefKind kind
)
4524 return strelemref_wrapper_name
[kind
];
4529 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
4530 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
4531 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
4532 * - Add a case for arrays of arrays.
4535 get_virtual_stelemref_wrapper (MonoStelemrefKind kind
)
4537 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
4538 static MonoMethodSignature
*signature
;
4539 MonoMethodBuilder
*mb
;
4542 const char *param_names
[16];
4545 if (cached_methods
[kind
])
4546 return cached_methods
[kind
];
4548 MonoType
*void_type
= mono_get_void_type ();
4549 MonoType
*object_type
= mono_get_object_type ();
4550 MonoType
*int_type
= mono_get_int_type ();
4552 name
= g_strdup_printf ("virt_stelemref_%s", mono_marshal_get_strelemref_wrapper_name (kind
));
4553 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
4557 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
4559 /* void this::stelemref (size_t idx, void* value) */
4560 sig
->ret
= void_type
;
4561 sig
->hasthis
= TRUE
;
4562 sig
->params
[0] = int_type
; /* this is a natural sized int */
4563 sig
->params
[1] = object_type
;
4567 param_names
[0] = "index";
4568 param_names
[1] = "value";
4569 get_marshal_cb ()->emit_virtual_stelemref (mb
, param_names
, kind
);
4571 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
4572 info
->d
.virtual_stelemref
.kind
= kind
;
4573 res
= mono_mb_create (mb
, signature
, 4, info
);
4574 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
4576 mono_marshal_lock ();
4577 if (!cached_methods
[kind
]) {
4578 cached_methods
[kind
] = res
;
4579 mono_marshal_unlock ();
4581 mono_marshal_unlock ();
4582 mono_free_method (res
);
4586 return cached_methods
[kind
];
4590 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
4592 MonoStelemrefKind kind
;
4594 g_assert (m_class_get_rank (array_class
) == 1);
4595 kind
= get_virtual_stelemref_kind (m_class_get_element_class (array_class
));
4597 return get_virtual_stelemref_wrapper (kind
);
4601 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
4606 *nwrappers
= STELEMREF_KIND_COUNT
;
4607 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
4608 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
4609 res
[i
] = get_virtual_stelemref_wrapper ((MonoStelemrefKind
)i
);
4613 #ifndef ENABLE_ILGEN
4615 emit_stelemref_noilgen (MonoMethodBuilder
*mb
)
4621 * mono_marshal_get_stelemref:
4624 mono_marshal_get_stelemref (void)
4626 static MonoMethod
* ret
= NULL
;
4627 MonoMethodSignature
*sig
;
4628 MonoMethodBuilder
*mb
;
4634 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
4637 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4639 MonoType
*void_type
= mono_get_void_type ();
4640 MonoType
*object_type
= mono_get_object_type ();
4641 MonoType
*int_type
= mono_get_int_type ();
4644 /* void stelemref (void* array, int idx, void* value) */
4645 sig
->ret
= void_type
;
4646 sig
->params
[0] = object_type
;
4647 sig
->params
[1] = int_type
; /* this is a natural sized int */
4648 sig
->params
[2] = object_type
;
4650 get_marshal_cb ()->emit_stelemref (mb
);
4652 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4653 ret
= mono_mb_create (mb
, sig
, 4, info
);
4659 #ifndef ENABLE_ILGEN
4661 mb_emit_byte_noilgen (MonoMethodBuilder
*mb
, guint8 op
)
4667 * mono_marshal_get_gsharedvt_in_wrapper:
4669 * This wrapper handles calls from normal code to gsharedvt code.
4672 mono_marshal_get_gsharedvt_in_wrapper (void)
4674 static MonoMethod
* ret
= NULL
;
4675 MonoMethodSignature
*sig
;
4676 MonoMethodBuilder
*mb
;
4682 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_OTHER
);
4684 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4685 sig
->ret
= mono_get_void_type ();
4688 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4690 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4692 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
4693 ret
= mono_mb_create (mb
, sig
, 4, info
);
4700 * mono_marshal_get_gsharedvt_out_wrapper:
4702 * This wrapper handles calls from gsharedvt code to normal code.
4705 mono_marshal_get_gsharedvt_out_wrapper (void)
4707 static MonoMethod
* ret
= NULL
;
4708 MonoMethodSignature
*sig
;
4709 MonoMethodBuilder
*mb
;
4715 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_OTHER
);
4717 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4718 sig
->ret
= mono_get_void_type ();
4721 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4723 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4725 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
4726 ret
= mono_mb_create (mb
, sig
, 4, info
);
4732 #ifndef ENABLE_ILGEN
4734 emit_array_address_noilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
4745 /* LOCKING: vars accessed under the marshal lock */
4746 static ArrayElemAddr
*elem_addr_cache
= NULL
;
4747 static int elem_addr_cache_size
= 0;
4748 static int elem_addr_cache_next
= 0;
4751 * mono_marshal_get_array_address:
4752 * \param rank rank of the array type
4753 * \param elem_size size in bytes of an element of an array.
4755 * Returns a MonoMethod that implements the code to get the address
4756 * of an element in a multi-dimenasional array of \p rank dimensions.
4757 * The returned method takes an array as the first argument and then
4758 * \p rank indexes for the \p rank dimensions.
4759 * If ELEM_SIZE is 0, read the array size from the array object.
4762 mono_marshal_get_array_address (int rank
, int elem_size
)
4765 MonoMethodBuilder
*mb
;
4766 MonoMethodSignature
*sig
;
4772 mono_marshal_lock ();
4773 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4774 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4775 ret
= elem_addr_cache
[i
].method
;
4779 mono_marshal_unlock ();
4783 MonoType
*object_type
= mono_get_object_type ();
4784 MonoType
*int_type
= mono_get_int_type ();
4785 MonoType
*int32_type
= mono_get_int32_type ();
4787 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
4789 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
4790 sig
->ret
= int_type
;
4791 sig
->params
[0] = object_type
;
4792 for (int i
= 0; i
< rank
; ++i
) {
4793 sig
->params
[i
+ 1] = int32_type
;
4796 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
4797 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4800 get_marshal_cb ()->emit_array_address (mb
, rank
, elem_size
);
4802 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
4803 info
->d
.element_addr
.rank
= rank
;
4804 info
->d
.element_addr
.elem_size
= elem_size
;
4805 ret
= mono_mb_create (mb
, sig
, 4, info
);
4808 /* cache the result */
4810 mono_marshal_lock ();
4811 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4812 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4813 /* FIXME: free ret */
4814 ret
= elem_addr_cache
[i
].method
;
4820 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
4821 int new_size
= elem_addr_cache_size
+ 4;
4822 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
4823 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
4824 g_free (elem_addr_cache
);
4825 elem_addr_cache
= new_array
;
4826 elem_addr_cache_size
= new_size
;
4828 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
4829 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
4830 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
4831 elem_addr_cache_next
++;
4833 mono_marshal_unlock ();
4837 #ifndef ENABLE_ILGEN
4839 emit_array_accessor_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4845 * mono_marshal_get_array_accessor_wrapper:
4847 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
4850 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
4852 MonoMethodSignature
*sig
;
4853 MonoMethodBuilder
*mb
;
4856 MonoGenericContext
*ctx
= NULL
;
4857 MonoMethod
*orig_method
= NULL
;
4861 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
4862 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
4863 * FIXME: Use generic methods.
4870 g_assert_not_reached ();
4872 cache
= get_cache (&get_method_image (method
)->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
4873 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4877 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4880 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4882 get_marshal_cb ()->emit_array_accessor_wrapper (mb
, method
, sig
, ctx
);
4884 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
4885 info
->d
.array_accessor
.method
= method
;
4889 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4890 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4892 res
= mono_mb_create_and_cache_full (cache
, method
,
4893 mb
, sig
, sig
->param_count
+ 16,
4903 mono_marshal_alloc_co_task_mem (size_t size
)
4906 /* This returns a valid pointer for size 0 on MS.NET */
4909 return g_try_malloc (size
);
4914 * mono_marshal_alloc:
4917 mono_marshal_alloc (gsize size
, MonoError
*error
)
4923 res
= mono_marshal_alloc_co_task_mem (size
);
4925 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
" bytes", size
);
4930 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
4932 ves_icall_marshal_alloc_impl (gsize size
, MonoError
*error
)
4934 return mono_marshal_alloc (size
, error
);
4939 mono_marshal_free_co_task_mem (void *ptr
)
4946 * mono_marshal_free:
4949 mono_marshal_free (gpointer ptr
)
4951 mono_marshal_free_co_task_mem (ptr
);
4955 * mono_marshal_free_array:
4958 mono_marshal_free_array (gpointer
*ptr
, int size
)
4965 for (i
= 0; i
< size
; i
++)
4970 mono_marshal_string_to_utf16 (MonoString
*s
)
4972 // FIXME This should be an intrinsic.
4973 // FIXMEcoop The input parameter is easy to deal with,
4974 // but what happens with the result?
4975 // See https://github.com/mono/mono/issues/12165.
4976 return s
? mono_string_chars_internal (s
) : NULL
;
4979 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
4981 mono_marshal_string_to_utf16_copy_impl (MonoStringHandle s
, MonoError
*error
)
4983 if (MONO_HANDLE_IS_NULL (s
))
4986 gsize
const length
= mono_string_handle_length (s
);
4987 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((length
+ 1) * sizeof (*res
), error
);
4988 return_val_if_nok (error
, NULL
);
4989 gchandle_t gchandle
= 0;
4990 memcpy (res
, mono_string_handle_pin_chars (s
, &gchandle
), length
* sizeof (*res
));
4991 mono_gchandle_free_internal (gchandle
);
4997 * mono_marshal_set_last_error:
4999 * This function is invoked to set the last error value from a P/Invoke call
5000 * which has \c SetLastError set.
5003 mono_marshal_set_last_error (void)
5005 /* This icall is called just after a P/Invoke call before the P/Invoke
5006 * wrapper transitions the runtime back to running mode. */
5008 MONO_REQ_GC_SAFE_MODE
;
5009 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
5011 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
5016 mono_marshal_set_last_error_windows (int error
)
5019 /* This icall is called just after a P/Invoke call before the P/Invoke
5020 * wrapper transitions the runtime back to running mode. */
5021 MONO_REQ_GC_SAFE_MODE
;
5022 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
5027 mono_marshal_clear_last_error (void)
5029 /* This icall is called just before a P/Invoke call. */
5031 SetLastError (ERROR_SUCCESS
);
5038 copy_managed_common (MonoArrayHandle managed
, gconstpointer native
, gint32 start_index
,
5039 gint32 length
, gpointer
*managed_addr
, guint32
*gchandle
, MonoError
*error
)
5041 MONO_CHECK_ARG_NULL_HANDLE (managed
, 0);
5042 MONO_CHECK_ARG_NULL (native
, 0);
5044 MonoClass
*klass
= mono_handle_class (managed
);
5046 // FIXME? move checks to managed
5047 if (m_class_get_rank (klass
) != 1) {
5048 mono_error_set_argument (error
, "array", "array is multi-dimensional");
5051 if (start_index
< 0) {
5052 mono_error_set_argument (error
, "startIndex", "Must be >= 0");
5056 mono_error_set_argument (error
, "length", "Must be >= 0");
5059 if (start_index
+ length
> mono_array_handle_length (managed
)) {
5060 mono_error_set_argument (error
, "length", "start_index + length > array length");
5064 gsize
const element_size
= mono_array_element_size (klass
);
5066 // Handle generic arrays, which do not allow fixed.
5068 *managed_addr
= mono_array_handle_pin_with_size (managed
, element_size
, start_index
, gchandle
);
5070 return element_size
* length
;
5074 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArrayHandle src
, gint32 start_index
,
5075 gpointer dest
, gint32 length
, gconstpointer managed_source_addr
, MonoError
*error
)
5077 guint32 gchandle
= 0;
5078 gsize
const bytes
= copy_managed_common (src
, dest
, start_index
, length
, (gpointer
*)&managed_source_addr
, &gchandle
, error
);
5080 memmove (dest
, managed_source_addr
, bytes
); // no references should be involved
5081 mono_gchandle_free_internal (gchandle
);
5085 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gconstpointer src
, gint32 start_index
,
5086 MonoArrayHandle dest
, gint32 length
, gpointer managed_dest_addr
, MonoError
*error
)
5088 guint32 gchandle
= 0;
5089 gsize
const bytes
= copy_managed_common (dest
, src
, start_index
, length
, &managed_dest_addr
, &gchandle
, error
);
5091 memmove (managed_dest_addr
, src
, bytes
); // no references should be involved
5092 mono_gchandle_free_internal (gchandle
);
5096 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (const char *ptr
, MonoError
*error
)
5099 return NULL_HANDLE_STRING
;
5100 return mono_string_new_handle (mono_domain_get (), ptr
, error
);
5104 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (const char *ptr
, gint32 len
, MonoError
*error
)
5107 mono_error_set_argument_null (error
, "ptr", "");
5108 return NULL_HANDLE_STRING
;
5110 return mono_string_new_utf8_len (mono_domain_get (), ptr
, len
, error
);
5114 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (const gunichar2
*ptr
, MonoError
*error
)
5117 const gunichar2
*t
= ptr
;
5120 return NULL_HANDLE_STRING
;
5125 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5126 return_val_if_nok (error
, NULL_HANDLE_STRING
);
5132 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (const gunichar2
*ptr
, gint32 len
, MonoError
*error
)
5135 mono_error_set_argument_null (error
, "ptr", "");
5136 return NULL_HANDLE_STRING
;
5138 return mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5142 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5144 return GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
));
5148 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype
, MonoError
*error
)
5150 if (MONO_HANDLE_IS_NULL (rtype
)) {
5151 mono_error_set_argument_null (error
, "type", "");
5155 MonoType
* const type
= MONO_HANDLE_GETVAL (rtype
, type
);
5156 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
5157 if (!mono_class_init_checked (klass
, error
))
5160 guint32
const layout
= (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
);
5162 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
5163 return sizeof (gpointer
);
5164 } else if (type
->type
== MONO_TYPE_VOID
) {
5166 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5167 mono_error_set_argument_format (error
, "t", "Type %s cannot be marshaled as an unmanaged structure.", m_class_get_name (klass
));
5172 return (guint32
)mono_marshal_type_size (type
, NULL
, &align
, FALSE
, m_class_is_unicode (klass
));
5176 ves_icall_System_Runtime_InteropServices_Marshal_SizeOfHelper (MonoReflectionTypeHandle rtype
, MonoBoolean throwIfNotMarshalable
, MonoError
*error
)
5178 return ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (rtype
, error
);
5182 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObjectHandle obj
, gpointer dst
, MonoBoolean delete_old
, MonoError
*error
)
5184 MONO_CHECK_ARG_NULL_HANDLE_NAMED (obj
, "structure",);
5185 MONO_CHECK_ARG_NULL_NAMED (dst
, "ptr",);
5187 #ifdef ENABLE_NETCORE
5188 MonoClass
*klass
= mono_handle_class (obj
);
5189 if (m_class_is_auto_layout (klass
)) {
5190 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5193 if (m_class_is_ginst (klass
)) {
5194 mono_error_set_argument (error
, "structure", "The specified object must not be an instance of a generic type.");
5199 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (obj
));
5201 gpointer pa
[ ] = { MONO_HANDLE_RAW (obj
), &dst
, &delete_old
};
5203 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
5207 ptr_to_structure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5209 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (dst
));
5211 gpointer pa
[ ] = { &src
, MONO_HANDLE_RAW (dst
) };
5213 // FIXMEcoop? mono_runtime_invoke_handle causes a GC assertion failure in marshal2 with interpreter
5214 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5217 #ifdef ENABLE_NETCORE
5220 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructureInternal (gconstpointer src
, MonoObjectHandle dst
, MonoBoolean allow_vtypes
, MonoError
*error
)
5225 t
= m_class_get_byval_arg (mono_handle_class (dst
));
5226 if (!allow_vtypes
&& MONO_TYPE_ISSTRUCT (t
)) {
5227 mono_error_set_argument (error
, "structure", "The structure must not be a value class.");
5231 klass
= mono_class_from_mono_type_internal (t
);
5232 if (m_class_is_auto_layout (klass
)) {
5233 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5237 ptr_to_structure (src
, dst
, error
);
5243 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5247 MONO_CHECK_ARG_NULL (src
,);
5248 MONO_CHECK_ARG_NULL_HANDLE (dst
,);
5250 t
= mono_type_get_underlying_type (m_class_get_byval_arg (mono_handle_class (dst
)));
5252 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5253 mono_error_set_argument (error
, "dst", "Destination is a boxed value type.");
5257 ptr_to_structure (src
, dst
, error
);
5261 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gconstpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5266 MONO_CHECK_ARG_NULL_HANDLE (type
, NULL_HANDLE
);
5268 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5269 if (!mono_class_init_checked (klass
, error
))
5272 MonoObjectHandle res
= mono_object_new_handle (mono_domain_get (), klass
, error
);
5273 return_val_if_nok (error
, NULL_HANDLE
);
5275 ptr_to_structure (src
, res
, error
);
5276 return_val_if_nok (error
, NULL_HANDLE
);
5283 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type
, MonoStringHandle field_name
, MonoError
*error
)
5286 if (MONO_HANDLE_IS_NULL (ref_type
)) {
5287 mono_error_set_argument_null (error
, "t", "");
5290 if (MONO_HANDLE_IS_NULL (field_name
)) {
5291 mono_error_set_argument_null (error
, "fieldName", "");
5295 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (ref_type
))) {
5296 mono_error_set_argument (error
, "type", "");
5300 char *fname
= mono_string_handle_to_utf8 (field_name
, error
);
5301 return_val_if_nok (error
, 0);
5303 MonoType
*type
= MONO_HANDLE_GETVAL (ref_type
, type
);
5304 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
5305 if (!mono_class_init_checked (klass
, error
))
5307 #ifdef ENABLE_NETCORE
5308 if (m_class_is_auto_layout (klass
)) {
5309 mono_error_set_argument (error
, NULL
, "");
5313 int match_index
= -1;
5314 while (klass
&& match_index
== -1) {
5315 MonoClassField
* field
;
5317 gpointer iter
= NULL
;
5318 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5319 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5321 if (!strcmp (fname
, mono_field_get_name (field
))) {
5328 if (match_index
== -1)
5329 klass
= m_class_get_parent (klass
);
5334 if(match_index
== -1) {
5335 /* Get back original class instance */
5336 klass
= mono_class_from_mono_type_internal (type
);
5338 mono_error_set_argument_format (error
, "fieldName", "Field passed in is not a marshaled member of the type %s", m_class_get_name (klass
));
5342 MonoMarshalType
*info
= mono_marshal_load_type_info (klass
);
5343 return info
->fields
[match_index
].offset
;
5348 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2
*s
, int length
, MonoError
*error
)
5350 return mono_utf16_to_utf8 (s
, length
, error
);
5354 mono_marshal_alloc_hglobal (size_t size
, MonoError
*error
)
5356 void* p
= g_try_malloc (size
);
5358 mono_error_set_out_of_memory (error
, "");
5361 #endif /* !HOST_WIN32 */
5364 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2
*s
, int length
, MonoError
*error
)
5369 gsize
const len
= ((gsize
)length
+ 1) * 2;
5370 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc_hglobal (len
, error
);
5372 memcpy (res
, s
, length
* 2);
5379 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
5381 MonoMarshalType
*info
;
5384 info
= mono_marshal_load_type_info (klass
);
5386 for (i
= 0; i
< info
->num_fields
; i
++) {
5387 MonoMarshalConv conv
;
5388 MonoType
*ftype
= info
->fields
[i
].field
->type
;
5391 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5394 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
5395 m_class_is_unicode (klass
), &conv
);
5397 cpos
= ptr
+ info
->fields
[i
].offset
;
5400 case MONO_MARSHAL_CONV_NONE
:
5401 if (MONO_TYPE_ISSTRUCT (ftype
)) {
5402 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
5406 case MONO_MARSHAL_CONV_STR_LPWSTR
:
5407 /* We assume this field points inside a MonoString */
5409 case MONO_MARSHAL_CONV_STR_LPTSTR
:
5411 /* We assume this field points inside a MonoString
5415 case MONO_MARSHAL_CONV_STR_LPSTR
:
5416 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
5417 case MONO_MARSHAL_CONV_STR_TBSTR
:
5418 case MONO_MARSHAL_CONV_STR_UTF8STR
:
5419 mono_marshal_free (*(gpointer
*)cpos
);
5421 case MONO_MARSHAL_CONV_STR_BSTR
:
5422 mono_free_bstr (*(gpointer
*)cpos
);
5431 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5433 MONO_CHECK_ARG_NULL_NAMED (src
, "ptr",);
5434 MONO_CHECK_ARG_NULL_HANDLE_NAMED (type
, "structureType",);
5436 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (type
))) {
5437 mono_error_set_argument (error
, "structureType", "");
5441 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5442 if (!mono_class_init_checked (klass
, error
))
5444 #ifdef ENABLE_NETCORE
5445 if (m_class_is_auto_layout (klass
)) {
5446 mono_error_set_argument (error
, "structureType", "The specified structure must be blittable or have layout information.");
5452 mono_struct_delete_old (klass
, (char *)src
);
5456 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gsize size
, MonoError
*error
)
5459 /* This returns a valid pointer for size 0 on MS.NET */
5462 return mono_marshal_alloc_hglobal (size
, error
);
5466 static inline gpointer
5467 mono_marshal_realloc_hglobal (gpointer ptr
, size_t size
)
5469 return g_try_realloc (ptr
, size
);
5474 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gsize size
, MonoError
*error
)
5477 mono_error_set_out_of_memory (error
, "");
5481 gpointer
const res
= mono_marshal_realloc_hglobal (ptr
, size
);
5484 mono_error_set_out_of_memory (error
, "");
5491 mono_marshal_free_hglobal (gpointer ptr
)
5498 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
5500 mono_marshal_free_hglobal (ptr
);
5504 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
, MonoError
*error
)
5506 void *res
= mono_marshal_alloc_co_task_mem (size
);
5509 mono_error_set_out_of_memory (error
, "");
5515 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gsize size
, MonoError
*error
)
5517 void *res
= mono_marshal_alloc_co_task_mem (size
);
5520 mono_error_set_out_of_memory (error
, "");
5526 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
5528 mono_marshal_free_co_task_mem (ptr
);
5532 static inline gpointer
5533 mono_marshal_realloc_co_task_mem (gpointer ptr
, size_t size
)
5535 return g_try_realloc (ptr
, size
);
5540 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
, MonoError
*error
)
5542 void *res
= mono_marshal_realloc_co_task_mem (ptr
, size
);
5545 mono_error_set_out_of_memory (error
, "");
5552 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArrayHandle arrayobj
, int index
, MonoError
*error
)
5554 int esize
= mono_array_element_size (mono_handle_class (arrayobj
));
5555 return mono_array_addr_with_size_fast (MONO_HANDLE_RAW (arrayobj
), esize
, index
);
5559 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionTypeHandle type
, MonoError
*error
)
5561 MonoClass
*klass
= mono_type_get_class (MONO_HANDLE_GETVAL (type
, type
));
5562 if (!mono_class_init_checked (klass
, error
))
5563 return MONO_HANDLE_CAST (MonoDelegate
, NULL_HANDLE
);
5565 return mono_ftnptr_to_delegate_impl (klass
, ftn
, error
);
5569 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate
, MonoError
*error
)
5571 return mono_delegate_to_ftnptr_impl (delegate
, error
);
5575 ves_icall_System_Runtime_InteropServices_Marshal_GetArrayElementSize (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5577 MonoClass
*eklass
= mono_type_get_class (MONO_HANDLE_GETVAL (type_h
, type
));
5579 mono_class_init_internal (eklass
);
5581 if (m_class_has_references (eklass
)) {
5582 mono_error_set_argument (error
, NULL
, NULL
);
5585 return mono_class_array_element_size (eklass
);
5589 ves_icall_System_Runtime_InteropServices_Marshal_IsPinnableType (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5591 MonoClass
*klass
= mono_class_from_mono_type_internal (MONO_HANDLE_GETVAL (type_h
, type
));
5593 if (m_class_get_rank (klass
)) {
5594 MonoClass
*eklass
= m_class_get_element_class (klass
);
5595 if (m_class_is_primitive (eklass
))
5597 return eklass
!= mono_defaults
.object_class
&& m_class_is_blittable (eklass
);
5599 return m_class_is_blittable (klass
);
5603 * mono_marshal_is_loading_type_info:
5605 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
5609 mono_marshal_is_loading_type_info (MonoClass
*klass
)
5611 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5613 return g_slist_find (loads_list
, klass
) != NULL
;
5617 * mono_marshal_load_type_info:
5619 * Initialize \c klass::marshal_info using information from metadata. This function can
5620 * recursively call itself, and the caller is responsible to avoid that by calling
5621 * \c mono_marshal_is_loading_type_info beforehand.
5623 * LOCKING: Acquires the loader lock.
5626 mono_marshal_load_type_info (MonoClass
* klass
)
5629 guint32 native_size
= 0, min_align
= 1, packing
;
5630 MonoMarshalType
*info
;
5631 MonoClassField
* field
;
5636 g_assert (klass
!= NULL
);
5638 info
= mono_class_get_marshal_info (klass
);
5642 if (!m_class_is_inited (klass
))
5643 mono_class_init_internal (klass
);
5645 info
= mono_class_get_marshal_info (klass
);
5650 * This function can recursively call itself, so we keep the list of classes which are
5651 * under initialization in a TLS list.
5653 g_assert (!mono_marshal_is_loading_type_info (klass
));
5654 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5655 loads_list
= g_slist_prepend (loads_list
, klass
);
5656 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5659 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5660 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5662 if (mono_field_is_deleted (field
))
5667 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
5669 info
= (MonoMarshalType
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
5670 info
->num_fields
= count
;
5672 /* Try to find a size for this type in metadata */
5673 mono_metadata_packing_from_typedef (m_class_get_image (klass
), m_class_get_type_token (klass
), NULL
, &native_size
);
5675 if (m_class_get_parent (klass
)) {
5676 int parent_size
= mono_class_native_size (m_class_get_parent (klass
), NULL
);
5678 /* Add parent size to real size */
5679 native_size
+= parent_size
;
5680 info
->native_size
= parent_size
;
5683 packing
= m_class_get_packing_size (klass
) ? m_class_get_packing_size (klass
) : 8;
5686 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5690 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5693 if (mono_field_is_deleted (field
))
5695 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
5696 mono_metadata_field_info_with_mempool (m_class_get_image (klass
), mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
5697 NULL
, NULL
, &info
->fields
[j
].mspec
);
5699 info
->fields
[j
].field
= field
;
5701 if ((mono_class_num_fields (klass
) == 1) && (m_class_get_instance_size (klass
) == MONO_ABI_SIZEOF (MonoObject
)) &&
5702 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
5703 /* This field is a hack inserted by MCS to empty structures */
5708 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
5709 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
5710 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5711 &align
, TRUE
, m_class_is_unicode (klass
));
5712 align
= m_class_get_packing_size (klass
) ? MIN (m_class_get_packing_size (klass
), align
): align
;
5713 min_align
= MAX (align
, min_align
);
5714 info
->fields
[j
].offset
= info
->native_size
;
5715 info
->fields
[j
].offset
+= align
- 1;
5716 info
->fields
[j
].offset
&= ~(align
- 1);
5717 info
->native_size
= info
->fields
[j
].offset
+ size
;
5719 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
5720 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5721 &align
, TRUE
, m_class_is_unicode (klass
));
5722 min_align
= MAX (align
, min_align
);
5723 info
->fields
[j
].offset
= field
->offset
- MONO_ABI_SIZEOF (MonoObject
);
5724 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
5730 if (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_PTR
)
5731 info
->native_size
= TARGET_SIZEOF_VOID_P
;
5733 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5734 info
->native_size
= MAX (native_size
, info
->native_size
);
5736 * If the provided Size is equal or larger than the calculated size, and there
5737 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
5739 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
5740 if (native_size
&& native_size
== info
->native_size
&& m_class_get_packing_size (klass
) == 0)
5743 min_align
= MIN (min_align
, packing
);
5747 if (info
->native_size
& (min_align
- 1)) {
5748 info
->native_size
+= min_align
- 1;
5749 info
->native_size
&= ~(min_align
- 1);
5752 info
->min_align
= min_align
;
5754 /* Update the class's blittable info, if the layouts don't match */
5755 if (info
->native_size
!= mono_class_value_size (klass
, NULL
)) {
5756 mono_class_set_nonblittable (klass
); /* FIXME - how is this justified? what if we previously thought the class was blittable? */
5759 /* If this is an array type, ensure that we have element info */
5760 if (m_class_get_rank (klass
) && !mono_marshal_is_loading_type_info (m_class_get_element_class (klass
))) {
5761 mono_marshal_load_type_info (m_class_get_element_class (klass
));
5764 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5765 loads_list
= g_slist_remove (loads_list
, klass
);
5766 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5768 mono_marshal_lock ();
5769 MonoMarshalType
*info2
= mono_class_get_marshal_info (klass
);
5771 /*We do double-checking locking on marshal_info */
5772 mono_memory_barrier ();
5773 mono_class_set_marshal_info (klass
, info
);
5774 ++class_marshal_info_count
;
5777 mono_marshal_unlock ();
5783 * mono_class_native_size:
5784 * \param klass a class
5785 * \returns the native size of an object instance (when marshaled
5786 * to unmanaged code)
5789 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
5791 MonoMarshalType
*info
= mono_class_get_marshal_info (klass
);
5793 if (mono_marshal_is_loading_type_info (klass
)) {
5798 mono_marshal_load_type_info (klass
);
5800 info
= mono_class_get_marshal_info (klass
);
5804 *align
= info
->min_align
;
5806 return info
->native_size
;
5810 * mono_type_native_stack_size:
5811 * @t: the type to return the size it uses on the stack
5813 * Returns: the number of bytes required to hold an instance of this
5814 * type on the native stack
5817 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
5821 g_assert (t
!= NULL
);
5827 *align
= TARGET_SIZEOF_VOID_P
;
5828 return TARGET_SIZEOF_VOID_P
;
5832 case MONO_TYPE_BOOLEAN
:
5833 case MONO_TYPE_CHAR
:
5844 case MONO_TYPE_STRING
:
5845 case MONO_TYPE_OBJECT
:
5846 case MONO_TYPE_CLASS
:
5847 case MONO_TYPE_SZARRAY
:
5849 case MONO_TYPE_FNPTR
:
5850 case MONO_TYPE_ARRAY
:
5851 *align
= TARGET_SIZEOF_VOID_P
;
5852 return TARGET_SIZEOF_VOID_P
;
5857 *align
= MONO_ABI_ALIGNOF (double);
5861 *align
= MONO_ABI_ALIGNOF (gint64
);
5863 case MONO_TYPE_GENERICINST
:
5864 if (!mono_type_generic_inst_is_valuetype (t
)) {
5865 *align
= TARGET_SIZEOF_VOID_P
;
5866 return TARGET_SIZEOF_VOID_P
;
5869 case MONO_TYPE_TYPEDBYREF
:
5870 case MONO_TYPE_VALUETYPE
: {
5872 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
5874 if (m_class_is_enumtype (klass
))
5875 return mono_type_native_stack_size (mono_class_enum_basetype_internal (klass
), align
);
5877 size
= mono_class_native_size (klass
, align
);
5878 *align
= *align
+ 3;
5888 g_error ("type 0x%02x unknown", t
->type
);
5894 * mono_marshal_type_size:
5897 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
5898 gboolean as_field
, gboolean unicode
)
5901 MonoMarshalNative native_type
= (MonoMarshalNative
)mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
5904 switch (native_type
) {
5905 case MONO_NATIVE_BOOLEAN
:
5908 case MONO_NATIVE_I1
:
5909 case MONO_NATIVE_U1
:
5912 case MONO_NATIVE_I2
:
5913 case MONO_NATIVE_U2
:
5914 case MONO_NATIVE_VARIANTBOOL
:
5917 case MONO_NATIVE_I4
:
5918 case MONO_NATIVE_U4
:
5919 case MONO_NATIVE_ERROR
:
5922 case MONO_NATIVE_I8
:
5923 case MONO_NATIVE_U8
:
5924 *align
= MONO_ABI_ALIGNOF (gint64
);
5926 case MONO_NATIVE_R4
:
5929 case MONO_NATIVE_R8
:
5930 *align
= MONO_ABI_ALIGNOF (double);
5932 case MONO_NATIVE_INT
:
5933 case MONO_NATIVE_UINT
:
5934 case MONO_NATIVE_LPSTR
:
5935 case MONO_NATIVE_LPWSTR
:
5936 case MONO_NATIVE_LPTSTR
:
5937 case MONO_NATIVE_BSTR
:
5938 case MONO_NATIVE_ANSIBSTR
:
5939 case MONO_NATIVE_TBSTR
:
5940 case MONO_NATIVE_UTF8STR
:
5941 case MONO_NATIVE_LPARRAY
:
5942 case MONO_NATIVE_SAFEARRAY
:
5943 case MONO_NATIVE_IUNKNOWN
:
5944 case MONO_NATIVE_IDISPATCH
:
5945 case MONO_NATIVE_INTERFACE
:
5946 case MONO_NATIVE_ASANY
:
5947 case MONO_NATIVE_FUNC
:
5948 case MONO_NATIVE_LPSTRUCT
:
5949 *align
= MONO_ABI_ALIGNOF (gpointer
);
5950 return TARGET_SIZEOF_VOID_P
;
5951 case MONO_NATIVE_STRUCT
:
5952 klass
= mono_class_from_mono_type_internal (type
);
5953 if (klass
== mono_defaults
.object_class
&&
5954 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
5958 padded_size
= mono_class_native_size (klass
, align
);
5959 if (padded_size
== 0)
5962 case MONO_NATIVE_BYVALTSTR
: {
5963 int esize
= unicode
? 2: 1;
5966 return mspec
->data
.array_data
.num_elem
* esize
;
5968 case MONO_NATIVE_BYVALARRAY
: {
5969 // FIXME: Have to consider ArraySubType
5971 klass
= mono_class_from_mono_type_internal (type
);
5972 if (m_class_get_element_class (klass
) == mono_defaults
.char_class
) {
5973 esize
= unicode
? 2 : 1;
5976 esize
= mono_class_native_size (m_class_get_element_class (klass
), align
);
5979 return mspec
->data
.array_data
.num_elem
* esize
;
5981 case MONO_NATIVE_CUSTOM
:
5982 *align
= TARGET_SIZEOF_VOID_P
;
5983 return TARGET_SIZEOF_VOID_P
;
5985 case MONO_NATIVE_CURRENCY
:
5986 case MONO_NATIVE_VBBYREFSTR
:
5988 g_error ("native type %02x not implemented", native_type
);
5991 g_assert_not_reached ();
5996 * mono_marshal_asany:
5997 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
6000 mono_marshal_asany_impl (MonoObjectHandle o
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6002 if (MONO_HANDLE_IS_NULL (o
))
6005 MonoType
*t
= m_class_get_byval_arg (mono_handle_class (o
));
6012 case MONO_TYPE_BOOLEAN
:
6015 case MONO_TYPE_CHAR
:
6020 return mono_handle_unbox_unsafe (o
);
6021 case MONO_TYPE_STRING
:
6022 switch (string_encoding
) {
6023 case MONO_NATIVE_LPWSTR
:
6024 return mono_marshal_string_to_utf16_copy_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6025 case MONO_NATIVE_LPSTR
:
6026 case MONO_NATIVE_UTF8STR
:
6027 // Same code path, because in Mono, we treated strings as Utf8
6028 return mono_string_to_utf8str_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6030 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6031 g_assert_not_reached ();
6034 case MONO_TYPE_CLASS
:
6035 case MONO_TYPE_VALUETYPE
: {
6037 MonoClass
*klass
= t
->data
.klass
;
6039 if (mono_class_is_auto_layout (klass
))
6042 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6043 return mono_handle_unbox_unsafe (o
);
6045 gpointer res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), error
);
6046 return_val_if_nok (error
, NULL
);
6048 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6049 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (o
));
6050 MonoBoolean delete_old
= FALSE
;
6051 gpointer pa
[ ] = { MONO_HANDLE_RAW (o
), &res
, &delete_old
};
6053 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
6054 return_val_if_nok (error
, NULL
);
6062 mono_error_set_argument (error
, "", "No PInvoke conversion exists for value passed to Object-typed parameter.");
6067 * mono_marshal_free_asany:
6068 * This is a JIT icall, it sets the pending exception (in wrapper)
6071 mono_marshal_free_asany_impl (MonoObjectHandle o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6076 if (MONO_HANDLE_IS_NULL (o
))
6079 t
= m_class_get_byval_arg (mono_handle_class (o
));
6081 case MONO_TYPE_STRING
:
6082 switch (string_encoding
) {
6083 case MONO_NATIVE_LPWSTR
:
6084 case MONO_NATIVE_LPSTR
:
6085 case MONO_NATIVE_UTF8STR
:
6086 mono_marshal_free (ptr
);
6089 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6090 g_assert_not_reached ();
6093 case MONO_TYPE_CLASS
:
6094 case MONO_TYPE_VALUETYPE
: {
6095 klass
= t
->data
.klass
;
6097 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6100 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
6101 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (o
));
6105 pa
[1] = MONO_HANDLE_RAW (o
);
6107 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
6108 if (!mono_error_ok (error
))
6112 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6113 mono_struct_delete_old (klass
, (char *)ptr
);
6116 mono_marshal_free (ptr
);
6124 #ifndef ENABLE_ILGEN
6126 emit_generic_array_helper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6132 * mono_marshal_get_generic_array_helper:
6134 * Return a wrapper which is used to implement the implicit interfaces on arrays.
6135 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
6138 mono_marshal_get_generic_array_helper (MonoClass
*klass
, const gchar
*name
, MonoMethod
*method
)
6140 MonoMethodSignature
*sig
, *csig
;
6141 MonoMethodBuilder
*mb
;
6145 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
6146 mb
->method
->slot
= -1;
6148 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
6149 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
6151 sig
= mono_method_signature_internal (method
);
6152 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
6153 csig
->generic_param_count
= 0;
6155 get_marshal_cb ()->emit_generic_array_helper (mb
, method
, csig
);
6157 /* We can corlib internal methods */
6158 get_marshal_cb ()->mb_skip_visibility (mb
);
6160 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
6161 info
->d
.generic_array_helper
.method
= method
;
6162 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
6170 * The mono_win32_compat_* functions are implementations of inline
6171 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
6172 * although not exported by kernel32.
6174 * We map the appropiate kernel32 entries to these functions using
6175 * dllmaps declared in the global etc/mono/config.
6179 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
6181 if (!dest
|| !source
)
6184 memcpy (dest
, source
, length
);
6188 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
6190 memset (dest
, fill
, length
);
6194 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
6196 if (!dest
|| !source
)
6199 memmove (dest
, source
, length
);
6203 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
6205 memset (dest
, 0, length
);
6209 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
6214 for (i
= 0; i
< len
; ++i
)
6221 while (byte
&& !(byte
& 1))
6223 g_assert (byte
== 1);
6229 #ifndef ENABLE_ILGEN
6231 emit_thunk_invoke_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6237 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
6239 MonoMethodBuilder
*mb
;
6240 MonoMethodSignature
*sig
, *csig
;
6245 int i
, param_count
, sig_size
;
6249 klass
= method
->klass
;
6250 image
= m_class_get_image (klass
);
6252 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
6254 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
6257 MonoType
*object_type
= mono_get_object_type ();
6259 sig
= mono_method_signature_internal (method
);
6260 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
6262 /* add "this" and exception param */
6263 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
6265 /* dup & extend signature */
6266 csig
= mono_metadata_signature_alloc (image
, param_count
);
6267 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
6268 memcpy (csig
, sig
, sig_size
);
6269 csig
->param_count
= param_count
;
6272 csig
->call_convention
= MONO_CALL_DEFAULT
;
6276 csig
->params
[0] = m_class_get_byval_arg (klass
);
6277 /* move params up by one */
6278 for (i
= 0; i
< sig
->param_count
; i
++)
6279 csig
->params
[i
+ 1] = sig
->params
[i
];
6282 /* setup exception param as byref+[out] */
6283 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
, m_class_get_byval_arg (mono_defaults
.exception_class
));
6284 csig
->params
[param_count
- 1]->byref
= 1;
6285 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
6287 /* convert struct return to object */
6288 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6289 csig
->ret
= object_type
;
6291 get_marshal_cb ()->emit_thunk_invoke_wrapper (mb
, method
, csig
);
6293 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
6300 clear_runtime_invoke_method_cache (GHashTable
*table
, MonoMethod
*method
)
6302 MonoWrapperMethodCacheKey hash_key
= {method
, FALSE
, FALSE
};
6304 * Since we have a small set of possible keys, remove each one separately, thus
6305 * avoiding the traversal of the entire hash table, when using foreach_remove.
6307 g_hash_table_remove (table
, &hash_key
);
6308 hash_key
.need_direct_wrapper
= TRUE
;
6309 g_hash_table_remove (table
, &hash_key
);
6310 hash_key
.virtual_
= TRUE
;
6311 g_hash_table_remove (table
, &hash_key
);
6312 hash_key
.need_direct_wrapper
= FALSE
;
6313 g_hash_table_remove (table
, &hash_key
);
6317 * mono_marshal_free_dynamic_wrappers:
6319 * Free wrappers of the dynamic method METHOD.
6322 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
6324 MonoImage
*image
= get_method_image (method
);
6326 g_assert (method_is_dynamic (method
));
6328 /* This could be called during shutdown */
6329 if (marshal_mutex_initialized
)
6330 mono_marshal_lock ();
6332 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
6333 * they could be shared with other methods ?
6335 if (image
->wrapper_caches
.runtime_invoke_method_cache
)
6336 clear_runtime_invoke_method_cache (image
->wrapper_caches
.runtime_invoke_method_cache
, method
);
6337 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
6338 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
6339 // FIXME: Need to clear the caches in other images as well
6340 if (image
->delegate_bound_static_invoke_cache
)
6341 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature_internal (method
));
6343 if (marshal_mutex_initialized
)
6344 mono_marshal_unlock ();
6348 mono_marshal_get_type_object (MonoClass
*klass
)
6351 MonoType
*type
= m_class_get_byval_arg (klass
);
6352 MonoObject
*result
= (MonoObject
*)mono_type_get_object_checked (mono_domain_get (), type
, error
);
6353 mono_error_set_pending_exception (error
);
6358 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
)
6360 get_marshal_cb ()->emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, aot
, check_exceptions
, func_param
);
6363 #ifndef ENABLE_ILGEN
6365 emit_native_wrapper_noilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
)
6370 static MonoMarshalCallbacks marshal_cb
;
6371 static gboolean cb_inited
= FALSE
;
6374 mono_install_marshal_callbacks (MonoMarshalCallbacks
*cb
)
6376 g_assert (!cb_inited
);
6377 g_assert (cb
->version
== MONO_MARSHAL_CALLBACKS_VERSION
);
6378 memcpy (&marshal_cb
, cb
, sizeof (MonoMarshalCallbacks
));
6382 #ifndef ENABLE_ILGEN
6384 install_noilgen (void)
6386 MonoMarshalCallbacks cb
;
6387 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6388 cb
.emit_marshal_array
= emit_marshal_array_noilgen
;
6389 cb
.emit_marshal_boolean
= emit_marshal_boolean_noilgen
;
6390 cb
.emit_marshal_ptr
= emit_marshal_ptr_noilgen
;
6391 cb
.emit_marshal_char
= emit_marshal_char_noilgen
;
6392 cb
.emit_marshal_scalar
= emit_marshal_scalar_noilgen
;
6393 cb
.emit_marshal_custom
= emit_marshal_custom_noilgen
;
6394 cb
.emit_marshal_asany
= emit_marshal_asany_noilgen
;
6395 cb
.emit_marshal_vtype
= emit_marshal_vtype_noilgen
;
6396 cb
.emit_marshal_string
= emit_marshal_string_noilgen
;
6397 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_noilgen
;
6398 cb
.emit_marshal_handleref
= emit_marshal_handleref_noilgen
;
6399 cb
.emit_marshal_object
= emit_marshal_object_noilgen
;
6400 cb
.emit_marshal_variant
= emit_marshal_variant_noilgen
;
6401 cb
.emit_castclass
= emit_castclass_noilgen
;
6402 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_noilgen
;
6403 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_noilgen
;
6404 cb
.emit_isinst
= emit_isinst_noilgen
;
6405 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_noilgen
;
6406 cb
.emit_stelemref
= emit_stelemref_noilgen
;
6407 cb
.emit_array_address
= emit_array_address_noilgen
;
6408 cb
.emit_native_wrapper
= emit_native_wrapper_noilgen
;
6409 cb
.emit_managed_wrapper
= emit_managed_wrapper_noilgen
;
6410 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_noilgen
;
6411 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_noilgen
;
6412 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_noilgen
;
6413 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_noilgen
;
6414 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_noilgen
;
6415 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_noilgen
;
6416 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_noilgen
;
6417 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_noilgen
;
6418 cb
.emit_generic_array_helper
= emit_generic_array_helper_noilgen
;
6419 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_noilgen
;
6420 cb
.emit_create_string_hack
= emit_create_string_hack_noilgen
;
6421 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_noilgen
;
6422 cb
.emit_icall_wrapper
= emit_icall_wrapper_noilgen
;
6423 cb
.emit_return
= emit_return_noilgen
;
6424 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_noilgen
;
6425 cb
.mb_skip_visibility
= mb_skip_visibility_noilgen
;
6426 cb
.mb_set_dynamic
= mb_set_dynamic_noilgen
;
6427 cb
.mb_emit_exception
= mb_emit_exception_noilgen
;
6428 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_noilgen
;
6429 cb
.mb_emit_byte
= mb_emit_byte_noilgen
;
6430 mono_install_marshal_callbacks (&cb
);
6434 static MonoMarshalCallbacks
*
6435 get_marshal_cb (void)
6437 if (G_UNLIKELY (!cb_inited
)) {
6439 mono_marshal_ilgen_init ();