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
)
190 MonoString
*s
= mono_string_new_checked (mono_domain_get (), text
, error
);
191 return_val_if_nok (error
, NULL_HANDLE_STRING
);
192 return MONO_HANDLE_NEW (MonoString
, s
);
194 return NULL_HANDLE_STRING
;
198 mono_marshal_init (void)
200 static gboolean module_initialized
= FALSE
;
202 if (!module_initialized
) {
203 module_initialized
= TRUE
;
204 mono_coop_mutex_init_recursive (&marshal_mutex
);
205 marshal_mutex_initialized
= TRUE
;
207 register_icall (mono_marshal_string_to_utf16
, mono_icall_sig_ptr_obj
, FALSE
);
208 register_icall (mono_marshal_string_to_utf16_copy
, mono_icall_sig_ptr_obj
, FALSE
);
209 register_icall (mono_string_to_utf16_internal
, mono_icall_sig_ptr_obj
, FALSE
);
210 register_icall (ves_icall_mono_string_from_utf16
, mono_icall_sig_obj_ptr
, FALSE
);
211 register_icall (mono_string_from_byvalstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
212 register_icall (mono_string_from_byvalwstr
, mono_icall_sig_obj_ptr_int
, FALSE
);
213 register_icall (mono_string_new_wrapper_internal
, mono_icall_sig_obj_ptr
, FALSE
);
214 register_icall (ves_icall_string_new_wrapper
, mono_icall_sig_obj_ptr
, FALSE
);
215 register_icall (mono_string_new_len_wrapper
, mono_icall_sig_obj_ptr_int
, FALSE
);
216 register_icall (ves_icall_mono_string_to_utf8
, mono_icall_sig_ptr_obj
, FALSE
);
217 register_icall (mono_string_to_utf8str
, mono_icall_sig_ptr_obj
, FALSE
);
218 register_icall (mono_string_to_ansibstr
, mono_icall_sig_ptr_object
, FALSE
);
219 register_icall (mono_string_builder_to_utf8
, mono_icall_sig_ptr_object
, FALSE
);
220 register_icall (mono_string_builder_to_utf16
, mono_icall_sig_ptr_object
, FALSE
);
221 register_icall (mono_array_to_savearray
, mono_icall_sig_ptr_object
, FALSE
);
222 register_icall (mono_array_to_lparray
, mono_icall_sig_ptr_object
, FALSE
);
223 register_icall (mono_free_lparray
, mono_icall_sig_void_object_ptr
, FALSE
);
224 register_icall (mono_byvalarray_to_byte_array
, mono_icall_sig_void_object_ptr_int32
, FALSE
);
225 register_icall (mono_array_to_byte_byvalarray
, mono_icall_sig_void_ptr_object_int32
, FALSE
);
226 register_icall (mono_delegate_to_ftnptr
, mono_icall_sig_ptr_object
, FALSE
);
227 register_icall (mono_ftnptr_to_delegate
, mono_icall_sig_object_ptr_ptr
, FALSE
);
228 register_icall (mono_marshal_asany
, mono_icall_sig_ptr_object_int32_int32
, FALSE
);
229 register_icall (mono_marshal_free_asany
, mono_icall_sig_void_object_ptr_int32_int32
, FALSE
);
230 register_icall (ves_icall_marshal_alloc
, mono_icall_sig_ptr_ptr
, FALSE
);
231 register_icall (mono_marshal_free
, mono_icall_sig_void_ptr
, FALSE
);
232 register_icall (mono_marshal_set_last_error
, mono_icall_sig_void
, TRUE
);
233 register_icall (mono_marshal_set_last_error_windows
, mono_icall_sig_void_int32
, TRUE
);
234 register_icall (mono_marshal_clear_last_error
, mono_icall_sig_void
, TRUE
);
235 register_icall (mono_string_utf8_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
236 register_icall (mono_string_utf8_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
237 register_icall (mono_string_utf16_to_builder
, mono_icall_sig_void_ptr_ptr
, FALSE
);
238 register_icall (mono_string_utf16_to_builder2
, mono_icall_sig_object_ptr
, FALSE
);
239 register_icall (mono_marshal_free_array
, mono_icall_sig_void_ptr_int32
, FALSE
);
240 register_icall (mono_string_to_byvalstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
241 register_icall (mono_string_to_byvalwstr
, mono_icall_sig_void_ptr_ptr_int32
, FALSE
);
242 // Because #define g_free monoeg_g_free.
243 register_icall (monoeg_g_free
, mono_icall_sig_void_ptr
, FALSE
);
244 register_icall (mono_object_isinst_icall
, mono_icall_sig_object_object_ptr
, TRUE
);
245 register_icall (mono_struct_delete_old
, mono_icall_sig_void_ptr_ptr
, FALSE
);
246 register_icall (mono_delegate_begin_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
247 register_icall (mono_delegate_end_invoke
, mono_icall_sig_object_object_ptr
, FALSE
);
248 register_icall (mono_gc_wbarrier_generic_nostore_internal
, mono_icall_sig_void_ptr
, FALSE
);
249 register_icall (mono_gchandle_get_target_internal
, mono_icall_sig_object_int32
, TRUE
);
250 register_icall (mono_marshal_isinst_with_cache
, mono_icall_sig_object_object_ptr_ptr
, FALSE
);
251 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
252 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
253 register_icall (mono_threads_enter_gc_unsafe_region_unbalanced
, mono_icall_sig_ptr_ptr
, TRUE
);
254 register_icall (mono_threads_exit_gc_unsafe_region_unbalanced
, mono_icall_sig_void_ptr_ptr
, TRUE
);
255 register_icall (mono_threads_attach_coop
, mono_icall_sig_ptr_ptr_ptr
, TRUE
);
256 register_icall (mono_threads_detach_coop
, mono_icall_sig_void_ptr_ptr
, TRUE
);
257 register_icall (mono_marshal_get_type_object
, mono_icall_sig_object_ptr
, TRUE
);
259 mono_cominterop_init ();
260 mono_remoting_init ();
262 mono_counters_register ("MonoClass::class_marshal_info_count count",
263 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_marshal_info_count
);
268 mono_marshal_cleanup (void)
270 mono_cominterop_cleanup ();
272 mono_native_tls_free (load_type_info_tls_id
);
273 mono_native_tls_free (last_error_tls_id
);
274 mono_coop_mutex_destroy (&marshal_mutex
);
275 marshal_mutex_initialized
= FALSE
;
279 mono_marshal_lock_internal (void)
281 mono_marshal_lock ();
285 mono_marshal_unlock_internal (void)
287 mono_marshal_unlock ();
290 // This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error.
292 mono_delegate_to_ftnptr_impl (MonoDelegateHandle delegate
, MonoError
*error
)
294 gpointer result
= NULL
;
295 MonoMethod
*method
, *wrapper
;
297 uint32_t target_handle
= 0;
299 if (MONO_HANDLE_IS_NULL (delegate
))
302 if (MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
)) {
303 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
307 klass
= mono_handle_class (delegate
);
308 g_assert (m_class_is_delegate (klass
));
310 method
= MONO_HANDLE_GETVAL (delegate
, method
);
311 if (MONO_HANDLE_GETVAL (delegate
, method_is_virtual
)) {
312 MonoObjectHandle delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
313 method
= mono_object_handle_get_virtual_method (delegate_target
, method
, error
);
314 goto_if_nok (error
, leave
);
317 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
320 ftnptr
= mono_lookup_pinvoke_call_internal (method
, error
);
322 g_assert (!is_ok (error
));
329 MonoObjectHandle delegate_target
;
330 delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
331 if (!MONO_HANDLE_IS_NULL (delegate_target
)) {
332 /* Produce a location which can be embedded in JITted code */
333 target_handle
= mono_gchandle_new_weakref_from_handle (delegate_target
);
336 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
, error
);
337 goto_if_nok (error
, leave
);
339 MONO_HANDLE_SETVAL (delegate
, delegate_trampoline
, gpointer
, mono_compile_method_checked (wrapper
, error
));
340 goto_if_nok (error
, leave
);
342 // Add the delegate to the delegate hash table
343 delegate_hash_table_add (delegate
);
345 /* when the object is collected, collect the dynamic method, too */
346 mono_object_register_finalizer ((MonoObject
*) MONO_HANDLE_RAW (delegate
));
348 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
351 if (!is_ok (error
) && target_handle
!= 0)
352 mono_gchandle_free_internal (target_handle
);
357 * this hash table maps from a delegate trampoline object to a weak reference
358 * of the delegate. As an optimizations with a non-moving GC we store the
359 * object pointer itself, otherwise we use a GC handle.
361 static GHashTable
*delegate_hash_table
;
364 delegate_hash_table_new (void) {
365 return g_hash_table_new (NULL
, NULL
);
369 delegate_hash_table_remove (MonoDelegate
*d
)
371 if (mono_gc_is_moving ())
374 mono_marshal_lock ();
375 if (delegate_hash_table
== NULL
)
376 delegate_hash_table
= delegate_hash_table_new ();
377 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
378 mono_marshal_unlock ();
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 if (mono_gc_is_moving ()) {
389 if (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
) == NULL
) {
390 guint32 gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, d
), FALSE
);
391 // This delegate will always be associated with its delegate_trampoline in the table.
392 // We don't free this delegate object because it is too expensive to keep track of these
393 // pairs and avoid races with the delegate finalization.
394 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
397 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, MONO_HANDLE_RAW (d
));
399 mono_marshal_unlock ();
403 * mono_marshal_use_aot_wrappers:
405 * Instructs this module to use AOT compatible wrappers.
408 mono_marshal_use_aot_wrappers (gboolean use
)
410 use_aot_wrappers
= use
;
414 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
417 MonoCustomAttrInfo
*cinfo
;
418 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
420 /* The attribute is only available in Net 2.0 */
421 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
423 * The pinvoke attributes are stored in a real custom attribute so we have to
426 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
427 if (!mono_error_ok (error
)) {
428 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
429 mono_error_cleanup (error
);
431 if (cinfo
&& !mono_runtime_get_no_exec ()) {
432 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), error
);
434 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
436 if (!mono_error_ok (error
)) {
437 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
438 mono_error_cleanup (error
);
442 mono_custom_attrs_free (cinfo
);
447 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
449 mono_ftnptr_to_delegate_impl (MonoClass
*klass
, gpointer ftn
, MonoError
*error
)
452 MonoDelegateHandle d
= MONO_HANDLE_NEW (MonoDelegate
, NULL
);
457 mono_marshal_lock ();
458 if (delegate_hash_table
== NULL
)
459 delegate_hash_table
= delegate_hash_table_new ();
461 if (mono_gc_is_moving ()) {
462 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
463 mono_marshal_unlock ();
465 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_CAST (MonoDelegate
, mono_gchandle_get_target_handle (gchandle
)));
467 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_NEW (MonoDelegate
, (MonoDelegate
*)g_hash_table_lookup (delegate_hash_table
, ftn
)));
468 mono_marshal_unlock ();
470 if (MONO_HANDLE_IS_NULL (d
)) {
471 /* This is a native function, so construct a delegate for it */
472 MonoMethodSignature
*sig
;
474 MonoMarshalSpec
**mspecs
;
475 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
476 MonoMethodPInvoke piinfo
;
477 MonoObjectHandle this_obj
;
480 if (use_aot_wrappers
) {
481 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
482 this_obj
= MONO_HANDLE_NEW (MonoObject
, mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, error
));
483 goto_if_nok (error
, leave
);
485 memset (&piinfo
, 0, sizeof (piinfo
));
486 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
488 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
489 mono_method_get_marshal_info (invoke
, mspecs
);
490 /* Freed below so don't alloc from mempool */
491 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
494 wrapper
= mono_marshal_get_native_func_wrapper (m_class_get_image (klass
), sig
, &piinfo
, mspecs
, ftn
);
495 this_obj
= MONO_HANDLE_NEW (MonoObject
, NULL
);
497 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
499 mono_metadata_free_marshal_spec (mspecs
[i
]);
504 MONO_HANDLE_ASSIGN (d
, mono_object_new_handle (mono_domain_get (), klass
, error
));
505 goto_if_nok (error
, leave
);
506 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, error
);
507 goto_if_nok (error
, leave
);
509 mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject
, d
), this_obj
, compiled_ptr
, wrapper
, error
);
510 goto_if_nok (error
, leave
);
513 g_assert (!MONO_HANDLE_IS_NULL (d
));
514 if (MONO_HANDLE_DOMAIN (d
) != mono_domain_get ())
515 mono_error_set_not_supported (error
, "Delegates cannot be marshalled from native code into a domain other than their home domain");
521 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
526 delegate_hash_table_remove (delegate
);
528 ptr
= (gpointer
)mono_atomic_xchg_ptr (&delegate
->delegate_trampoline
, NULL
);
530 if (!delegate
->target
) {
531 /* The wrapper method is shared between delegates -> no need to free it */
540 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
541 /* FIXME we leak wrapper with the interpreter */
545 method
= mono_jit_info_get_method (ji
);
546 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
548 /*the target gchandle is the first entry after size and the wrapper itself.*/
549 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
552 mono_gchandle_free_internal (gchandle
);
554 mono_runtime_free_method (mono_object_domain (delegate
), method
);
558 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error */
560 mono_string_from_byvalstr_impl (const char *data
, int max_len
, MonoError
*error
)
562 // FIXME This optimization ok to miss before wrapper? Or null is rare?
564 return NULL_HANDLE_STRING
;
567 while (len
< max_len
- 1 && data
[len
])
571 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), data
, len
, error
);
572 return_val_if_nok (error
, NULL_HANDLE_STRING
);
573 return MONO_HANDLE_NEW (MonoString
, s
);
576 /* This is a JIT icall, it sets the pending exception (in wrapper) and return NULL on error */
578 mono_string_from_byvalwstr_impl (const gunichar2
*data
, int max_len
, MonoError
*error
)
580 // FIXME This optimization ok to miss before wrapper? Or null is rare?
582 return NULL_HANDLE_STRING
;
584 // FIXME Check max_len while scanning data? mono_string_from_byvalstr does.
585 int len
= g_utf16_len (data
);
587 MonoString
*res
= mono_string_new_utf16_checked (mono_domain_get (), data
, MIN (len
, max_len
), error
);
588 return_val_if_nok (error
, NULL_HANDLE_STRING
);
589 return MONO_HANDLE_NEW (MonoString
, res
);
593 mono_array_to_savearray_impl (MonoArrayHandle array
, MonoError
*error
)
595 if (!MONO_HANDLE_BOOL (array
))
598 g_assert_not_reached ();
603 mono_array_to_lparray_impl (MonoArrayHandle array_handle
, MonoError
*error
)
605 if (!MONO_HANDLE_BOOL (array_handle
))
608 MonoArray
*array
= MONO_HANDLE_RAW (array_handle
); // FIXMEcoop
611 gpointer
*nativeArray
= NULL
;
612 int nativeArraySize
= 0;
614 MonoClass
*klass
= array
->obj
.vtable
->klass
;
615 MonoClass
*klass_element_class
= m_class_get_element_class (klass
);
617 switch (m_class_get_byval_arg (klass_element_class
)->type
) {
619 g_assert_not_reached ();
621 case MONO_TYPE_CLASS
:
622 nativeArraySize
= array
->max_length
;
623 nativeArray
= g_new (gpointer
, nativeArraySize
);
624 for (i
= 0; i
< nativeArraySize
; ++i
) {
625 nativeArray
[i
] = mono_cominterop_get_com_interface (((MonoObject
**)array
->vector
)[i
], klass_element_class
, error
);
626 if (!is_ok (error
)) {
627 // FIXME? Returns uninitialized.
633 case MONO_TYPE_BOOLEAN
:
646 case MONO_TYPE_VALUETYPE
:
650 case MONO_TYPE_GENERICINST
:
651 case MONO_TYPE_OBJECT
:
652 case MONO_TYPE_ARRAY
:
653 case MONO_TYPE_SZARRAY
:
654 case MONO_TYPE_STRING
:
656 g_warning ("type 0x%x not handled", m_class_get_byval_arg (klass_element_class
)->type
);
657 g_assert_not_reached ();
660 return array
->vector
;
664 mono_free_lparray_impl (MonoArrayHandle array
, gpointer
* nativeArray
, MonoError
*error
)
667 if (!nativeArray
|| MONO_HANDLE_IS_NULL (array
))
670 MonoClass
* const klass
= mono_handle_class (array
);
672 if (m_class_get_byval_arg (m_class_get_element_class (klass
))->type
== MONO_TYPE_CLASS
)
673 g_free (nativeArray
);
677 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
679 mono_byvalarray_to_byte_array_impl (MonoArrayHandle arr
, const char *native_arr
, guint32 elnum
, MonoError
*error
)
681 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
683 GError
*gerror
= NULL
;
685 gunichar2
*ut
= g_utf8_to_utf16 (native_arr
, elnum
, NULL
, &items_written
, &gerror
);
688 g_error_free (gerror
);
691 gchandle_t gchandle
= 0;
692 memcpy (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), ut
, items_written
* sizeof (gunichar2
));
693 mono_gchandle_free_internal (gchandle
);
697 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns on error */
699 mono_array_to_byte_byvalarray_impl (gpointer native_arr
, MonoArrayHandle arr
, guint32 elnum
, MonoError
*error
)
701 g_assert (m_class_get_element_class (mono_handle_class (arr
)) == mono_defaults
.char_class
);
703 GError
*gerror
= NULL
;
705 gchandle_t gchandle
= 0;
706 char *as
= g_utf16_to_utf8 (MONO_ARRAY_HANDLE_PIN (arr
, gunichar2
, 0, &gchandle
), mono_array_handle_length (arr
), NULL
, NULL
, &gerror
);
707 mono_gchandle_free_internal (gchandle
);
709 mono_error_set_argument (error
, "string", gerror
->message
);
710 g_error_free (gerror
);
713 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
717 static MonoStringBuilderHandle
718 mono_string_builder_new (int starting_string_length
, MonoError
*error
)
720 static MonoClass
*string_builder_class
;
721 static MonoMethod
*sb_ctor
;
724 int initial_len
= starting_string_length
;
730 MonoMethodDesc
*desc
;
733 string_builder_class
= mono_class_try_get_stringbuilder_class ();
734 g_assert (string_builder_class
); //TODO don't swallow the error
735 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
736 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
738 mono_method_desc_free (desc
);
739 mono_memory_barrier ();
743 // We make a new array in the _to_builder function, so this
744 // array will always be garbage collected.
745 args
[0] = &initial_len
;
747 MonoStringBuilderHandle sb
= MONO_HANDLE_CAST (MonoStringBuilder
, mono_object_new_handle (mono_domain_get (), string_builder_class
, error
));
748 mono_error_assert_ok (error
);
750 mono_runtime_try_invoke_handle (sb_ctor
, MONO_HANDLE_CAST (MonoObject
, sb
), args
, error
);
751 mono_error_assert_ok (error
);
753 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW_GET (MonoArray
, sb
, chunkChars
);
754 g_assert (MONO_HANDLE_GETVAL (chunkChars
, max_length
) >= initial_len
);
760 mono_string_utf16_to_builder_copy (MonoStringBuilderHandle sb
, const gunichar2
*text
, size_t string_len
, MonoError
*error
)
762 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
763 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
765 guint capacity
= mono_string_builder_capacity (sb
);
767 g_assert (capacity
>= string_len
);
769 MONO_ENTER_NO_SAFEPOINTS
;
772 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
773 const int maxLength
= MONO_HANDLE_GETVAL (chunkChars
, max_length
);
774 g_assert (maxLength
>= 0);
775 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
776 g_assert (chunkOffset
>= 0);
777 if (maxLength
> 0 && chunkOffset
< string_len
) {
778 // Check that we will not overrun our boundaries.
779 int charsToCopy
= MIN (string_len
- chunkOffset
, maxLength
);
780 memcpy (MONO_HANDLE_RAW (chunkChars
)->vector
, text
+ chunkOffset
, charsToCopy
* sizeof (gunichar2
));
781 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, charsToCopy
);
783 MONO_HANDLE_SETVAL (chunk
, chunkLength
, int, 0);
785 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
786 } while (MONO_HANDLE_BOOL (chunk
));
788 MONO_EXIT_NO_SAFEPOINTS
;
791 MonoStringBuilderHandle
792 mono_string_utf16_to_builder2_impl (const gunichar2
*text
, MonoError
*error
)
795 return NULL_HANDLE_STRING_BUILDER
;
797 const gsize len
= g_utf16_len (text
);
799 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
800 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
802 mono_string_utf16len_to_builder (sb
, text
, len
, error
);
803 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
809 mono_string_utf8len_to_builder (MonoStringBuilderHandle sb
, const char *text
, gsize len
, MonoError
*error
)
811 if (!MONO_HANDLE_BOOL (sb
) || !text
)
814 GError
*gerror
= NULL
;
816 gunichar2
* ut
= g_utf8_to_utf16 (text
, len
, NULL
, &copied
, &gerror
);
817 int capacity
= mono_string_builder_capacity (sb
);
819 if (copied
> capacity
)
823 MONO_HANDLE_SETRAW (sb
, chunkPrevious
, NULL
);
824 mono_string_utf16_to_builder_copy (sb
, ut
, copied
, error
);
827 g_error_free (gerror
);
834 mono_string_utf8_to_builder_impl (MonoStringBuilderHandle sb
, const char *text
, MonoError
*error
)
836 mono_string_utf8len_to_builder (sb
, text
, text
? strlen (text
) : 0, error
);
839 MonoStringBuilderHandle
840 mono_string_utf8_to_builder2_impl (const char *text
, MonoError
*error
)
843 return NULL_HANDLE_STRING_BUILDER
;
845 const gsize len
= strlen (text
);
847 MonoStringBuilderHandle sb
= mono_string_builder_new (len
, error
);
848 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
850 mono_string_utf8len_to_builder (sb
, text
, len
, error
);
851 return_val_if_nok (error
, NULL_HANDLE_STRING_BUILDER
);
857 mono_string_utf16len_to_builder (MonoStringBuilderHandle sb
, const gunichar2
*text
, gsize len
, MonoError
*error
)
859 if (!MONO_HANDLE_BOOL (sb
) || !text
)
861 len
= MIN (len
, mono_string_builder_capacity (sb
));
862 mono_string_utf16_to_builder_copy (sb
, text
, len
, error
);
866 mono_string_utf16_to_builder_impl (MonoStringBuilderHandle sb
, const gunichar2
*text
, MonoError
*error
)
868 mono_string_utf16len_to_builder (sb
, text
, text
? g_utf16_len (text
) : 0, error
);
872 * mono_string_builder_to_utf8:
873 * \param sb the string builder
875 * Converts to utf8 the contents of the \c MonoStringBuilder .
877 * \returns a utf8 string with the contents of the \c StringBuilder .
879 * The return value must be released with mono_marshal_free.
881 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
884 mono_string_builder_to_utf8_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
887 GError
*gerror
= NULL
;
889 gunichar2
*str_utf16
= NULL
;
893 if (!MONO_HANDLE_BOOL (sb
))
896 str_utf16
= mono_string_builder_to_utf16_impl (sb
, error
);
897 goto_if_nok (error
, exit
);
899 tmp
= g_utf16_to_utf8 (str_utf16
, mono_string_builder_string_length (sb
), NULL
, &byte_count
, &gerror
);
901 mono_error_set_execution_engine (error
, "Failed to convert StringBuilder from utf16 to utf8");
905 len
= mono_string_builder_capacity (sb
) + 1;
906 res
= (char *)mono_marshal_alloc (MAX (byte_count
+ 1, len
), error
);
907 if (!is_ok (error
)) {
912 memcpy (res
, tmp
, byte_count
);
913 res
[byte_count
] = 0;
915 g_error_free (gerror
);
916 mono_marshal_free (str_utf16
);
922 * mono_string_builder_to_utf16:
923 * \param sb the string builder
925 * Converts to utf16 the contents of the \c MonoStringBuilder .
927 * Returns: a utf16 string with the contents of the \c StringBuilder .
929 * The return value must be released with mono_marshal_free.
931 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
934 mono_string_builder_to_utf16_impl (MonoStringBuilderHandle sb
, MonoError
*error
)
936 if (!MONO_HANDLE_BOOL (sb
))
939 g_assert (MONO_HANDLE_GET_BOOL (sb
, chunkChars
));
941 guint capacity
= mono_string_builder_capacity (sb
);
942 guint length
= mono_string_builder_string_length (sb
);
944 // Follow CoreCLR and double NULL terminate the buffer so we have more protection
945 // against native code putting garbage in there.
947 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((capacity
+ 2) * sizeof (gunichar2
), error
);
948 return_val_if_nok (error
, NULL
);
951 str
[capacity
+ 1] = 0;
953 MonoArrayHandle chunkChars
= MONO_HANDLE_NEW (MonoArray
, NULL
);
954 MonoStringBuilderHandle chunk
= MONO_HANDLE_NEW (MonoStringBuilder
, MONO_HANDLE_RAW (sb
));
956 MONO_ENTER_NO_SAFEPOINTS
;
959 const int chunkLength
= MONO_HANDLE_GETVAL (chunk
, chunkLength
);
960 g_assert (chunkLength
>= 0);
961 if (chunkLength
> 0) {
962 // Check that we will not overrun our boundaries.
963 MONO_HANDLE_GET (chunkChars
, chunk
, chunkChars
);
964 const int chunkOffset
= MONO_HANDLE_GETVAL (chunk
, chunkOffset
);
965 g_assert (chunkOffset
>= 0);
966 g_assertf ((chunkOffset
+ chunkLength
) >= chunkLength
, "integer overflow");
967 g_assertf ((chunkOffset
+ chunkLength
) <= capacity
, "A chunk in the StringBuilder had a length longer than expected from the offset.");
968 memcpy (str
+ chunkOffset
, MONO_HANDLE_RAW (chunkChars
)->vector
, chunkLength
* sizeof (gunichar2
));
970 MONO_HANDLE_GET (chunk
, chunk
, chunkPrevious
);
971 } while (MONO_HANDLE_BOOL (chunk
));
975 MONO_EXIT_NO_SAFEPOINTS
;
982 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
984 mono_string_to_utf8str_impl (MonoStringHandle s
, MonoError
*error
)
986 return mono_string_handle_to_utf8 (s
, error
);
992 mono_string_to_ansibstr_impl (MonoStringHandle string_obj
, MonoError
*error
)
994 g_error ("UnmanagedMarshal.BStr is not implemented.");
999 * mono_string_to_byvalstr:
1000 * \param dst Where to store the null-terminated utf8 decoded string.
1001 * \param src the \c MonoString to copy.
1002 * \param size the maximum number of bytes to copy.
1004 * Copies the \c MonoString pointed to by \p src as a utf8 string
1005 * into \p dst, it copies at most \p size bytes into the destination.
1008 mono_string_to_byvalstr_impl (char *dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1010 g_assert (dst
!= NULL
);
1011 g_assert (size
> 0);
1013 memset (dst
, 0, size
);
1014 if (!MONO_HANDLE_BOOL (src
))
1017 // FIXME convert right into dst instead of the double copy.
1019 char *s
= mono_string_handle_to_utf8 (src
, error
);
1020 return_if_nok (error
);
1021 int len
= MIN (size
, strlen (s
));
1022 len
-= (len
>= size
);
1023 memcpy (dst
, s
, len
);
1029 * mono_string_to_byvalwstr:
1030 * \param dst Where to store the null-terminated utf16 decoded string.
1031 * \param src the \c MonoString to copy.
1032 * \param size the maximum number of wide characters to copy (each consumes 2 bytes)
1034 * Copies the \c MonoString pointed to by \p src as a utf16 string into
1035 * \p dst, it copies at most \p size gunichar2s into the destination (including
1036 * a terminating 16-bit zero terminator).
1039 mono_string_to_byvalwstr_impl (gunichar2
*dst
, MonoStringHandle src
, int size
, MonoError
*error
)
1042 g_assert (size
> 0);
1044 if (!MONO_HANDLE_BOOL (src
)) {
1045 memset (dst
, 0, size
* sizeof (gunichar2
));
1049 gchandle_t gchandle
= 0;
1050 int len
= MIN (size
, mono_string_handle_length (src
));
1051 memcpy (dst
, mono_string_handle_pin_chars (src
, &gchandle
), len
* sizeof (gunichar2
));
1052 mono_gchandle_free_internal (gchandle
);
1053 len
-= (size
<= mono_string_handle_length (src
));
1057 /* this is an icall, it sets the pending exception and returns NULL on error */
1059 mono_string_new_len_wrapper_impl (const char *text
, guint length
, MonoError
*error
)
1061 MonoString
*s
= mono_string_new_len_checked (mono_domain_get (), text
, length
, error
);
1062 return_val_if_nok (error
, NULL_HANDLE_STRING
);
1063 return MONO_HANDLE_NEW (MonoString
, s
);
1067 mono_type_to_ldind (MonoType
*type
)
1073 switch (type
->type
) {
1075 return CEE_LDIND_I1
;
1077 case MONO_TYPE_BOOLEAN
:
1078 return CEE_LDIND_U1
;
1080 return CEE_LDIND_I2
;
1082 case MONO_TYPE_CHAR
:
1083 return CEE_LDIND_U2
;
1085 return CEE_LDIND_I4
;
1087 return CEE_LDIND_U4
;
1091 case MONO_TYPE_FNPTR
:
1093 case MONO_TYPE_CLASS
:
1094 case MONO_TYPE_STRING
:
1095 case MONO_TYPE_OBJECT
:
1096 case MONO_TYPE_SZARRAY
:
1097 case MONO_TYPE_ARRAY
:
1098 return CEE_LDIND_REF
;
1101 return CEE_LDIND_I8
;
1103 return CEE_LDIND_R4
;
1105 return CEE_LDIND_R8
;
1106 case MONO_TYPE_VALUETYPE
:
1107 if (m_class_is_enumtype (type
->data
.klass
)) {
1108 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1112 case MONO_TYPE_TYPEDBYREF
:
1114 case MONO_TYPE_GENERICINST
:
1115 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1118 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1124 mono_type_to_stind (MonoType
*type
)
1127 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1130 switch (type
->type
) {
1133 case MONO_TYPE_BOOLEAN
:
1134 return CEE_STIND_I1
;
1137 case MONO_TYPE_CHAR
:
1138 return CEE_STIND_I2
;
1141 return CEE_STIND_I4
;
1145 case MONO_TYPE_FNPTR
:
1147 case MONO_TYPE_CLASS
:
1148 case MONO_TYPE_STRING
:
1149 case MONO_TYPE_OBJECT
:
1150 case MONO_TYPE_SZARRAY
:
1151 case MONO_TYPE_ARRAY
:
1152 return CEE_STIND_REF
;
1155 return CEE_STIND_I8
;
1157 return CEE_STIND_R4
;
1159 return CEE_STIND_R8
;
1160 case MONO_TYPE_VALUETYPE
:
1161 if (m_class_is_enumtype (type
->data
.klass
)) {
1162 type
= mono_class_enum_basetype_internal (type
->data
.klass
);
1166 case MONO_TYPE_TYPEDBYREF
:
1168 case MONO_TYPE_GENERICINST
:
1169 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1172 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1177 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1179 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1182 MonoMulticastDelegate
*mcast_delegate
;
1186 g_assert (delegate
);
1187 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
1188 if (mcast_delegate
->delegates
!= NULL
) {
1189 mono_error_set_argument (error
, NULL
, "The delegate must have only one target");
1190 mono_error_set_pending_exception (error
);
1194 #ifndef DISABLE_REMOTING
1195 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1196 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1197 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
1198 /* If the target is a proxy, make a direct call. Is proxy's work
1199 // to make the call asynchronous.
1201 MonoMethodMessage
*msg
;
1202 MonoDelegate
*async_callback
;
1204 MonoAsyncResult
*ares
;
1206 MonoArray
*out_args
;
1207 method
= delegate
->method
;
1209 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, error
);
1210 if (mono_error_set_pending_exception (error
))
1212 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, error
);
1213 if (mono_error_set_pending_exception (error
))
1215 MONO_OBJECT_SETREF_INTERNAL (ares
, async_delegate
, (MonoObject
*)delegate
);
1216 MONO_OBJECT_SETREF_INTERNAL (ares
, async_callback
, (MonoObject
*)async_callback
);
1217 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1218 msg
->call_type
= CallType_BeginInvoke
;
1221 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1222 if (!mono_error_ok (error
)) {
1223 mono_error_set_pending_exception (error
);
1227 mono_set_pending_exception ((MonoException
*) exc
);
1233 klass
= delegate
->object
.vtable
->klass
;
1235 ERROR_DECL (begin_invoke_error
);
1236 method
= mono_get_delegate_begin_invoke_checked (klass
, begin_invoke_error
);
1237 mono_error_cleanup (begin_invoke_error
); /* if we can't call BeginInvoke, fall back on Invoke */
1239 method
= mono_get_delegate_invoke_internal (klass
);
1242 MonoAsyncResult
*result
= mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, error
);
1243 mono_error_set_pending_exception (error
);
1248 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
1250 GString
*res
= g_string_new ("");
1253 g_string_append (res
, prefix
);
1254 g_string_append_c (res
, '_');
1257 mono_type_get_desc (res
, sig
->ret
, FALSE
);
1260 g_string_append (res
, "__this__");
1262 for (int i
= 0; i
< sig
->param_count
; ++i
) {
1263 g_string_append_c (res
, '_');
1264 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
1266 char *result
= res
->str
;
1267 g_string_free (res
, FALSE
);
1272 * mono_marshal_get_string_encoding:
1274 * Return the string encoding which should be used for a given parameter.
1277 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1279 /* First try the parameter marshal info */
1281 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
1282 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
1283 return spec
->data
.array_data
.elem_type
;
1286 return spec
->native
;
1290 return MONO_NATIVE_LPSTR
;
1292 /* Then try the method level marshal info */
1293 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1294 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1295 return MONO_NATIVE_LPSTR
;
1296 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1297 return MONO_NATIVE_LPWSTR
;
1298 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1300 return MONO_NATIVE_LPWSTR
;
1302 return MONO_NATIVE_LPSTR
;
1305 return MONO_NATIVE_LPSTR
;
1310 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1312 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1315 case MONO_NATIVE_LPWSTR
:
1316 return MONO_MARSHAL_CONV_STR_LPWSTR
;
1317 case MONO_NATIVE_LPSTR
:
1318 case MONO_NATIVE_VBBYREFSTR
:
1319 return MONO_MARSHAL_CONV_STR_LPSTR
;
1320 case MONO_NATIVE_LPTSTR
:
1321 return MONO_MARSHAL_CONV_STR_LPTSTR
;
1322 case MONO_NATIVE_BSTR
:
1323 return MONO_MARSHAL_CONV_STR_BSTR
;
1324 case MONO_NATIVE_UTF8STR
:
1325 return MONO_MARSHAL_CONV_STR_UTF8STR
;
1327 return MONO_MARSHAL_CONV_INVALID
;
1332 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1334 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1337 case MONO_NATIVE_LPWSTR
:
1338 return MONO_MARSHAL_CONV_SB_LPWSTR
;
1339 case MONO_NATIVE_LPSTR
:
1340 return MONO_MARSHAL_CONV_SB_LPSTR
;
1341 case MONO_NATIVE_UTF8STR
:
1342 return MONO_MARSHAL_CONV_SB_UTF8STR
;
1343 case MONO_NATIVE_LPTSTR
:
1344 return MONO_MARSHAL_CONV_SB_LPTSTR
;
1346 return MONO_MARSHAL_CONV_INVALID
;
1351 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1353 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1358 case MONO_NATIVE_LPWSTR
:
1360 return MONO_MARSHAL_CONV_LPWSTR_STR
;
1361 case MONO_NATIVE_UTF8STR
:
1362 return MONO_MARSHAL_CONV_UTF8STR_STR
;
1363 case MONO_NATIVE_LPSTR
:
1364 case MONO_NATIVE_VBBYREFSTR
:
1365 return MONO_MARSHAL_CONV_LPSTR_STR
;
1366 case MONO_NATIVE_LPTSTR
:
1370 return MONO_MARSHAL_CONV_LPTSTR_STR
;
1371 case MONO_NATIVE_BSTR
:
1372 return MONO_MARSHAL_CONV_BSTR_STR
;
1374 return MONO_MARSHAL_CONV_INVALID
;
1379 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1381 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1386 case MONO_NATIVE_LPWSTR
:
1387 return MONO_MARSHAL_CONV_LPWSTR_SB
;
1388 case MONO_NATIVE_UTF8STR
:
1389 return MONO_MARSHAL_CONV_UTF8STR_SB
;
1390 case MONO_NATIVE_LPSTR
:
1391 return MONO_MARSHAL_CONV_LPSTR_SB
;
1393 case MONO_NATIVE_LPTSTR
:
1394 return MONO_MARSHAL_CONV_LPTSTR_SB
;
1397 return MONO_MARSHAL_CONV_INVALID
;
1402 * Return whenever a field of a native structure or an array member needs to
1406 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1408 MonoMarshalNative encoding
;
1411 case MONO_TYPE_VALUETYPE
:
1412 /* FIXME: Optimize this */
1414 case MONO_TYPE_OBJECT
:
1415 case MONO_TYPE_CLASS
:
1416 if (t
->data
.klass
== mono_class_try_get_stringbuilder_class ()) {
1418 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
1422 case MONO_TYPE_STRING
:
1423 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1424 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
1431 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
1434 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1437 mono_marshal_lock ();
1440 g_hash_table_new (hash_func
, equal_func
);
1441 mono_memory_barrier ();
1444 mono_marshal_unlock ();
1450 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1452 return get_cache (var
, hash_func
, equal_func
);
1456 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
1460 mono_marshal_lock ();
1461 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1462 mono_marshal_unlock ();
1469 * Create a MonoMethod from MB, set INFO as wrapper info.
1472 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1473 int max_stack
, WrapperInfo
*info
)
1477 res
= mono_mb_create_method (mb
, sig
, max_stack
);
1479 mono_marshal_set_wrapper_info (res
, info
);
1483 /* Create the method from the builder and place it in the cache */
1485 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
1486 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1487 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
1494 mono_marshal_lock ();
1495 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1496 mono_marshal_unlock ();
1499 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
1500 mono_marshal_lock ();
1501 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1504 g_hash_table_insert (cache
, key
, res
);
1505 mono_marshal_set_wrapper_info (res
, info
);
1506 mono_marshal_unlock ();
1510 mono_marshal_unlock ();
1511 mono_free_method (newm
);
1519 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
1520 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1523 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
1527 * mono_marshal_method_from_wrapper:
1530 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
1533 int wrapper_type
= wrapper
->wrapper_type
;
1536 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1539 info
= mono_marshal_get_wrapper_info (wrapper
);
1541 switch (wrapper_type
) {
1542 case MONO_WRAPPER_REMOTING_INVOKE
:
1543 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
1544 case MONO_WRAPPER_XDOMAIN_INVOKE
:
1545 m
= info
->d
.remoting
.method
;
1546 if (wrapper
->is_inflated
) {
1550 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
1551 * contains an uninflated method.
1553 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1554 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1558 case MONO_WRAPPER_SYNCHRONIZED
:
1559 m
= info
->d
.synchronized
.method
;
1560 if (wrapper
->is_inflated
) {
1563 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1564 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1568 case MONO_WRAPPER_UNBOX
:
1569 return info
->d
.unbox
.method
;
1570 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
1571 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
1572 return info
->d
.managed_to_native
.method
;
1575 case MONO_WRAPPER_RUNTIME_INVOKE
:
1576 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
1577 return info
->d
.runtime_invoke
.method
;
1580 case MONO_WRAPPER_DELEGATE_INVOKE
:
1582 return info
->d
.delegate_invoke
.method
;
1591 * mono_marshal_get_wrapper_info:
1593 * Retrieve the WrapperInfo structure associated with WRAPPER.
1596 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
1598 g_assert (wrapper
->wrapper_type
);
1600 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
1604 * mono_marshal_set_wrapper_info:
1606 * Set the WrapperInfo structure associated with the wrapper
1607 * method METHOD to INFO.
1610 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
1614 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1617 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
1622 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
1626 info
= (WrapperInfo
*)mono_image_alloc0 (get_method_image (mb
->method
), sizeof (WrapperInfo
));
1627 info
->subtype
= subtype
;
1632 * get_wrapper_target_class:
1634 * Return the class where a wrapper method should be placed.
1637 get_wrapper_target_class (MonoImage
*image
)
1644 * - can't put all wrappers into an mscorlib class, because they reference
1645 * metadata (signature) so they should be put into the same image as the
1646 * method they wrap, so they are unloaded together.
1647 * - putting them into a class with a type initalizer could cause the
1648 * initializer to be executed which can be a problem if the wrappers are
1650 * - putting them into an inflated class can cause problems if the the
1651 * class is deleted because it references an image which is unloaded.
1652 * To avoid these problems, we put the wrappers into the <Module> class of
1655 if (image_is_dynamic (image
)) {
1656 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
1658 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), error
);
1659 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1667 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
1668 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
1672 * check_generic_wrapper_cache:
1674 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
1675 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
1676 * generic method definition.
1679 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
1682 MonoMethod
*inst
, *def
;
1683 MonoGenericContext
*ctx
;
1685 g_assert (orig_method
->is_inflated
);
1686 ctx
= mono_method_get_context (orig_method
);
1689 * Look for the instance
1691 res
= mono_marshal_find_in_cache (cache
, key
);
1696 * Look for the definition
1698 def
= mono_marshal_find_in_cache (cache
, def_key
);
1701 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1702 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1704 mono_memory_barrier ();
1705 mono_marshal_lock ();
1706 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1708 g_hash_table_insert (cache
, key
, inst
);
1711 mono_marshal_unlock ();
1718 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
1721 MonoMethod
*inst
, *res
;
1724 * We use the same cache for the generic definition and the instances.
1726 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1727 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1728 mono_memory_barrier ();
1729 mono_marshal_lock ();
1730 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1732 g_hash_table_insert (cache
, key
, inst
);
1735 mono_marshal_unlock ();
1740 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
1744 MonoMethod
*inst
, *def
;
1747 * Look for the instance
1749 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
1754 * Look for the definition
1756 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
1758 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1759 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1762 mono_memory_barrier ();
1763 mono_marshal_lock ();
1764 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1766 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1769 mono_marshal_unlock ();
1776 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
1779 MonoMethod
*inst
, *res
;
1780 WrapperInfo
*ginfo
, *info
;
1783 * We use the same cache for the generic definition and the instances.
1785 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1786 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1788 ginfo
= mono_marshal_get_wrapper_info (def
);
1790 info
= (WrapperInfo
*)mono_image_alloc0 (m_class_get_image (def
->klass
), sizeof (WrapperInfo
));
1791 info
->subtype
= ginfo
->subtype
;
1792 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
1793 info
->d
.delegate_invoke
.method
= mono_class_inflate_generic_method_checked (ginfo
->d
.delegate_invoke
.method
, ctx
, error
);
1794 mono_error_assert_ok (error
);
1798 mono_memory_barrier ();
1799 mono_marshal_lock ();
1800 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1802 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1805 mono_marshal_unlock ();
1809 #ifndef ENABLE_ILGEN
1811 emit_delegate_begin_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1817 * mono_marshal_get_delegate_begin_invoke:
1820 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
1822 MonoMethodSignature
*sig
;
1823 MonoMethodBuilder
*mb
;
1827 MonoGenericContext
*ctx
= NULL
;
1828 MonoMethod
*orig_method
= NULL
;
1830 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
1831 !strcmp (method
->name
, "BeginInvoke"));
1834 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
1836 if (method
->is_inflated
) {
1837 orig_method
= method
;
1838 ctx
= &((MonoMethodInflated
*)method
)->context
;
1839 method
= ((MonoMethodInflated
*)method
)->declaring
;
1842 sig
= mono_signature_no_pinvoke (method
);
1848 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1849 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
1853 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_begin_invoke_cache
,
1854 (GHashFunc
)mono_signature_hash
,
1855 (GCompareFunc
)mono_metadata_signature_equal
);
1856 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
1860 g_assert (sig
->hasthis
);
1862 name
= mono_signature_to_name (sig
, "begin_invoke");
1864 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1866 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1869 get_marshal_cb ()->emit_delegate_begin_invoke (mb
, sig
);
1871 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
1872 info
->d
.delegate_invoke
.method
= method
;
1876 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1877 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
1879 res
= mono_mb_create_and_cache_full (cache
, sig
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
1886 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1888 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1891 MonoDomain
*domain
= mono_domain_get ();
1892 MonoAsyncResult
*ares
;
1893 MonoMethod
*method
= NULL
;
1894 MonoMethodSignature
*sig
;
1895 MonoMethodMessage
*msg
;
1896 MonoObject
*res
, *exc
;
1897 MonoArray
*out_args
;
1900 g_assert (delegate
);
1902 if (!delegate
->method_info
) {
1903 g_assert (delegate
->method
);
1904 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, error
);
1905 if (!mono_error_ok (error
)) {
1906 mono_error_set_pending_exception (error
);
1909 MONO_OBJECT_SETREF_INTERNAL (delegate
, method_info
, rm
);
1912 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
1913 g_assert_not_reached ();
1915 klass
= delegate
->object
.vtable
->klass
;
1917 method
= mono_get_delegate_end_invoke_checked (klass
, error
);
1918 mono_error_assert_ok (error
);
1919 g_assert (method
!= NULL
);
1921 sig
= mono_signature_no_pinvoke (method
);
1923 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, error
);
1924 if (mono_error_set_pending_exception (error
))
1927 ares
= (MonoAsyncResult
*)mono_array_get_internal (msg
->args
, gpointer
, sig
->param_count
- 1);
1929 mono_error_set_remoting (error
, "The async result object is null or of an unexpected type.");
1930 mono_error_set_pending_exception (error
);
1934 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
1935 mono_error_set_invalid_operation (error
,
1936 "%s", "The IAsyncResult object provided does not match this delegate.");
1937 mono_error_set_pending_exception (error
);
1941 #ifndef DISABLE_REMOTING
1942 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1943 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1944 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
1945 if (!mono_error_ok (error
)) {
1946 mono_error_set_pending_exception (error
);
1949 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, error
);
1950 if (mono_error_set_pending_exception (error
))
1952 msg
->call_type
= CallType_EndInvoke
;
1953 MONO_OBJECT_SETREF_INTERNAL (msg
, async_result
, ares
);
1954 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1955 if (!mono_error_ok (error
)) {
1956 mono_error_set_pending_exception (error
);
1962 res
= mono_threadpool_end_invoke (ares
, &out_args
, &exc
, error
);
1963 if (mono_error_set_pending_exception (error
))
1968 if (((MonoException
*)exc
)->stack_trace
) {
1969 ERROR_DECL (inner_error
);
1970 char *strace
= mono_string_to_utf8_checked_internal (((MonoException
*)exc
)->stack_trace
, inner_error
);
1971 if (is_ok (inner_error
)) {
1973 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
1975 MonoString
*tmp_str
= mono_string_new_checked (domain
, tmp
, inner_error
);
1977 if (is_ok (inner_error
))
1978 MONO_OBJECT_SETREF_INTERNAL (((MonoException
*)exc
), stack_trace
, tmp_str
);
1980 if (!is_ok (inner_error
))
1981 mono_error_cleanup (inner_error
); /* no stack trace, but at least throw the original exception */
1983 mono_set_pending_exception ((MonoException
*)exc
);
1986 mono_method_return_message_restore (method
, params
, out_args
, error
);
1987 mono_error_set_pending_exception (error
);
1991 #ifndef ENABLE_ILGEN
1993 emit_delegate_end_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1999 * mono_marshal_get_delegate_end_invoke:
2002 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
2004 MonoMethodSignature
*sig
;
2005 MonoMethodBuilder
*mb
;
2009 MonoGenericContext
*ctx
= NULL
;
2010 MonoMethod
*orig_method
= NULL
;
2012 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2013 !strcmp (method
->name
, "EndInvoke"));
2016 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
2018 if (method
->is_inflated
) {
2019 orig_method
= method
;
2020 ctx
= &((MonoMethodInflated
*)method
)->context
;
2021 method
= ((MonoMethodInflated
*)method
)->declaring
;
2024 sig
= mono_signature_no_pinvoke (method
);
2030 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2031 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2035 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_end_invoke_cache
,
2036 (GHashFunc
)mono_signature_hash
,
2037 (GCompareFunc
)mono_metadata_signature_equal
);
2038 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2042 g_assert (sig
->hasthis
);
2044 name
= mono_signature_to_name (sig
, "end_invoke");
2046 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2048 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2051 get_marshal_cb ()->emit_delegate_end_invoke (mb
, sig
);
2053 WrapperInfo
*info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
2054 info
->d
.delegate_invoke
.method
= method
;
2058 def
= mono_mb_create_and_cache_full (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2059 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2061 res
= mono_mb_create_and_cache_full (cache
, sig
,
2062 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2071 MonoMethodSignature
*sig
;
2073 } SignaturePointerPair
;
2076 signature_pointer_pair_hash (gconstpointer data
)
2078 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
2080 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
2084 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
2086 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
2087 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
2091 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
2093 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
2095 return pair
->pointer
== user_data
;
2099 free_signature_pointer_pair (SignaturePointerPair
*pair
)
2104 #ifndef ENABLE_ILGEN
2106 mb_skip_visibility_noilgen (MonoMethodBuilder
*mb
)
2111 mb_set_dynamic_noilgen (MonoMethodBuilder
*mb
)
2116 mb_emit_exception_noilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
2121 mb_emit_exception_for_error_noilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
2126 emit_delegate_invoke_internal_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodSignature
*invoke_sig
, gboolean static_method_with_first_arg_bound
, gboolean callvirt
, gboolean closed_over_null
, MonoMethod
*method
, MonoMethod
*target_method
, MonoClass
*target_class
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
)
2132 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
2134 MonoMethodSignature
*sig
, *invoke_sig
;
2135 MonoMethodBuilder
*mb
;
2138 gpointer cache_key
= NULL
;
2139 SignaturePointerPair key
= { NULL
, NULL
};
2140 SignaturePointerPair
*new_key
;
2142 MonoClass
*target_class
= NULL
;
2143 gboolean closed_over_null
= FALSE
;
2144 MonoGenericContext
*ctx
= NULL
;
2145 MonoGenericContainer
*container
= NULL
;
2146 MonoMethod
*orig_method
= method
;
2148 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
2151 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2152 !strcmp (method
->name
, "Invoke"));
2154 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2157 * If the delegate target is null, and the target method is not static, a virtual
2158 * call is made to that method with the first delegate argument as this. This is
2159 * a non-documented .NET feature.
2162 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
2163 if (target_method
->is_inflated
) {
2165 MonoType
*target_type
;
2167 g_assert (method
->signature
->hasthis
);
2168 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
2169 mono_method_get_context (method
), error
);
2170 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
2171 target_class
= mono_class_from_mono_type_internal (target_type
);
2173 target_class
= target_method
->klass
;
2176 closed_over_null
= sig
->param_count
== mono_method_signature_internal (target_method
)->param_count
;
2179 if (static_method_with_first_arg_bound
) {
2180 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
2181 g_assert (!callvirt
);
2182 invoke_sig
= mono_method_signature_internal (target_method
);
2184 * The wrapper has a different lifetime from the method to be invoked.
2185 * If the method is dynamic we don't want to be using its signature
2186 * in the wrapper since it could get freed early.
2188 if (method_is_dynamic (target_method
))
2189 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (target_method
), invoke_sig
);
2193 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
2195 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
2196 ctx
= &((MonoMethodInflated
*)method
)->context
;
2197 method
= ((MonoMethodInflated
*)method
)->declaring
;
2199 container
= mono_method_get_generic_container (method
);
2201 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
2202 g_assert (container
);
2204 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2211 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2212 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2215 cache_key
= method
->klass
;
2216 } else if (static_method_with_first_arg_bound
) {
2217 cache
= get_cache (&get_method_image (target_method
)->delegate_bound_static_invoke_cache
,
2218 (GHashFunc
)mono_signature_hash
,
2219 (GCompareFunc
)mono_metadata_signature_equal
);
2221 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
2223 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
2226 cache_key
= invoke_sig
;
2227 } else if (callvirt
) {
2228 GHashTable
**cache_ptr
;
2230 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
2232 /* We need to cache the signature+method pair */
2233 mono_marshal_lock ();
2235 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
2237 key
.sig
= invoke_sig
;
2238 key
.pointer
= target_method
;
2239 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
2240 mono_marshal_unlock ();
2244 // Inflated methods should not be in this cache because it's not stored on the imageset.
2245 g_assert (!method
->is_inflated
);
2246 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_invoke_cache
,
2247 (GHashFunc
)mono_signature_hash
,
2248 (GCompareFunc
)mono_metadata_signature_equal
);
2249 res
= mono_marshal_find_in_cache (cache
, sig
);
2255 if (!static_method_with_first_arg_bound
) {
2256 invoke_sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
2257 invoke_sig
->hasthis
= 0;
2260 if (static_method_with_first_arg_bound
)
2261 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
2262 else if (closed_over_null
)
2263 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
2265 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
2267 name
= mono_signature_to_name (invoke_sig
, "invoke");
2269 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2271 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2274 get_marshal_cb ()->emit_delegate_invoke_internal (mb
, sig
, invoke_sig
, static_method_with_first_arg_bound
, callvirt
, closed_over_null
, method
, target_method
, target_class
, ctx
, container
);
2276 get_marshal_cb ()->mb_skip_visibility (mb
);
2278 info
= mono_wrapper_info_create (mb
, subtype
);
2279 info
->d
.delegate_invoke
.method
= method
;
2284 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2285 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2286 } else if (callvirt
) {
2287 new_key
= g_new0 (SignaturePointerPair
, 1);
2290 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
2294 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2298 /* mono_method_print_code (res); */
2304 * mono_marshal_get_delegate_invoke:
2305 * The returned method invokes all methods in a multicast delegate.
2308 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
2310 gboolean callvirt
= FALSE
;
2311 gboolean static_method_with_first_arg_bound
= FALSE
;
2312 MonoMethod
*target_method
= NULL
;
2313 MonoMethodSignature
*sig
;
2315 sig
= mono_signature_no_pinvoke (method
);
2317 if (del
&& !del
->target
&& del
->method
&& mono_method_signature_internal (del
->method
)->hasthis
) {
2319 target_method
= del
->method
;
2322 if (del
&& del
->method
&& mono_method_signature_internal (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2323 static_method_with_first_arg_bound
= TRUE
;
2324 target_method
= del
->method
;
2327 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
2331 MonoMethodSignature
*ctor_sig
;
2332 MonoMethodSignature
*sig
;
2335 /* protected by the marshal lock, contains CtorSigPair pointers */
2336 static GSList
*strsig_list
= NULL
;
2338 static MonoMethodSignature
*
2339 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
2341 MonoMethodSignature
*callsig
;
2345 mono_marshal_lock ();
2347 for (item
= strsig_list
; item
; item
= item
->next
) {
2348 cs
= (CtorSigPair
*)item
->data
;
2349 /* mono_metadata_signature_equal () is safe to call with the marshal lock
2350 * because it is lock-free.
2352 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
2357 mono_marshal_unlock ();
2361 static MonoMethodSignature
*
2362 add_string_ctor_signature (MonoMethod
*method
)
2364 MonoMethodSignature
*callsig
;
2367 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2368 callsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2369 cs
= g_new (CtorSigPair
, 1);
2371 cs
->ctor_sig
= mono_method_signature_internal (method
);
2373 mono_marshal_lock ();
2374 strsig_list
= g_slist_prepend (strsig_list
, cs
);
2375 mono_marshal_unlock ();
2380 * mono_marshal_get_string_ctor_signature:
2382 * Return the modified signature used by string ctors (they return the newly created
2385 MonoMethodSignature
*
2386 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
2388 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2390 sig
= add_string_ctor_signature (method
);
2396 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
2399 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
)))
2402 /* The result needs loaded indirectly */
2406 /* Can't share this with 'I' as that needs another indirection */
2407 return m_class_get_this_arg (mono_defaults
.int_class
);
2410 if (MONO_TYPE_IS_REFERENCE (t
))
2411 return mono_get_object_type ();
2414 /* The result needs to be boxed */
2419 /* Can't share these as the argument needs to be loaded using sign/zero extension */
2422 return m_class_get_byval_arg (mono_defaults.sbyte_class);
2424 return m_class_get_byval_arg (mono_defaults.int16_class);
2426 return mono_get_int32_type ();
2429 return m_class_get_byval_arg (mono_defaults
.int64_class
);
2430 case MONO_TYPE_BOOLEAN
:
2431 return m_class_get_byval_arg (mono_defaults
.byte_class
);
2432 case MONO_TYPE_CHAR
:
2433 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
2435 return mono_get_int_type ();
2436 case MONO_TYPE_VALUETYPE
:
2437 if (m_class_is_enumtype (t
->data
.klass
)) {
2438 t
= mono_class_enum_basetype_internal (t
->data
.klass
);
2448 * mono_marshal_get_runtime_invoke_sig:
2450 * Return a common signature used for sharing runtime invoke wrappers.
2452 static MonoMethodSignature
*
2453 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
2455 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
2458 res
->generic_param_count
= 0;
2459 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
2460 for (i
= 0; i
< res
->param_count
; ++i
)
2461 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
2467 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
2469 /* Can't share wrappers which return a vtype since it needs to be boxed */
2470 if (sig1
->ret
!= sig2
->ret
&& !(MONO_TYPE_IS_REFERENCE (sig1
->ret
) && MONO_TYPE_IS_REFERENCE (sig2
->ret
)) && !mono_metadata_type_equal (sig1
->ret
, sig2
->ret
))
2473 return mono_metadata_signature_equal (sig1
, sig2
);
2476 struct _MonoWrapperMethodCacheKey
{
2479 gboolean need_direct_wrapper
;
2482 struct _MonoWrapperSignatureCacheKey
{
2483 MonoMethodSignature
*signature
;
2487 typedef struct _MonoWrapperMethodCacheKey MonoWrapperMethodCacheKey
;
2488 typedef struct _MonoWrapperSignatureCacheKey MonoWrapperSignatureCacheKey
;
2491 wrapper_cache_method_key_hash (MonoWrapperMethodCacheKey
*key
)
2493 return mono_aligned_addr_hash (key
->method
) ^ (((!!key
->virtual_
) << 17) | ((!!key
->need_direct_wrapper
) << 19) * 17);
2497 wrapper_cache_signature_key_hash (MonoWrapperSignatureCacheKey
*key
)
2499 return mono_signature_hash (key
->signature
) ^ (((!!key
->valuetype
) << 18) * 17);
2503 wrapper_cache_method_key_equal (MonoWrapperMethodCacheKey
*key1
, MonoWrapperMethodCacheKey
*key2
)
2505 if (key1
->virtual_
!= key2
->virtual_
|| key1
->need_direct_wrapper
!= key2
->need_direct_wrapper
)
2507 return key1
->method
== key2
->method
;
2511 wrapper_cache_signature_key_equal (MonoWrapperSignatureCacheKey
*key1
, MonoWrapperSignatureCacheKey
*key2
)
2513 if (key1
->valuetype
!= key2
->valuetype
)
2515 return runtime_invoke_signature_equal (key1
->signature
, key2
->signature
);
2519 * mono_marshal_get_runtime_invoke:
2520 * Generates IL code for the runtime invoke function:
2522 * <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
2524 * We also catch exceptions if \p exc is not NULL.
2525 * If \p virtual is TRUE, then \p method is invoked virtually on \p this. This is useful since
2526 * it means that the compiled code for \p method does not have to be looked up
2527 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
2528 * its \p method argument.
2531 mono_marshal_get_runtime_invoke_full (MonoMethod
*method
, gboolean virtual_
, gboolean need_direct_wrapper
)
2533 MonoMethodSignature
*sig
, *csig
, *callsig
;
2534 MonoMethodBuilder
*mb
;
2535 GHashTable
*method_cache
= NULL
, *sig_cache
= NULL
;
2536 GHashTable
**cache_table
= NULL
;
2537 MonoClass
*target_klass
;
2538 MonoMethod
*res
= NULL
;
2539 static MonoMethodSignature
*cctor_signature
= NULL
;
2540 static MonoMethodSignature
*finalize_signature
= NULL
;
2542 const char *param_names
[16];
2544 MonoWrapperMethodCacheKey
*method_key
;
2545 MonoWrapperMethodCacheKey method_key_lookup_only
;
2546 memset (&method_key_lookup_only
, 0, sizeof (method_key_lookup_only
));
2547 method_key_lookup_only
.method
= method
;
2548 method_key_lookup_only
.virtual_
= virtual_
;
2549 method_key_lookup_only
.need_direct_wrapper
= need_direct_wrapper
;
2550 method_key
= &method_key_lookup_only
;
2554 if (!cctor_signature
) {
2555 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2556 cctor_signature
->ret
= mono_get_void_type ();
2558 if (!finalize_signature
) {
2559 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2560 finalize_signature
->ret
= mono_get_void_type ();
2561 finalize_signature
->hasthis
= 1;
2564 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_method_cache
;
2565 method_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_method_key_hash
, (GCompareFunc
) wrapper_cache_method_key_equal
);
2567 res
= mono_marshal_find_in_cache (method_cache
, method_key
);
2571 if (method
->string_ctor
) {
2572 callsig
= lookup_string_ctor_signature (mono_method_signature_internal (method
));
2574 callsig
= add_string_ctor_signature (method
);
2576 if (method_is_dynamic (method
))
2577 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
2579 callsig
= mono_method_signature_internal (method
);
2582 sig
= mono_method_signature_internal (method
);
2584 target_klass
= get_wrapper_target_class (m_class_get_image (method
->klass
));
2586 /* Try to share wrappers for non-corlib methods with simple signatures */
2587 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
2588 callsig
= cctor_signature
;
2589 target_klass
= mono_defaults
.object_class
;
2590 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
2591 callsig
= finalize_signature
;
2592 target_klass
= mono_defaults
.object_class
;
2595 if (need_direct_wrapper
|| virtual_
) {
2596 /* Already searched at the start. We cannot cache those wrappers based
2597 * on signatures because they contain a reference to the method */
2599 MonoMethodSignature
*tmp_sig
;
2601 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
2602 MonoWrapperSignatureCacheKey sig_key
;
2603 memset (&sig_key
, 0, sizeof (sig_key
));
2604 sig_key
.signature
= callsig
;
2605 sig_key
.valuetype
= m_class_is_valuetype (method
->klass
);
2607 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_signature_cache
;
2608 sig_cache
= get_cache (cache_table
, (GHashFunc
) wrapper_cache_signature_key_hash
, (GCompareFunc
) wrapper_cache_signature_key_equal
);
2610 /* from mono_marshal_find_in_cache */
2611 mono_marshal_lock ();
2612 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, &sig_key
);
2613 mono_marshal_unlock ();
2620 /* Make a copy of the signature from the image mempool */
2622 callsig
= mono_metadata_signature_dup_full (m_class_get_image (target_klass
), callsig
);
2626 csig
= mono_metadata_signature_alloc (m_class_get_image (target_klass
), 4);
2628 MonoType
*object_type
= mono_get_object_type ();
2629 MonoType
*int_type
= mono_get_int_type ();
2631 csig
->ret
= object_type
;
2632 if (m_class_is_valuetype (method
->klass
) && mono_method_signature_internal (method
)->hasthis
)
2633 csig
->params
[0] = get_runtime_invoke_type (m_class_get_this_arg (method
->klass
), FALSE
);
2635 csig
->params
[0] = object_type
;
2636 csig
->params
[1] = int_type
;
2637 csig
->params
[2] = int_type
;
2638 csig
->params
[3] = int_type
;
2641 /* This is called from runtime code so it has to be cdecl */
2642 csig
->call_convention
= MONO_CALL_C
;
2645 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : (need_direct_wrapper
? "runtime_invoke_direct" : "runtime_invoke"));
2646 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2649 param_names
[0] = "this";
2650 param_names
[1] = "params";
2651 param_names
[2] = "exc";
2652 param_names
[3] = "method";
2654 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, m_class_get_image (target_klass
), method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
2656 method_key
= g_new (MonoWrapperMethodCacheKey
, 1);
2657 memcpy (method_key
, &method_key_lookup_only
, sizeof (MonoWrapperMethodCacheKey
));
2659 if (need_direct_wrapper
|| virtual_
) {
2660 get_marshal_cb ()->mb_skip_visibility (mb
);
2661 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
2662 info
->d
.runtime_invoke
.method
= method
;
2663 res
= mono_mb_create_and_cache_full (method_cache
, method_key
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
2665 MonoWrapperSignatureCacheKey
*sig_key
= g_new0 (MonoWrapperSignatureCacheKey
, 1);
2666 sig_key
->signature
= callsig
;
2667 sig_key
->valuetype
= m_class_is_valuetype (method
->klass
);
2669 /* taken from mono_mb_create_and_cache */
2670 mono_marshal_lock ();
2671 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2672 mono_marshal_unlock ();
2674 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2675 info
->d
.runtime_invoke
.sig
= callsig
;
2677 /* Somebody may have created it before us */
2680 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2682 mono_marshal_lock ();
2683 res
= (MonoMethod
*)g_hash_table_lookup (sig_cache
, sig_key
);
2686 g_hash_table_insert (sig_cache
, sig_key
, res
);
2687 g_hash_table_insert (method_cache
, method_key
, res
);
2689 mono_free_method (newm
);
2691 g_free (method_key
);
2693 mono_marshal_unlock ();
2696 g_free (method_key
);
2699 /* end mono_mb_create_and_cache */
2708 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
2710 gboolean need_direct_wrapper
= FALSE
;
2713 need_direct_wrapper
= TRUE
;
2715 if (method
->dynamic
)
2716 need_direct_wrapper
= TRUE
;
2718 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2719 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2721 * Array Get/Set/Address methods. The JIT implements them using inline code
2722 * so we need to create an invoke wrapper which calls the method directly.
2724 need_direct_wrapper
= TRUE
;
2727 if (method
->string_ctor
) {
2728 /* Can't share this as we push a string as this */
2729 need_direct_wrapper
= TRUE
;
2732 return mono_marshal_get_runtime_invoke_full (method
, virtual_
, need_direct_wrapper
);
2735 #ifndef ENABLE_ILGEN
2737 emit_runtime_invoke_body_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
2738 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
2739 gboolean virtual_
, gboolean need_direct_wrapper
)
2744 emit_runtime_invoke_dynamic_noilgen (MonoMethodBuilder
*mb
)
2750 * mono_marshal_get_runtime_invoke_dynamic:
2752 * Return a method which can be used to invoke managed methods from native code
2754 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
2755 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
2756 * ARGS should point to an architecture specific structure containing
2757 * the arguments and space for the return value.
2758 * The other arguments are the same as for runtime_invoke (), except that
2759 * ARGS should contain the this argument too.
2760 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
2761 * is only one copy of it, which is useful in full-aot.
2764 mono_marshal_get_runtime_invoke_dynamic (void)
2766 static MonoMethod
*method
;
2767 MonoMethodSignature
*csig
;
2768 MonoMethodBuilder
*mb
;
2775 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
2777 MonoType
*void_type
= mono_get_void_type ();
2778 MonoType
*int_type
= mono_get_int_type ();
2780 csig
->ret
= void_type
;
2781 csig
->params
[0] = int_type
;
2782 csig
->params
[1] = int_type
;
2783 csig
->params
[2] = int_type
;
2784 csig
->params
[3] = int_type
;
2786 name
= g_strdup ("runtime_invoke_dynamic");
2787 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2790 get_marshal_cb ()->emit_runtime_invoke_dynamic (mb
);
2792 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
2794 mono_marshal_lock ();
2795 /* double-checked locking */
2797 method
= mono_mb_create (mb
, csig
, 16, info
);
2799 mono_marshal_unlock ();
2807 * mono_marshal_get_runtime_invoke_for_sig:
2809 * Return a runtime invoke wrapper for a given signature.
2812 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
2814 MonoMethodSignature
*csig
, *callsig
;
2815 MonoMethodBuilder
*mb
;
2817 GHashTable
*cache
= NULL
;
2818 GHashTable
**cache_table
= NULL
;
2819 MonoMethod
*res
= NULL
;
2821 const char *param_names
[16];
2824 /* A simplified version of mono_marshal_get_runtime_invoke */
2826 image
= mono_defaults
.corlib
;
2828 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
2830 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
2832 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
2833 (GCompareFunc
)runtime_invoke_signature_equal
);
2835 /* from mono_marshal_find_in_cache */
2836 mono_marshal_lock ();
2837 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2838 mono_marshal_unlock ();
2845 /* Make a copy of the signature from the image mempool */
2846 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
2848 MonoType
*object_type
= mono_get_object_type ();
2849 MonoType
*int_type
= mono_get_int_type ();
2850 csig
= mono_metadata_signature_alloc (image
, 4);
2851 csig
->ret
= object_type
;
2852 csig
->params
[0] = object_type
;
2853 csig
->params
[1] = int_type
;
2854 csig
->params
[2] = int_type
;
2855 csig
->params
[3] = int_type
;
2858 /* This is called from runtime code so it has to be cdecl */
2859 csig
->call_convention
= MONO_CALL_C
;
2862 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
2863 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2866 param_names
[0] = "this";
2867 param_names
[1] = "params";
2868 param_names
[2] = "exc";
2869 param_names
[3] = "method";
2871 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
2873 /* taken from mono_mb_create_and_cache */
2874 mono_marshal_lock ();
2875 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2876 mono_marshal_unlock ();
2878 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2879 info
->d
.runtime_invoke
.sig
= callsig
;
2881 /* Somebody may have created it before us */
2884 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2886 mono_marshal_lock ();
2887 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2890 g_hash_table_insert (cache
, callsig
, res
);
2892 mono_free_method (newm
);
2894 mono_marshal_unlock ();
2897 /* end mono_mb_create_and_cache */
2904 #ifndef ENABLE_ILGEN
2906 emit_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
2911 emit_return_noilgen (MonoMethodBuilder
*mb
)
2917 * mono_marshal_get_icall_wrapper:
2918 * Generates IL code for the JIT icall wrapper. The generated method
2919 * calls the unmanaged code in \p callinfo->func.
2922 mono_marshal_get_icall_wrapper (MonoJitICallInfo
*callinfo
, gboolean check_exceptions
)
2924 MonoMethodSignature
*csig
, *csig2
;
2925 MonoMethodBuilder
*mb
;
2929 gconstpointer
const func
= callinfo
->func
;
2931 GHashTable
*cache
= get_cache (& m_class_get_image (mono_defaults
.object_class
)->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
2932 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
2935 MonoMethodSignature
*const sig
= callinfo
->sig
;
2936 g_assert (sig
->pinvoke
);
2938 char *const name
= g_strdup_printf ("__icall_wrapper_%s", callinfo
->name
);
2939 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
2941 mb
->method
->save_lmf
= 1;
2943 /* Add an explicit this argument */
2945 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
2947 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2949 get_marshal_cb ()->emit_icall_wrapper (mb
, callinfo
, csig2
, check_exceptions
);
2951 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2953 if (csig
->call_convention
== MONO_CALL_VARARG
)
2954 csig
->call_convention
= 0;
2956 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
2957 info
->d
.icall
.jit_icall_id
= mono_jit_icall_info_id (callinfo
);
2958 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
2966 mono_marshal_get_aot_init_wrapper_name (MonoAotInitSubtype subtype
)
2968 const char *name
= NULL
;
2970 case AOT_INIT_METHOD
:
2971 name
= "init_method";
2973 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
2974 name
= "init_method_gshared_mrgctx";
2976 case AOT_INIT_METHOD_GSHARED_THIS
:
2977 name
= "init_method_gshared_this";
2979 case AOT_INIT_METHOD_GSHARED_VTABLE
:
2980 name
= "init_method_gshared_vtable";
2983 g_assert_not_reached ();
2989 mono_marshal_get_aot_init_wrapper (MonoAotInitSubtype subtype
)
2991 MonoMethodBuilder
*mb
;
2994 MonoMethodSignature
*csig
= NULL
;
2995 MonoType
*void_type
= mono_get_void_type ();
2996 MonoType
*int_type
= mono_get_int_type ();
2997 const char *name
= mono_marshal_get_aot_init_wrapper_name (subtype
);
3000 case AOT_INIT_METHOD
:
3001 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
3002 csig
->ret
= void_type
;
3003 csig
->params
[0] = int_type
;
3004 csig
->params
[1] = int_type
;
3006 case AOT_INIT_METHOD_GSHARED_MRGCTX
:
3007 case AOT_INIT_METHOD_GSHARED_THIS
:
3008 case AOT_INIT_METHOD_GSHARED_VTABLE
:
3009 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3010 csig
->ret
= void_type
;
3011 csig
->params
[0] = int_type
;
3012 csig
->params
[1] = int_type
;
3013 csig
->params
[2] = int_type
;
3016 g_assert_not_reached ();
3019 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_OTHER
);
3021 // Just stub out the method with a "CEE_RET"
3022 // Our codegen backend generates other code here
3023 get_marshal_cb ()->emit_return (mb
);
3025 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_AOT_INIT
);
3026 info
->d
.aot_init
.subtype
= subtype
;
3027 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
3033 #ifndef ENABLE_ILGEN
3035 emit_marshal_custom_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3036 MonoMarshalSpec
*spec
,
3037 int conv_arg
, MonoType
**conv_arg_type
,
3038 MarshalAction action
)
3040 MonoType
*int_type
= mono_get_int_type ();
3041 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
3042 *conv_arg_type
= int_type
;
3047 emit_marshal_asany_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3048 MonoMarshalSpec
*spec
,
3049 int conv_arg
, MonoType
**conv_arg_type
,
3050 MarshalAction action
)
3056 emit_marshal_vtype_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3057 MonoMarshalSpec
*spec
,
3058 int conv_arg
, MonoType
**conv_arg_type
,
3059 MarshalAction action
)
3065 emit_marshal_string_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3066 MonoMarshalSpec
*spec
,
3067 int conv_arg
, MonoType
**conv_arg_type
,
3068 MarshalAction action
)
3070 MonoType
*int_type
= mono_get_int_type ();
3072 case MARSHAL_ACTION_CONV_IN
:
3073 *conv_arg_type
= int_type
;
3075 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3076 *conv_arg_type
= int_type
;
3084 emit_marshal_safehandle_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3085 MonoMarshalSpec
*spec
, int conv_arg
,
3086 MonoType
**conv_arg_type
, MarshalAction action
)
3088 MonoType
*int_type
= mono_get_int_type ();
3089 if (action
== MARSHAL_ACTION_CONV_IN
)
3090 *conv_arg_type
= int_type
;
3096 emit_marshal_handleref_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3097 MonoMarshalSpec
*spec
, int conv_arg
,
3098 MonoType
**conv_arg_type
, MarshalAction action
)
3100 MonoType
*int_type
= mono_get_int_type ();
3101 if (action
== MARSHAL_ACTION_CONV_IN
)
3102 *conv_arg_type
= int_type
;
3108 emit_marshal_object_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3109 MonoMarshalSpec
*spec
,
3110 int conv_arg
, MonoType
**conv_arg_type
,
3111 MarshalAction action
)
3113 MonoType
*int_type
= mono_get_int_type ();
3114 if (action
== MARSHAL_ACTION_CONV_IN
)
3115 *conv_arg_type
= int_type
;
3120 emit_marshal_variant_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3121 MonoMarshalSpec
*spec
,
3122 int conv_arg
, MonoType
**conv_arg_type
,
3123 MarshalAction action
)
3125 g_assert_not_reached ();
3130 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
3132 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
3133 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
3135 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
3137 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
3147 #ifndef ENABLE_ILGEN
3149 emit_marshal_array_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3150 MonoMarshalSpec
*spec
,
3151 int conv_arg
, MonoType
**conv_arg_type
,
3152 MarshalAction action
)
3154 MonoType
*int_type
= mono_get_int_type ();
3155 MonoType
*object_type
= mono_get_object_type ();
3157 case MARSHAL_ACTION_CONV_IN
:
3158 *conv_arg_type
= object_type
;
3160 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3161 *conv_arg_type
= int_type
;
3169 mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
3172 return mono_get_int32_type ();
3174 switch (spec
->native
) {
3175 case MONO_NATIVE_I1
:
3176 case MONO_NATIVE_U1
:
3177 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3178 case MONO_NATIVE_VARIANTBOOL
:
3179 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
3180 return m_class_get_byval_arg (mono_defaults
.int16_class
);
3181 case MONO_NATIVE_BOOLEAN
:
3182 return mono_get_int32_type ();
3184 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3185 return mono_get_int32_type ();
3191 mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
3193 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3195 switch (spec
->native
) {
3196 case MONO_NATIVE_I1
:
3197 case MONO_NATIVE_U1
:
3198 conv_arg_class
= mono_defaults
.byte_class
;
3199 if (ldop
) *ldop
= CEE_LDIND_I1
;
3201 case MONO_NATIVE_VARIANTBOOL
:
3202 conv_arg_class
= mono_defaults
.int16_class
;
3203 if (ldop
) *ldop
= CEE_LDIND_I2
;
3205 case MONO_NATIVE_BOOLEAN
:
3208 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3211 return conv_arg_class
;
3214 #ifndef ENABLE_ILGEN
3216 emit_marshal_boolean_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3217 MonoMarshalSpec
*spec
,
3218 int conv_arg
, MonoType
**conv_arg_type
,
3219 MarshalAction action
)
3221 MonoType
*int_type
= mono_get_int_type ();
3223 case MARSHAL_ACTION_CONV_IN
:
3225 *conv_arg_type
= int_type
;
3227 *conv_arg_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, NULL
);
3230 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3231 MonoClass
* conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
3233 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3235 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3244 emit_marshal_ptr_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3245 MonoMarshalSpec
*spec
, int conv_arg
,
3246 MonoType
**conv_arg_type
, MarshalAction action
)
3252 emit_marshal_char_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3253 MonoMarshalSpec
*spec
, int conv_arg
,
3254 MonoType
**conv_arg_type
, MarshalAction action
)
3260 emit_marshal_scalar_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3261 MonoMarshalSpec
*spec
, int conv_arg
,
3262 MonoType
**conv_arg_type
, MarshalAction action
)
3269 mono_emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3270 MonoMarshalSpec
*spec
, int conv_arg
,
3271 MonoType
**conv_arg_type
, MarshalAction action
)
3273 /* Ensure that we have marshalling info for this param */
3274 mono_marshal_load_type_info (mono_class_from_mono_type_internal (t
));
3276 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
3277 return get_marshal_cb ()->emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3279 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
3280 return get_marshal_cb ()->emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3283 case MONO_TYPE_VALUETYPE
:
3284 if (t
->data
.klass
== mono_class_try_get_handleref_class ())
3285 return get_marshal_cb ()->emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3287 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3288 case MONO_TYPE_STRING
:
3289 return get_marshal_cb ()->emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3290 case MONO_TYPE_CLASS
:
3291 case MONO_TYPE_OBJECT
:
3292 #if !defined(DISABLE_COM)
3293 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
3294 return get_marshal_cb ()->emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3297 #if !defined(DISABLE_COM)
3298 if (spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
3299 spec
->native
== MONO_NATIVE_IDISPATCH
||
3300 spec
->native
== MONO_NATIVE_INTERFACE
))
3301 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3302 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
3303 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
3304 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
3305 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3308 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
3309 mono_class_is_subclass_of_internal (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
3310 return get_marshal_cb ()->emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3312 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3313 case MONO_TYPE_ARRAY
:
3314 case MONO_TYPE_SZARRAY
:
3315 return get_marshal_cb ()->emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3316 case MONO_TYPE_BOOLEAN
:
3317 return get_marshal_cb ()->emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3319 return get_marshal_cb ()->emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3320 case MONO_TYPE_CHAR
:
3321 return get_marshal_cb ()->emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3334 case MONO_TYPE_FNPTR
:
3335 return get_marshal_cb ()->emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3336 case MONO_TYPE_GENERICINST
:
3337 if (mono_type_generic_inst_is_valuetype (t
))
3338 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3340 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3346 #ifndef ENABLE_ILGEN
3348 emit_create_string_hack_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
3353 emit_native_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*pinfo
)
3359 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean set_default
)
3361 MonoMethodSignature
*sig
;
3366 * Under windows, delegates passed to native code must use the STDCALL
3367 * calling convention.
3370 csig
->call_convention
= MONO_CALL_STDCALL
;
3373 sig
= mono_method_signature_internal (method
);
3377 cmod_count
= mono_type_custom_modifier_count (sig
->ret
);
3379 /* Change default calling convention if needed */
3380 /* Why is this a modopt ? */
3381 if (cmod_count
== 0)
3384 for (i
= 0; i
< cmod_count
; ++i
) {
3387 MonoType
*cmod_type
= mono_type_get_custom_modifier (sig
->ret
, i
, &required
, error
);
3388 mono_error_assert_ok (error
);
3389 MonoClass
*cmod_class
= mono_class_from_mono_type_internal (cmod_type
);
3390 if ((m_class_get_image (cmod_class
) == mono_defaults
.corlib
) && !strcmp (m_class_get_name_space (cmod_class
), "System.Runtime.CompilerServices")) {
3391 const char *cmod_class_name
= m_class_get_name (cmod_class
);
3392 if (!strcmp (cmod_class_name
, "CallConvCdecl"))
3393 csig
->call_convention
= MONO_CALL_C
;
3394 else if (!strcmp (cmod_class_name
, "CallConvStdcall"))
3395 csig
->call_convention
= MONO_CALL_STDCALL
;
3396 else if (!strcmp (cmod_class_name
, "CallConvFastcall"))
3397 csig
->call_convention
= MONO_CALL_FASTCALL
;
3398 else if (!strcmp (cmod_class_name
, "CallConvThiscall"))
3399 csig
->call_convention
= MONO_CALL_THISCALL
;
3405 * mono_marshal_get_native_wrapper:
3406 * \param method The \c MonoMethod to wrap.
3407 * \param check_exceptions Whenever to check for pending exceptions
3409 * Generates IL code for the pinvoke wrapper. The generated method
3410 * calls the unmanaged code in \c piinfo->addr.
3413 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
3415 MonoMethodSignature
*sig
, *csig
;
3416 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
3417 MonoMethodBuilder
*mb
;
3418 MonoMarshalSpec
**mspecs
;
3421 gboolean pinvoke
= FALSE
;
3424 ERROR_DECL (emitted_error
);
3427 g_assert (method
!= NULL
);
3428 g_assert (mono_method_signature_internal (method
)->pinvoke
);
3430 GHashTable
**cache_ptr
;
3432 MonoType
*string_type
= m_class_get_byval_arg (mono_defaults
.string_class
);
3435 if (check_exceptions
)
3436 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
3438 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
3440 if (check_exceptions
)
3441 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
3443 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
3446 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
3448 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3451 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
3452 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
3456 return mono_cominterop_get_native_wrapper (method
);
3458 g_assert_not_reached ();
3462 sig
= mono_method_signature_internal (method
);
3464 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3465 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
3468 if (!piinfo
->addr
) {
3470 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
3471 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "Method contains unsupported native code");
3473 mono_lookup_pinvoke_call_internal (method
, emitted_error
);
3475 if (!aot
|| (method
->klass
== mono_defaults
.string_class
))
3476 piinfo
->addr
= mono_lookup_internal_call (method
);
3480 /* hack - redirect certain string constructors to CreateString */
3481 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
3482 g_assert (!pinvoke
);
3483 g_assert (method
->string_ctor
);
3484 g_assert (sig
->hasthis
);
3486 /* CreateString returns a value */
3487 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3488 csig
->ret
= string_type
;
3492 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
3493 if (!strcmp ("CreateString", res
->name
) &&
3494 mono_metadata_signature_equal (csig
, mono_method_signature_internal (res
))) {
3497 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
3498 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
3500 /* create a wrapper to preserve .ctor in stack trace */
3501 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
3503 get_marshal_cb ()->emit_create_string_hack (mb
, csig
, res
);
3505 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
3506 info
->d
.string_ctor
.method
= method
;
3508 /* use native_wrapper_cache because internal calls are looked up there */
3509 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3510 csig
->param_count
+ 1, info
, NULL
);
3517 /* exception will be thrown */
3518 piinfo
->addr
= NULL
;
3519 g_warning ("cannot find CreateString for .ctor");
3522 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3524 mb
->method
->save_lmf
= 1;
3527 * In AOT mode and embedding scenarios, it is possible that the icall is not
3528 * registered in the runtime doing the AOT compilation.
3530 if (!piinfo
->addr
&& !aot
) {
3531 /* if there's no code but the error isn't set, just use a fairly generic exception. */
3532 if (is_ok (emitted_error
))
3533 mono_error_set_generic_error (emitted_error
, "System", "MissingMethodException", "");
3534 get_marshal_cb ()->mb_emit_exception_for_error (mb
, emitted_error
);
3535 mono_error_cleanup (emitted_error
);
3537 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3538 info
->d
.managed_to_native
.method
= method
;
3540 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3542 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3543 csig
->param_count
+ 16, info
, NULL
);
3549 g_assert (is_ok (emitted_error
));
3551 /* internal calls: we simply push all arguments and call the method (no conversions) */
3552 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
3554 csig
= mono_metadata_signature_dup_add_this (get_method_image (method
), sig
, method
->klass
);
3556 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3558 //printf ("%s\n", mono_method_full_name (method, 1));
3560 /* hack - string constructors returns a value */
3561 if (method
->string_ctor
)
3562 csig
->ret
= string_type
;
3564 get_marshal_cb ()->emit_native_icall_wrapper (mb
, method
, csig
, check_exceptions
, aot
, piinfo
);
3566 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3567 info
->d
.managed_to_native
.method
= method
;
3569 csig
= mono_metadata_signature_dup_full (get_method_image (method
), csig
);
3571 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3580 g_assert (piinfo
->addr
);
3582 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3583 mono_marshal_set_callconv_from_modopt (method
, csig
, FALSE
);
3585 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
3586 mono_method_get_marshal_info (method
, mspecs
);
3588 mono_marshal_emit_native_wrapper (get_method_image (mb
->method
), mb
, csig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
);
3589 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
3590 info
->d
.managed_to_native
.method
= method
;
3593 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3597 for (i
= sig
->param_count
; i
>= 0; i
--)
3599 mono_metadata_free_marshal_spec (mspecs
[i
]);
3602 /* mono_method_print_code (res); */
3608 * mono_marshal_get_native_func_wrapper:
3609 * \param image The image to use for memory allocation and for looking up custom marshallers.
3610 * \param sig The signature of the function
3611 * \param func The native function to wrap
3613 * \returns a wrapper method around native functions, similar to the pinvoke
3617 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
3618 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
3620 MonoMethodSignature
*csig
;
3622 SignaturePointerPair key
, *new_key
;
3623 MonoMethodBuilder
*mb
;
3632 // Generic types are not safe to place in MonoImage caches.
3633 g_assert (!sig
->is_inflated
);
3635 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
3636 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
3639 name
= g_strdup_printf ("wrapper_native_%p", func
);
3640 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3641 mb
->method
->save_lmf
= 1;
3643 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
);
3645 csig
= mono_metadata_signature_dup_full (image
, sig
);
3648 new_key
= g_new (SignaturePointerPair
,1);
3649 new_key
->sig
= csig
;
3650 new_key
->pointer
= func
;
3652 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
3658 mono_marshal_set_wrapper_info (res
, NULL
);
3664 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
3668 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
3670 MonoMethodSignature
*sig
, *csig
;
3671 MonoMethodBuilder
*mb
;
3676 MonoMethodPInvoke mpiinfo
;
3677 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
3678 MonoMarshalSpec
**mspecs
;
3679 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
3680 MonoImage
*image
= get_method_image (invoke
);
3683 // FIXME: include UnmanagedFunctionPointerAttribute info
3686 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
3688 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
3690 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
3693 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
3694 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
3696 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3697 mono_method_get_marshal_info (invoke
, mspecs
);
3698 /* Freed below so don't alloc from mempool */
3699 sig
= mono_metadata_signature_dup (mono_method_signature_internal (invoke
));
3702 name
= g_strdup_printf ("wrapper_aot_native");
3703 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3704 mb
->method
->save_lmf
= 1;
3706 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
);
3708 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
3709 info
->d
.managed_to_native
.method
= invoke
;
3711 g_assert (!sig
->hasthis
);
3712 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
3714 res
= mono_mb_create_and_cache_full (cache
, invoke
,
3715 mb
, csig
, csig
->param_count
+ 16,
3719 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3721 mono_metadata_free_marshal_spec (mspecs
[i
]);
3729 * mono_marshal_emit_managed_wrapper:
3731 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
3732 * the delegate which wraps the managed method to be called. For closed delegates,
3733 * it could have fewer parameters than the method it wraps.
3734 * THIS_LOC is the memory location where the target of the delegate is stored.
3737 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3739 get_marshal_cb ()->emit_managed_wrapper (mb
, invoke_sig
, mspecs
, m
, method
, target_handle
);
3742 #ifndef ENABLE_ILGEN
3744 emit_managed_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3746 MonoMethodSignature
*sig
, *csig
;
3748 MonoType
*int_type
= mono_get_int_type ();
3753 /* we first do all conversions */
3754 for (i
= 0; i
< sig
->param_count
; i
++) {
3755 MonoType
*t
= sig
->params
[i
];
3758 case MONO_TYPE_OBJECT
:
3759 case MONO_TYPE_CLASS
:
3760 case MONO_TYPE_VALUETYPE
:
3761 case MONO_TYPE_ARRAY
:
3762 case MONO_TYPE_SZARRAY
:
3763 case MONO_TYPE_STRING
:
3764 case MONO_TYPE_BOOLEAN
:
3765 mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
3769 if (!sig
->ret
->byref
) {
3770 switch (sig
->ret
->type
) {
3771 case MONO_TYPE_STRING
:
3772 csig
->ret
= int_type
;
3782 * mono_marshal_get_managed_wrapper:
3783 * Generates IL code to call managed methods from unmanaged code
3784 * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
3787 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
, MonoError
*error
)
3789 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
3790 MonoMethodBuilder
*mb
;
3791 MonoMethod
*res
, *invoke
;
3792 MonoMarshalSpec
**mspecs
;
3793 MonoMethodPInvoke piinfo
;
3796 EmitMarshalContext m
;
3798 g_assert (method
!= NULL
);
3801 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3802 mono_error_set_invalid_program (error
, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method
, TRUE
));
3807 * FIXME: Should cache the method+delegate type pair, since the same method
3808 * could be called with different delegates, thus different marshalling
3811 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
3813 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
3816 invoke
= mono_get_delegate_invoke_internal (delegate_klass
);
3817 invoke_sig
= mono_method_signature_internal (invoke
);
3819 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature_internal (invoke
)->param_count
+ 1);
3820 mono_method_get_marshal_info (invoke
, mspecs
);
3822 sig
= mono_method_signature_internal (method
);
3824 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3826 /*the target gchandle must be the first entry after size and the wrapper itself.*/
3827 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
3829 /* we copy the signature, so that we can modify it */
3831 /* Need to free this later */
3832 csig
= mono_metadata_signature_dup (invoke_sig
);
3834 csig
= mono_metadata_signature_dup_full (get_method_image (method
), invoke_sig
);
3838 memset (&m
, 0, sizeof (m
));
3844 m
.image
= get_method_image (method
);
3846 mono_marshal_set_callconv_from_modopt (invoke
, csig
, TRUE
);
3848 /* The attribute is only available in Net 2.0 */
3849 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
3850 MonoCustomAttrInfo
*cinfo
;
3851 MonoCustomAttrEntry
*attr
;
3854 * The pinvoke attributes are stored in a real custom attribute. Obtain the
3855 * contents of the attribute without constructing it, as that might not be
3856 * possible when running in cross-compiling mode.
3858 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, error
);
3859 mono_error_assert_ok (error
);
3862 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3863 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3864 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
3865 attr
= &cinfo
->attrs
[i
];
3871 gpointer
*typed_args
, *named_args
;
3872 CattrNamedArg
*arginfo
;
3875 MonoBoolean set_last_error
= 0;
3879 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
3880 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
3881 g_assert (mono_error_ok (error
));
3884 call_conv
= *(gint32
*)typed_args
[0];
3886 for (i
= 0; i
< num_named_args
; ++i
) {
3887 CattrNamedArg
*narg
= &arginfo
[i
];
3889 g_assert (narg
->field
);
3890 if (!strcmp (narg
->field
->name
, "CharSet")) {
3891 charset
= *(gint32
*)named_args
[i
];
3892 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
3893 set_last_error
= *(MonoBoolean
*)named_args
[i
];
3894 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
3895 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox_internal (o);
3896 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
3897 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox_internal (o);
3899 g_assert_not_reached ();
3902 g_free (typed_args
);
3903 g_free (named_args
);
3906 memset (&piinfo
, 0, sizeof (piinfo
));
3908 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
3910 csig
->call_convention
= call_conv
- 1;
3913 if (cinfo
&& !cinfo
->cached
)
3914 mono_custom_attrs_free (cinfo
);
3917 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
3919 if (!target_handle
) {
3922 // FIXME: Associate it with the method+delegate_klass pair
3923 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3924 info
->d
.native_to_managed
.method
= method
;
3925 info
->d
.native_to_managed
.klass
= delegate_klass
;
3927 res
= mono_mb_create_and_cache_full (cache
, method
,
3928 mb
, csig
, sig
->param_count
+ 16,
3931 get_marshal_cb ()->mb_set_dynamic (mb
);
3932 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
3936 for (i
= mono_method_signature_internal (invoke
)->param_count
; i
>= 0; i
--)
3938 mono_metadata_free_marshal_spec (mspecs
[i
]);
3941 /* mono_method_print_code (res); */
3946 #ifndef ENABLE_ILGEN
3948 emit_vtfixup_ftnptr_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
3954 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
3958 MonoMethodSignature
*sig
;
3959 MonoMethodBuilder
*mb
;
3964 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, error
);
3966 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (error
));
3969 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
3970 MonoMethodSignature
*csig
;
3971 MonoMarshalSpec
**mspecs
;
3972 EmitMarshalContext m
;
3974 sig
= mono_method_signature_internal (method
);
3975 g_assert (!sig
->hasthis
);
3977 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
3978 mono_method_get_marshal_info (method
, mspecs
);
3980 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3981 csig
= mono_metadata_signature_dup_full (image
, sig
);
3985 memset (&m
, 0, sizeof (m
));
3993 mono_marshal_set_callconv_from_modopt (method
, csig
, TRUE
);
3995 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
3997 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
3999 get_marshal_cb ()->mb_set_dynamic (mb
);
4000 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
4003 for (i
= sig
->param_count
; i
>= 0; i
--)
4005 mono_metadata_free_marshal_spec (mspecs
[i
]);
4008 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4009 mono_error_assert_ok (error
);
4010 return compiled_ptr
;
4013 sig
= mono_method_signature_internal (method
);
4014 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4016 param_count
= sig
->param_count
+ sig
->hasthis
;
4017 get_marshal_cb ()->emit_vtfixup_ftnptr (mb
, method
, param_count
, type
);
4018 get_marshal_cb ()->mb_set_dynamic (mb
);
4020 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
4023 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
4024 mono_error_assert_ok (error
);
4025 return compiled_ptr
;
4028 #ifndef ENABLE_ILGEN
4030 emit_castclass_noilgen (MonoMethodBuilder
*mb
)
4036 * mono_marshal_get_castclass_with_cache:
4037 * This does the equivalent of \c mono_object_castclass_with_cache.
4040 mono_marshal_get_castclass_with_cache (void)
4042 static MonoMethod
*cached
;
4044 MonoMethodBuilder
*mb
;
4045 MonoMethodSignature
*sig
;
4051 MonoType
*object_type
= mono_get_object_type ();
4052 MonoType
*int_type
= mono_get_int_type ();
4054 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
4055 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4056 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4057 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4058 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4059 sig
->ret
= object_type
;
4062 get_marshal_cb ()->emit_castclass (mb
);
4064 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
4065 res
= mono_mb_create (mb
, sig
, 8, info
);
4068 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4069 mono_free_method (res
);
4070 mono_metadata_free_method_signature (sig
);
4077 /* this is an icall */
4079 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
4082 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, error
);
4083 if (mono_error_set_pending_exception (error
))
4086 if (mono_object_is_transparent_proxy (obj
))
4089 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
4091 cache_update
= cache_update
| 0x1;
4093 *cache
= cache_update
;
4098 #ifndef ENABLE_ILGEN
4100 emit_isinst_noilgen (MonoMethodBuilder
*mb
)
4106 * mono_marshal_get_isinst_with_cache:
4107 * This does the equivalent of \c mono_marshal_isinst_with_cache.
4110 mono_marshal_get_isinst_with_cache (void)
4112 static MonoMethod
*cached
;
4114 MonoMethodBuilder
*mb
;
4115 MonoMethodSignature
*sig
;
4121 MonoType
*object_type
= mono_get_object_type ();
4122 MonoType
*int_type
= mono_get_int_type ();
4124 mb
= mono_mb_new (mono_defaults
.object_class
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
4125 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4127 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
4129 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
4131 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
4132 sig
->ret
= object_type
;
4135 get_marshal_cb ()->emit_isinst (mb
);
4137 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
4138 res
= mono_mb_create (mb
, sig
, 8, info
);
4141 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4142 mono_free_method (res
);
4143 mono_metadata_free_method_signature (sig
);
4150 #ifndef ENABLE_ILGEN
4152 emit_struct_to_ptr_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4158 * mono_marshal_get_struct_to_ptr:
4159 * \param klass \c MonoClass
4161 * Generates IL code for <code>StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)</code>
4164 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
4166 MonoMethodBuilder
*mb
;
4167 static MonoMethod
*stoptr
= NULL
;
4171 g_assert (klass
!= NULL
);
4173 mono_marshal_load_type_info (klass
);
4175 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4176 if (marshal_info
->str_to_ptr
)
4177 return marshal_info
->str_to_ptr
;
4181 stoptr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "StructureToPtr", 3, 0, error
);
4182 mono_error_assert_ok (error
);
4186 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_OTHER
);
4188 get_marshal_cb ()->emit_struct_to_ptr (mb
, klass
);
4190 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
4191 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
4194 mono_marshal_lock ();
4195 if (!marshal_info
->str_to_ptr
)
4196 marshal_info
->str_to_ptr
= res
;
4198 res
= marshal_info
->str_to_ptr
;
4199 mono_marshal_unlock ();
4203 #ifndef ENABLE_ILGEN
4205 emit_ptr_to_struct_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4211 * mono_marshal_get_ptr_to_struct:
4212 * \param klass \c MonoClass
4213 * Generates IL code for <code>PtrToStructure (IntPtr src, object structure)</code>
4216 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
4218 MonoMethodBuilder
*mb
;
4219 static MonoMethodSignature
*ptostr
= NULL
;
4223 g_assert (klass
!= NULL
);
4225 mono_marshal_load_type_info (klass
);
4227 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4228 if (marshal_info
->ptr_to_str
)
4229 return marshal_info
->ptr_to_str
;
4232 MonoMethodSignature
*sig
;
4234 /* Create the signature corresponding to
4235 static void PtrToStructure (IntPtr ptr, object structure);
4236 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
4237 sig
= mono_icall_sig_void_ptr_object
;
4238 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4240 mono_memory_barrier ();
4244 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_OTHER
);
4246 get_marshal_cb ()->emit_ptr_to_struct (mb
, klass
);
4248 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
4249 res
= mono_mb_create (mb
, ptostr
, 0, info
);
4252 mono_marshal_lock ();
4253 if (!marshal_info
->ptr_to_str
)
4254 marshal_info
->ptr_to_str
= res
;
4256 res
= marshal_info
->ptr_to_str
;
4257 mono_marshal_unlock ();
4262 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
4263 * This is used to avoid infinite recursion since it is hard to determine where to
4264 * replace a method with its synchronized wrapper, and where not.
4265 * The runtime should execute METHOD instead of the wrapper.
4268 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
4270 MonoMethodBuilder
*mb
;
4272 MonoMethodSignature
*sig
;
4274 MonoGenericContext
*ctx
= NULL
;
4275 MonoGenericContainer
*container
= NULL
;
4277 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4278 ctx
= &((MonoMethodInflated
*)method
)->context
;
4279 method
= ((MonoMethodInflated
*)method
)->declaring
;
4280 container
= mono_method_get_generic_container (method
);
4282 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4283 g_assert (container
);
4286 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4287 get_marshal_cb ()->mb_emit_exception (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
4288 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4290 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4292 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
4293 info
->d
.synchronized_inner
.method
= method
;
4294 res
= mono_mb_create (mb
, sig
, 0, info
);
4298 res
= mono_class_inflate_generic_method_checked (res
, ctx
, error
);
4299 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
4304 #ifndef ENABLE_ILGEN
4306 emit_synchronized_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4308 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4309 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4310 mono_class_set_type_load_failure (method
->klass
, "");
4318 * mono_marshal_get_synchronized_wrapper:
4319 * Generates IL code for the synchronized wrapper: the generated method
4320 * calls \p method while locking \c this or the parent type.
4323 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
4325 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
4326 MonoMethodSignature
*sig
;
4327 MonoMethodBuilder
*mb
;
4331 MonoGenericContext
*ctx
= NULL
;
4332 MonoMethod
*orig_method
= NULL
;
4333 MonoGenericContainer
*container
= NULL
;
4337 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
4340 /* FIXME: Support generic methods too */
4341 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4342 orig_method
= method
;
4343 ctx
= &((MonoMethodInflated
*)method
)->context
;
4344 method
= ((MonoMethodInflated
*)method
)->declaring
;
4345 container
= mono_method_get_generic_container (method
);
4347 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4348 g_assert (container
);
4355 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4356 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
4360 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4361 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4365 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4368 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
4370 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4371 info
->d
.synchronized
.method
= method
;
4373 mono_marshal_lock ();
4375 if (!enter_method
) {
4376 MonoMethodDesc
*desc
;
4378 desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
4379 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4380 g_assert (enter_method
);
4381 mono_method_desc_free (desc
);
4383 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
4384 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4385 g_assert (exit_method
);
4386 mono_method_desc_free (desc
);
4388 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
4389 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
4390 g_assert (gettypefromhandle_method
);
4391 mono_method_desc_free (desc
);
4394 mono_marshal_unlock ();
4396 get_marshal_cb ()->mb_skip_visibility (mb
);
4397 get_marshal_cb ()->emit_synchronized_wrapper (mb
, method
, ctx
, container
, enter_method
, exit_method
, gettypefromhandle_method
);
4401 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4402 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4404 res
= mono_mb_create_and_cache_full (cache
, method
,
4405 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4412 #ifndef ENABLE_ILGEN
4414 emit_unbox_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4420 * mono_marshal_get_unbox_wrapper:
4421 * The returned method calls \p method unboxing the \c this argument.
4424 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
4426 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4427 MonoMethodBuilder
*mb
;
4432 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4434 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4437 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
4439 g_assert (sig
->hasthis
);
4441 get_marshal_cb ()->emit_unbox_wrapper (mb
, method
);
4443 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4444 info
->d
.unbox
.method
= method
;
4446 res
= mono_mb_create_and_cache_full (cache
, method
,
4447 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4450 /* mono_method_print_code (res); */
4456 is_monomorphic_array (MonoClass
*klass
)
4458 MonoClass
*element_class
;
4459 if (m_class_get_rank (klass
) != 1)
4462 element_class
= m_class_get_element_class (klass
);
4463 return mono_class_is_sealed (element_class
) || m_class_is_valuetype (element_class
);
4466 static MonoStelemrefKind
4467 get_virtual_stelemref_kind (MonoClass
*element_class
)
4469 if (element_class
== mono_defaults
.object_class
)
4470 return STELEMREF_OBJECT
;
4471 if (is_monomorphic_array (element_class
))
4472 return STELEMREF_SEALED_CLASS
;
4474 /* magic ifaces requires aditional checks for when the element type is an array */
4475 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && m_class_is_array_special_interface (element_class
))
4476 return STELEMREF_COMPLEX
;
4478 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
4479 if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class
) && !mono_class_has_variant_generic_params (element_class
))
4480 #ifdef COMPRESSED_INTERFACE_BITMAP
4481 return STELEMREF_COMPLEX
;
4483 return STELEMREF_INTERFACE
;
4485 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
4486 if (mono_class_is_marshalbyref (element_class
) || m_class_get_rank (element_class
) || mono_class_has_variant_generic_params (element_class
))
4487 return STELEMREF_COMPLEX
;
4488 if (mono_class_is_sealed (element_class
))
4489 return STELEMREF_SEALED_CLASS
;
4490 if (m_class_get_idepth (element_class
) <= MONO_DEFAULT_SUPERTABLE_SIZE
)
4491 return STELEMREF_CLASS_SMALL_IDEPTH
;
4493 return STELEMREF_CLASS
;
4498 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
4500 char *name
= mono_type_get_full_name (m_class_element_class (mono_object_class (array
)));
4501 printf ("slow vstore of %s\n", name
);
4506 #ifndef ENABLE_ILGEN
4508 emit_virtual_stelemref_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
4513 static const char *strelemref_wrapper_name
[] = {
4514 "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
4517 static const gchar
*
4518 mono_marshal_get_strelemref_wrapper_name (MonoStelemrefKind kind
)
4520 return strelemref_wrapper_name
[kind
];
4525 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
4526 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
4527 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
4528 * - Add a case for arrays of arrays.
4531 get_virtual_stelemref_wrapper (MonoStelemrefKind kind
)
4533 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
4534 static MonoMethodSignature
*signature
;
4535 MonoMethodBuilder
*mb
;
4538 const char *param_names
[16];
4541 if (cached_methods
[kind
])
4542 return cached_methods
[kind
];
4544 MonoType
*void_type
= mono_get_void_type ();
4545 MonoType
*object_type
= mono_get_object_type ();
4546 MonoType
*int_type
= mono_get_int_type ();
4548 name
= g_strdup_printf ("virt_stelemref_%s", mono_marshal_get_strelemref_wrapper_name (kind
));
4549 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
4553 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
4555 /* void this::stelemref (size_t idx, void* value) */
4556 sig
->ret
= void_type
;
4557 sig
->hasthis
= TRUE
;
4558 sig
->params
[0] = int_type
; /* this is a natural sized int */
4559 sig
->params
[1] = object_type
;
4563 param_names
[0] = "index";
4564 param_names
[1] = "value";
4565 get_marshal_cb ()->emit_virtual_stelemref (mb
, param_names
, kind
);
4567 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
4568 info
->d
.virtual_stelemref
.kind
= kind
;
4569 res
= mono_mb_create (mb
, signature
, 4, info
);
4570 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
4572 mono_marshal_lock ();
4573 if (!cached_methods
[kind
]) {
4574 cached_methods
[kind
] = res
;
4575 mono_marshal_unlock ();
4577 mono_marshal_unlock ();
4578 mono_free_method (res
);
4582 return cached_methods
[kind
];
4586 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
4588 MonoStelemrefKind kind
;
4590 g_assert (m_class_get_rank (array_class
) == 1);
4591 kind
= get_virtual_stelemref_kind (m_class_get_element_class (array_class
));
4593 return get_virtual_stelemref_wrapper (kind
);
4597 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
4602 *nwrappers
= STELEMREF_KIND_COUNT
;
4603 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
4604 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
4605 res
[i
] = get_virtual_stelemref_wrapper ((MonoStelemrefKind
)i
);
4609 #ifndef ENABLE_ILGEN
4611 emit_stelemref_noilgen (MonoMethodBuilder
*mb
)
4617 * mono_marshal_get_stelemref:
4620 mono_marshal_get_stelemref (void)
4622 static MonoMethod
* ret
= NULL
;
4623 MonoMethodSignature
*sig
;
4624 MonoMethodBuilder
*mb
;
4630 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
4633 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4635 MonoType
*void_type
= mono_get_void_type ();
4636 MonoType
*object_type
= mono_get_object_type ();
4637 MonoType
*int_type
= mono_get_int_type ();
4640 /* void stelemref (void* array, int idx, void* value) */
4641 sig
->ret
= void_type
;
4642 sig
->params
[0] = object_type
;
4643 sig
->params
[1] = int_type
; /* this is a natural sized int */
4644 sig
->params
[2] = object_type
;
4646 get_marshal_cb ()->emit_stelemref (mb
);
4648 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4649 ret
= mono_mb_create (mb
, sig
, 4, info
);
4655 #ifndef ENABLE_ILGEN
4657 mb_emit_byte_noilgen (MonoMethodBuilder
*mb
, guint8 op
)
4663 * mono_marshal_get_gsharedvt_in_wrapper:
4665 * This wrapper handles calls from normal code to gsharedvt code.
4668 mono_marshal_get_gsharedvt_in_wrapper (void)
4670 static MonoMethod
* ret
= NULL
;
4671 MonoMethodSignature
*sig
;
4672 MonoMethodBuilder
*mb
;
4678 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_OTHER
);
4680 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4681 sig
->ret
= mono_get_void_type ();
4684 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4686 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4688 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
4689 ret
= mono_mb_create (mb
, sig
, 4, info
);
4696 * mono_marshal_get_gsharedvt_out_wrapper:
4698 * This wrapper handles calls from gsharedvt code to normal code.
4701 mono_marshal_get_gsharedvt_out_wrapper (void)
4703 static MonoMethod
* ret
= NULL
;
4704 MonoMethodSignature
*sig
;
4705 MonoMethodBuilder
*mb
;
4711 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_OTHER
);
4713 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4714 sig
->ret
= mono_get_void_type ();
4717 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4719 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4721 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
4722 ret
= mono_mb_create (mb
, sig
, 4, info
);
4728 #ifndef ENABLE_ILGEN
4730 emit_array_address_noilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
4741 /* LOCKING: vars accessed under the marshal lock */
4742 static ArrayElemAddr
*elem_addr_cache
= NULL
;
4743 static int elem_addr_cache_size
= 0;
4744 static int elem_addr_cache_next
= 0;
4747 * mono_marshal_get_array_address:
4748 * \param rank rank of the array type
4749 * \param elem_size size in bytes of an element of an array.
4751 * Returns a MonoMethod that implements the code to get the address
4752 * of an element in a multi-dimenasional array of \p rank dimensions.
4753 * The returned method takes an array as the first argument and then
4754 * \p rank indexes for the \p rank dimensions.
4755 * If ELEM_SIZE is 0, read the array size from the array object.
4758 mono_marshal_get_array_address (int rank
, int elem_size
)
4761 MonoMethodBuilder
*mb
;
4762 MonoMethodSignature
*sig
;
4768 mono_marshal_lock ();
4769 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4770 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4771 ret
= elem_addr_cache
[i
].method
;
4775 mono_marshal_unlock ();
4779 MonoType
*object_type
= mono_get_object_type ();
4780 MonoType
*int_type
= mono_get_int_type ();
4781 MonoType
*int32_type
= mono_get_int32_type ();
4783 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
4785 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
4786 sig
->ret
= int_type
;
4787 sig
->params
[0] = object_type
;
4788 for (int i
= 0; i
< rank
; ++i
) {
4789 sig
->params
[i
+ 1] = int32_type
;
4792 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
4793 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4796 get_marshal_cb ()->emit_array_address (mb
, rank
, elem_size
);
4798 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
4799 info
->d
.element_addr
.rank
= rank
;
4800 info
->d
.element_addr
.elem_size
= elem_size
;
4801 ret
= mono_mb_create (mb
, sig
, 4, info
);
4804 /* cache the result */
4806 mono_marshal_lock ();
4807 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4808 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4809 /* FIXME: free ret */
4810 ret
= elem_addr_cache
[i
].method
;
4816 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
4817 int new_size
= elem_addr_cache_size
+ 4;
4818 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
4819 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
4820 g_free (elem_addr_cache
);
4821 elem_addr_cache
= new_array
;
4822 elem_addr_cache_size
= new_size
;
4824 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
4825 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
4826 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
4827 elem_addr_cache_next
++;
4829 mono_marshal_unlock ();
4833 #ifndef ENABLE_ILGEN
4835 emit_array_accessor_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4841 * mono_marshal_get_array_accessor_wrapper:
4843 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
4846 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
4848 MonoMethodSignature
*sig
;
4849 MonoMethodBuilder
*mb
;
4852 MonoGenericContext
*ctx
= NULL
;
4853 MonoMethod
*orig_method
= NULL
;
4857 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
4858 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
4859 * FIXME: Use generic methods.
4866 g_assert_not_reached ();
4868 cache
= get_cache (&get_method_image (method
)->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
4869 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4873 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature_internal (method
));
4876 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_OTHER
);
4878 get_marshal_cb ()->emit_array_accessor_wrapper (mb
, method
, sig
, ctx
);
4880 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
4881 info
->d
.array_accessor
.method
= method
;
4885 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4886 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4888 res
= mono_mb_create_and_cache_full (cache
, method
,
4889 mb
, sig
, sig
->param_count
+ 16,
4899 mono_marshal_alloc_co_task_mem (size_t size
)
4902 /* This returns a valid pointer for size 0 on MS.NET */
4905 return g_try_malloc (size
);
4910 * mono_marshal_alloc:
4913 mono_marshal_alloc (gsize size
, MonoError
*error
)
4919 res
= mono_marshal_alloc_co_task_mem (size
);
4921 mono_error_set_out_of_memory (error
, "Could not allocate %" G_GSIZE_FORMAT
" bytes", size
);
4926 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
4928 ves_icall_marshal_alloc_impl (gsize size
, MonoError
*error
)
4930 return mono_marshal_alloc (size
, error
);
4935 mono_marshal_free_co_task_mem (void *ptr
)
4942 * mono_marshal_free:
4945 mono_marshal_free (gpointer ptr
)
4947 mono_marshal_free_co_task_mem (ptr
);
4951 * mono_marshal_free_array:
4954 mono_marshal_free_array (gpointer
*ptr
, int size
)
4961 for (i
= 0; i
< size
; i
++)
4966 mono_marshal_string_to_utf16 (MonoString
*s
)
4968 // FIXME This should be an intrinsic.
4969 // FIXMEcoop The input parameter is easy to deal with,
4970 // but what happens with the result?
4971 // See https://github.com/mono/mono/issues/12165.
4972 return s
? mono_string_chars_internal (s
) : NULL
;
4975 /* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
4977 mono_marshal_string_to_utf16_copy_impl (MonoStringHandle s
, MonoError
*error
)
4979 if (MONO_HANDLE_IS_NULL (s
))
4982 gsize
const length
= mono_string_handle_length (s
);
4983 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((length
+ 1) * sizeof (*res
), error
);
4984 return_val_if_nok (error
, NULL
);
4985 gchandle_t gchandle
= 0;
4986 memcpy (res
, mono_string_handle_pin_chars (s
, &gchandle
), length
* sizeof (*res
));
4987 mono_gchandle_free_internal (gchandle
);
4993 * mono_marshal_set_last_error:
4995 * This function is invoked to set the last error value from a P/Invoke call
4996 * which has \c SetLastError set.
4999 mono_marshal_set_last_error (void)
5001 /* This icall is called just after a P/Invoke call before the P/Invoke
5002 * wrapper transitions the runtime back to running mode. */
5004 MONO_REQ_GC_SAFE_MODE
;
5005 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
5007 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
5012 mono_marshal_set_last_error_windows (int error
)
5015 /* This icall is called just after a P/Invoke call before the P/Invoke
5016 * wrapper transitions the runtime back to running mode. */
5017 MONO_REQ_GC_SAFE_MODE
;
5018 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
5023 mono_marshal_clear_last_error (void)
5025 /* This icall is called just before a P/Invoke call. */
5027 SetLastError (ERROR_SUCCESS
);
5034 copy_managed_common (MonoArrayHandle managed
, gconstpointer native
, gint32 start_index
,
5035 gint32 length
, gpointer
*managed_addr
, guint32
*gchandle
, MonoError
*error
)
5037 MONO_CHECK_ARG_NULL_HANDLE (managed
, 0);
5038 MONO_CHECK_ARG_NULL (native
, 0);
5040 MonoClass
*klass
= mono_handle_class (managed
);
5042 // FIXME? move checks to managed
5043 if (m_class_get_rank (klass
) != 1) {
5044 mono_error_set_argument (error
, "array", "array is multi-dimensional");
5047 if (start_index
< 0) {
5048 mono_error_set_argument (error
, "startIndex", "Must be >= 0");
5052 mono_error_set_argument (error
, "length", "Must be >= 0");
5055 if (start_index
+ length
> mono_array_handle_length (managed
)) {
5056 mono_error_set_argument (error
, "length", "start_index + length > array length");
5060 gsize
const element_size
= mono_array_element_size (klass
);
5062 // Handle generic arrays, which do not allow fixed.
5064 *managed_addr
= mono_array_handle_pin_with_size (managed
, element_size
, start_index
, gchandle
);
5066 return element_size
* length
;
5070 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArrayHandle src
, gint32 start_index
,
5071 gpointer dest
, gint32 length
, gconstpointer managed_source_addr
, MonoError
*error
)
5073 guint32 gchandle
= 0;
5074 gsize
const bytes
= copy_managed_common (src
, dest
, start_index
, length
, (gpointer
*)&managed_source_addr
, &gchandle
, error
);
5076 memmove (dest
, managed_source_addr
, bytes
); // no references should be involved
5077 mono_gchandle_free_internal (gchandle
);
5081 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gconstpointer src
, gint32 start_index
,
5082 MonoArrayHandle dest
, gint32 length
, gpointer managed_dest_addr
, MonoError
*error
)
5084 guint32 gchandle
= 0;
5085 gsize
const bytes
= copy_managed_common (dest
, src
, start_index
, length
, &managed_dest_addr
, &gchandle
, error
);
5087 memmove (managed_dest_addr
, src
, bytes
); // no references should be involved
5088 mono_gchandle_free_internal (gchandle
);
5092 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (const char *ptr
, MonoError
*error
)
5095 return NULL_HANDLE_STRING
;
5096 return mono_string_new_handle (mono_domain_get (), ptr
, error
);
5100 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (const char *ptr
, gint32 len
, MonoError
*error
)
5103 mono_error_set_argument_null (error
, "ptr", "");
5104 return NULL_HANDLE_STRING
;
5106 return mono_string_new_utf8_len (mono_domain_get (), ptr
, len
, error
);
5110 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (const gunichar2
*ptr
, MonoError
*error
)
5113 const gunichar2
*t
= ptr
;
5116 return NULL_HANDLE_STRING
;
5121 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5122 return_val_if_nok (error
, NULL_HANDLE_STRING
);
5128 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (const gunichar2
*ptr
, gint32 len
, MonoError
*error
)
5131 mono_error_set_argument_null (error
, "ptr", "");
5132 return NULL_HANDLE_STRING
;
5134 return mono_string_new_utf16_handle (mono_domain_get (), ptr
, len
, error
);
5138 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5140 return GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
));
5144 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype
, MonoError
*error
)
5146 if (MONO_HANDLE_IS_NULL (rtype
)) {
5147 mono_error_set_argument_null (error
, "type", "");
5151 MonoType
* const type
= MONO_HANDLE_GETVAL (rtype
, type
);
5152 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
5153 if (!mono_class_init_checked (klass
, error
))
5156 guint32
const layout
= (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
);
5158 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
5159 return sizeof (gpointer
);
5160 } else if (type
->type
== MONO_TYPE_VOID
) {
5162 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5163 mono_error_set_argument_format (error
, "t", "Type %s cannot be marshaled as an unmanaged structure.", m_class_get_name (klass
));
5168 return (guint32
)mono_marshal_type_size (type
, NULL
, &align
, FALSE
, m_class_is_unicode (klass
));
5172 ves_icall_System_Runtime_InteropServices_Marshal_SizeOfHelper (MonoReflectionTypeHandle rtype
, MonoBoolean throwIfNotMarshalable
, MonoError
*error
)
5174 return ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (rtype
, error
);
5178 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObjectHandle obj
, gpointer dst
, MonoBoolean delete_old
, MonoError
*error
)
5180 MONO_CHECK_ARG_NULL_HANDLE_NAMED (obj
, "structure",);
5181 MONO_CHECK_ARG_NULL_NAMED (dst
, "ptr",);
5183 #ifdef ENABLE_NETCORE
5184 MonoClass
*klass
= mono_handle_class (obj
);
5185 if (m_class_is_auto_layout (klass
)) {
5186 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5189 if (m_class_is_ginst (klass
)) {
5190 mono_error_set_argument (error
, "structure", "The specified object must not be an instance of a generic type.");
5195 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (obj
));
5197 gpointer pa
[ ] = { MONO_HANDLE_RAW (obj
), &dst
, &delete_old
};
5199 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
5203 ptr_to_structure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5205 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (dst
));
5207 gpointer pa
[ ] = { &src
, MONO_HANDLE_RAW (dst
) };
5209 // FIXMEcoop? mono_runtime_invoke_handle causes a GC assertion failure in marshal2 with interpreter
5210 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5213 #ifdef ENABLE_NETCORE
5216 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructureInternal (gconstpointer src
, MonoObjectHandle dst
, MonoBoolean allow_vtypes
, MonoError
*error
)
5221 t
= m_class_get_byval_arg (mono_handle_class (dst
));
5222 if (!allow_vtypes
&& MONO_TYPE_ISSTRUCT (t
)) {
5223 mono_error_set_argument (error
, "structure", "The structure must not be a value class.");
5227 klass
= mono_class_from_mono_type_internal (t
);
5228 if (m_class_is_auto_layout (klass
)) {
5229 mono_error_set_argument (error
, "structure", "The specified structure must be blittable or have layout information.");
5233 ptr_to_structure (src
, dst
, error
);
5239 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gconstpointer src
, MonoObjectHandle dst
, MonoError
*error
)
5243 MONO_CHECK_ARG_NULL (src
,);
5244 MONO_CHECK_ARG_NULL_HANDLE (dst
,);
5246 t
= mono_type_get_underlying_type (m_class_get_byval_arg (mono_handle_class (dst
)));
5248 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5249 mono_error_set_argument (error
, "dst", "Destination is a boxed value type.");
5253 ptr_to_structure (src
, dst
, error
);
5257 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gconstpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5262 MONO_CHECK_ARG_NULL_HANDLE (type
, NULL_HANDLE
);
5264 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5265 if (!mono_class_init_checked (klass
, error
))
5268 MonoObjectHandle res
= mono_object_new_handle (mono_domain_get (), klass
, error
);
5269 return_val_if_nok (error
, NULL_HANDLE
);
5271 ptr_to_structure (src
, res
, error
);
5272 return_val_if_nok (error
, NULL_HANDLE
);
5279 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type
, MonoStringHandle field_name
, MonoError
*error
)
5282 if (MONO_HANDLE_IS_NULL (ref_type
)) {
5283 mono_error_set_argument_null (error
, "t", "");
5286 if (MONO_HANDLE_IS_NULL (field_name
)) {
5287 mono_error_set_argument_null (error
, "fieldName", "");
5291 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (ref_type
))) {
5292 mono_error_set_argument (error
, "type", "");
5296 char *fname
= mono_string_handle_to_utf8 (field_name
, error
);
5297 return_val_if_nok (error
, 0);
5299 MonoType
*type
= MONO_HANDLE_GETVAL (ref_type
, type
);
5300 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
5301 if (!mono_class_init_checked (klass
, error
))
5303 #ifdef ENABLE_NETCORE
5304 if (m_class_is_auto_layout (klass
)) {
5305 mono_error_set_argument (error
, NULL
, "");
5309 int match_index
= -1;
5310 while (klass
&& match_index
== -1) {
5311 MonoClassField
* field
;
5313 gpointer iter
= NULL
;
5314 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5315 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5317 if (!strcmp (fname
, mono_field_get_name (field
))) {
5324 if (match_index
== -1)
5325 klass
= m_class_get_parent (klass
);
5330 if(match_index
== -1) {
5331 /* Get back original class instance */
5332 klass
= mono_class_from_mono_type_internal (type
);
5334 mono_error_set_argument_format (error
, "fieldName", "Field passed in is not a marshaled member of the type %s", m_class_get_name (klass
));
5338 MonoMarshalType
*info
= mono_marshal_load_type_info (klass
);
5339 return info
->fields
[match_index
].offset
;
5344 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2
*s
, int length
, MonoError
*error
)
5346 return mono_utf16_to_utf8 (s
, length
, error
);
5350 mono_marshal_alloc_hglobal (size_t size
, MonoError
*error
)
5352 void* p
= g_try_malloc (size
);
5354 mono_error_set_out_of_memory (error
, "");
5357 #endif /* !HOST_WIN32 */
5360 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2
*s
, int length
, MonoError
*error
)
5365 gsize
const len
= ((gsize
)length
+ 1) * 2;
5366 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc_hglobal (len
, error
);
5368 memcpy (res
, s
, length
* 2);
5375 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
5377 MonoMarshalType
*info
;
5380 info
= mono_marshal_load_type_info (klass
);
5382 for (i
= 0; i
< info
->num_fields
; i
++) {
5383 MonoMarshalConv conv
;
5384 MonoType
*ftype
= info
->fields
[i
].field
->type
;
5387 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5390 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
5391 m_class_is_unicode (klass
), &conv
);
5393 cpos
= ptr
+ info
->fields
[i
].offset
;
5396 case MONO_MARSHAL_CONV_NONE
:
5397 if (MONO_TYPE_ISSTRUCT (ftype
)) {
5398 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
5402 case MONO_MARSHAL_CONV_STR_LPWSTR
:
5403 /* We assume this field points inside a MonoString */
5405 case MONO_MARSHAL_CONV_STR_LPTSTR
:
5407 /* We assume this field points inside a MonoString
5411 case MONO_MARSHAL_CONV_STR_LPSTR
:
5412 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
5413 case MONO_MARSHAL_CONV_STR_TBSTR
:
5414 case MONO_MARSHAL_CONV_STR_UTF8STR
:
5415 mono_marshal_free (*(gpointer
*)cpos
);
5417 case MONO_MARSHAL_CONV_STR_BSTR
:
5418 mono_free_bstr (*(gpointer
*)cpos
);
5427 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionTypeHandle type
, MonoError
*error
)
5429 MONO_CHECK_ARG_NULL_NAMED (src
, "ptr",);
5430 MONO_CHECK_ARG_NULL_HANDLE_NAMED (type
, "structureType",);
5432 if (!m_class_is_runtime_type (MONO_HANDLE_GET_CLASS (type
))) {
5433 mono_error_set_argument (error
, "structureType", "");
5437 MonoClass
*klass
= mono_class_from_mono_type_handle (type
);
5438 if (!mono_class_init_checked (klass
, error
))
5440 #ifdef ENABLE_NETCORE
5441 if (m_class_is_auto_layout (klass
)) {
5442 mono_error_set_argument (error
, "structureType", "The specified structure must be blittable or have layout information.");
5448 mono_struct_delete_old (klass
, (char *)src
);
5452 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gsize size
, MonoError
*error
)
5455 /* This returns a valid pointer for size 0 on MS.NET */
5458 return mono_marshal_alloc_hglobal (size
, error
);
5462 static inline gpointer
5463 mono_marshal_realloc_hglobal (gpointer ptr
, size_t size
)
5465 return g_try_realloc (ptr
, size
);
5470 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gsize size
, MonoError
*error
)
5473 mono_error_set_out_of_memory (error
, "");
5477 gpointer
const res
= mono_marshal_realloc_hglobal (ptr
, size
);
5480 mono_error_set_out_of_memory (error
, "");
5487 mono_marshal_free_hglobal (gpointer ptr
)
5494 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
5496 mono_marshal_free_hglobal (ptr
);
5500 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
, MonoError
*error
)
5502 void *res
= mono_marshal_alloc_co_task_mem (size
);
5505 mono_error_set_out_of_memory (error
, "");
5511 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gsize size
, MonoError
*error
)
5513 void *res
= mono_marshal_alloc_co_task_mem (size
);
5516 mono_error_set_out_of_memory (error
, "");
5522 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
5524 mono_marshal_free_co_task_mem (ptr
);
5528 static inline gpointer
5529 mono_marshal_realloc_co_task_mem (gpointer ptr
, size_t size
)
5531 return g_try_realloc (ptr
, size
);
5536 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
, MonoError
*error
)
5538 void *res
= mono_marshal_realloc_co_task_mem (ptr
, size
);
5541 mono_error_set_out_of_memory (error
, "");
5548 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray
*arrayobj
, int index
)
5550 return mono_array_addr_with_size_fast (arrayobj
, mono_array_element_size (arrayobj
->obj
.vtable
->klass
), index
);
5554 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionTypeHandle type
, MonoError
*error
)
5556 MonoClass
*klass
= mono_type_get_class (MONO_HANDLE_GETVAL (type
, type
));
5557 if (!mono_class_init_checked (klass
, error
))
5558 return MONO_HANDLE_CAST (MonoDelegate
, NULL_HANDLE
);
5560 return mono_ftnptr_to_delegate_impl (klass
, ftn
, error
);
5564 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate
, MonoError
*error
)
5566 return mono_delegate_to_ftnptr_impl (delegate
, error
);
5570 ves_icall_System_Runtime_InteropServices_Marshal_GetArrayElementSize (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5572 MonoClass
*eklass
= mono_type_get_class (MONO_HANDLE_GETVAL (type_h
, type
));
5574 mono_class_init_internal (eklass
);
5576 if (m_class_has_references (eklass
)) {
5577 mono_error_set_argument (error
, NULL
, NULL
);
5580 return mono_class_array_element_size (eklass
);
5584 ves_icall_System_Runtime_InteropServices_Marshal_IsPinnableType (MonoReflectionTypeHandle type_h
, MonoError
*error
)
5586 MonoClass
*klass
= mono_class_from_mono_type_internal (MONO_HANDLE_GETVAL (type_h
, type
));
5588 if (m_class_get_rank (klass
)) {
5589 MonoClass
*eklass
= m_class_get_element_class (klass
);
5590 if (m_class_is_primitive (eklass
))
5592 return eklass
!= mono_defaults
.object_class
&& m_class_is_blittable (eklass
);
5594 return m_class_is_blittable (klass
);
5598 * mono_marshal_is_loading_type_info:
5600 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
5604 mono_marshal_is_loading_type_info (MonoClass
*klass
)
5606 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5608 return g_slist_find (loads_list
, klass
) != NULL
;
5612 * mono_marshal_load_type_info:
5614 * Initialize \c klass::marshal_info using information from metadata. This function can
5615 * recursively call itself, and the caller is responsible to avoid that by calling
5616 * \c mono_marshal_is_loading_type_info beforehand.
5618 * LOCKING: Acquires the loader lock.
5621 mono_marshal_load_type_info (MonoClass
* klass
)
5624 guint32 native_size
= 0, min_align
= 1, packing
;
5625 MonoMarshalType
*info
;
5626 MonoClassField
* field
;
5631 g_assert (klass
!= NULL
);
5633 info
= mono_class_get_marshal_info (klass
);
5637 if (!m_class_is_inited (klass
))
5638 mono_class_init_internal (klass
);
5640 info
= mono_class_get_marshal_info (klass
);
5645 * This function can recursively call itself, so we keep the list of classes which are
5646 * under initialization in a TLS list.
5648 g_assert (!mono_marshal_is_loading_type_info (klass
));
5649 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5650 loads_list
= g_slist_prepend (loads_list
, klass
);
5651 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5654 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5655 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5657 if (mono_field_is_deleted (field
))
5662 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
5664 info
= (MonoMarshalType
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
5665 info
->num_fields
= count
;
5667 /* Try to find a size for this type in metadata */
5668 mono_metadata_packing_from_typedef (m_class_get_image (klass
), m_class_get_type_token (klass
), NULL
, &native_size
);
5670 if (m_class_get_parent (klass
)) {
5671 int parent_size
= mono_class_native_size (m_class_get_parent (klass
), NULL
);
5673 /* Add parent size to real size */
5674 native_size
+= parent_size
;
5675 info
->native_size
= parent_size
;
5678 packing
= m_class_get_packing_size (klass
) ? m_class_get_packing_size (klass
) : 8;
5681 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
5685 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5688 if (mono_field_is_deleted (field
))
5690 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
5691 mono_metadata_field_info_with_mempool (m_class_get_image (klass
), mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
5692 NULL
, NULL
, &info
->fields
[j
].mspec
);
5694 info
->fields
[j
].field
= field
;
5696 if ((mono_class_num_fields (klass
) == 1) && (m_class_get_instance_size (klass
) == MONO_ABI_SIZEOF (MonoObject
)) &&
5697 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
5698 /* This field is a hack inserted by MCS to empty structures */
5703 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
5704 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
5705 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5706 &align
, TRUE
, m_class_is_unicode (klass
));
5707 align
= m_class_get_packing_size (klass
) ? MIN (m_class_get_packing_size (klass
), align
): align
;
5708 min_align
= MAX (align
, min_align
);
5709 info
->fields
[j
].offset
= info
->native_size
;
5710 info
->fields
[j
].offset
+= align
- 1;
5711 info
->fields
[j
].offset
&= ~(align
- 1);
5712 info
->native_size
= info
->fields
[j
].offset
+ size
;
5714 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
5715 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5716 &align
, TRUE
, m_class_is_unicode (klass
));
5717 min_align
= MAX (align
, min_align
);
5718 info
->fields
[j
].offset
= field
->offset
- MONO_ABI_SIZEOF (MonoObject
);
5719 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
5725 if (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_PTR
)
5726 info
->native_size
= TARGET_SIZEOF_VOID_P
;
5728 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5729 info
->native_size
= MAX (native_size
, info
->native_size
);
5731 * If the provided Size is equal or larger than the calculated size, and there
5732 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
5734 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
5735 if (native_size
&& native_size
== info
->native_size
&& m_class_get_packing_size (klass
) == 0)
5738 min_align
= MIN (min_align
, packing
);
5742 if (info
->native_size
& (min_align
- 1)) {
5743 info
->native_size
+= min_align
- 1;
5744 info
->native_size
&= ~(min_align
- 1);
5747 info
->min_align
= min_align
;
5749 /* Update the class's blittable info, if the layouts don't match */
5750 if (info
->native_size
!= mono_class_value_size (klass
, NULL
)) {
5751 mono_class_set_nonblittable (klass
); /* FIXME - how is this justified? what if we previously thought the class was blittable? */
5754 /* If this is an array type, ensure that we have element info */
5755 if (m_class_get_rank (klass
) && !mono_marshal_is_loading_type_info (m_class_get_element_class (klass
))) {
5756 mono_marshal_load_type_info (m_class_get_element_class (klass
));
5759 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5760 loads_list
= g_slist_remove (loads_list
, klass
);
5761 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5763 mono_marshal_lock ();
5764 MonoMarshalType
*info2
= mono_class_get_marshal_info (klass
);
5766 /*We do double-checking locking on marshal_info */
5767 mono_memory_barrier ();
5768 mono_class_set_marshal_info (klass
, info
);
5769 ++class_marshal_info_count
;
5772 mono_marshal_unlock ();
5778 * mono_class_native_size:
5779 * \param klass a class
5780 * \returns the native size of an object instance (when marshaled
5781 * to unmanaged code)
5784 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
5786 MonoMarshalType
*info
= mono_class_get_marshal_info (klass
);
5788 if (mono_marshal_is_loading_type_info (klass
)) {
5793 mono_marshal_load_type_info (klass
);
5795 info
= mono_class_get_marshal_info (klass
);
5799 *align
= info
->min_align
;
5801 return info
->native_size
;
5805 * mono_type_native_stack_size:
5806 * @t: the type to return the size it uses on the stack
5808 * Returns: the number of bytes required to hold an instance of this
5809 * type on the native stack
5812 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
5816 g_assert (t
!= NULL
);
5822 *align
= TARGET_SIZEOF_VOID_P
;
5823 return TARGET_SIZEOF_VOID_P
;
5827 case MONO_TYPE_BOOLEAN
:
5828 case MONO_TYPE_CHAR
:
5839 case MONO_TYPE_STRING
:
5840 case MONO_TYPE_OBJECT
:
5841 case MONO_TYPE_CLASS
:
5842 case MONO_TYPE_SZARRAY
:
5844 case MONO_TYPE_FNPTR
:
5845 case MONO_TYPE_ARRAY
:
5846 *align
= TARGET_SIZEOF_VOID_P
;
5847 return TARGET_SIZEOF_VOID_P
;
5852 *align
= MONO_ABI_ALIGNOF (double);
5856 *align
= MONO_ABI_ALIGNOF (gint64
);
5858 case MONO_TYPE_GENERICINST
:
5859 if (!mono_type_generic_inst_is_valuetype (t
)) {
5860 *align
= TARGET_SIZEOF_VOID_P
;
5861 return TARGET_SIZEOF_VOID_P
;
5864 case MONO_TYPE_TYPEDBYREF
:
5865 case MONO_TYPE_VALUETYPE
: {
5867 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
5869 if (m_class_is_enumtype (klass
))
5870 return mono_type_native_stack_size (mono_class_enum_basetype_internal (klass
), align
);
5872 size
= mono_class_native_size (klass
, align
);
5873 *align
= *align
+ 3;
5883 g_error ("type 0x%02x unknown", t
->type
);
5889 * mono_marshal_type_size:
5892 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
5893 gboolean as_field
, gboolean unicode
)
5896 MonoMarshalNative native_type
= (MonoMarshalNative
)mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
5899 switch (native_type
) {
5900 case MONO_NATIVE_BOOLEAN
:
5903 case MONO_NATIVE_I1
:
5904 case MONO_NATIVE_U1
:
5907 case MONO_NATIVE_I2
:
5908 case MONO_NATIVE_U2
:
5909 case MONO_NATIVE_VARIANTBOOL
:
5912 case MONO_NATIVE_I4
:
5913 case MONO_NATIVE_U4
:
5914 case MONO_NATIVE_ERROR
:
5917 case MONO_NATIVE_I8
:
5918 case MONO_NATIVE_U8
:
5919 *align
= MONO_ABI_ALIGNOF (gint64
);
5921 case MONO_NATIVE_R4
:
5924 case MONO_NATIVE_R8
:
5925 *align
= MONO_ABI_ALIGNOF (double);
5927 case MONO_NATIVE_INT
:
5928 case MONO_NATIVE_UINT
:
5929 case MONO_NATIVE_LPSTR
:
5930 case MONO_NATIVE_LPWSTR
:
5931 case MONO_NATIVE_LPTSTR
:
5932 case MONO_NATIVE_BSTR
:
5933 case MONO_NATIVE_ANSIBSTR
:
5934 case MONO_NATIVE_TBSTR
:
5935 case MONO_NATIVE_UTF8STR
:
5936 case MONO_NATIVE_LPARRAY
:
5937 case MONO_NATIVE_SAFEARRAY
:
5938 case MONO_NATIVE_IUNKNOWN
:
5939 case MONO_NATIVE_IDISPATCH
:
5940 case MONO_NATIVE_INTERFACE
:
5941 case MONO_NATIVE_ASANY
:
5942 case MONO_NATIVE_FUNC
:
5943 case MONO_NATIVE_LPSTRUCT
:
5944 *align
= MONO_ABI_ALIGNOF (gpointer
);
5945 return TARGET_SIZEOF_VOID_P
;
5946 case MONO_NATIVE_STRUCT
:
5947 klass
= mono_class_from_mono_type_internal (type
);
5948 if (klass
== mono_defaults
.object_class
&&
5949 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
5953 padded_size
= mono_class_native_size (klass
, align
);
5954 if (padded_size
== 0)
5957 case MONO_NATIVE_BYVALTSTR
: {
5958 int esize
= unicode
? 2: 1;
5961 return mspec
->data
.array_data
.num_elem
* esize
;
5963 case MONO_NATIVE_BYVALARRAY
: {
5964 // FIXME: Have to consider ArraySubType
5966 klass
= mono_class_from_mono_type_internal (type
);
5967 if (m_class_get_element_class (klass
) == mono_defaults
.char_class
) {
5968 esize
= unicode
? 2 : 1;
5971 esize
= mono_class_native_size (m_class_get_element_class (klass
), align
);
5974 return mspec
->data
.array_data
.num_elem
* esize
;
5976 case MONO_NATIVE_CUSTOM
:
5977 *align
= TARGET_SIZEOF_VOID_P
;
5978 return TARGET_SIZEOF_VOID_P
;
5980 case MONO_NATIVE_CURRENCY
:
5981 case MONO_NATIVE_VBBYREFSTR
:
5983 g_error ("native type %02x not implemented", native_type
);
5986 g_assert_not_reached ();
5991 * mono_marshal_asany:
5992 * This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error.
5995 mono_marshal_asany_impl (MonoObjectHandle o
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
5997 if (MONO_HANDLE_IS_NULL (o
))
6000 MonoType
*t
= m_class_get_byval_arg (mono_handle_class (o
));
6007 case MONO_TYPE_BOOLEAN
:
6010 case MONO_TYPE_CHAR
:
6015 return mono_handle_unbox_unsafe (o
);
6016 case MONO_TYPE_STRING
:
6017 switch (string_encoding
) {
6018 case MONO_NATIVE_LPWSTR
:
6019 return mono_marshal_string_to_utf16_copy_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6020 case MONO_NATIVE_LPSTR
:
6021 case MONO_NATIVE_UTF8STR
:
6022 // Same code path, because in Mono, we treated strings as Utf8
6023 return mono_string_to_utf8str_impl (MONO_HANDLE_CAST (MonoString
, o
), error
);
6025 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6026 g_assert_not_reached ();
6029 case MONO_TYPE_CLASS
:
6030 case MONO_TYPE_VALUETYPE
: {
6032 MonoClass
*klass
= t
->data
.klass
;
6034 if (mono_class_is_auto_layout (klass
))
6037 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6038 return mono_handle_unbox_unsafe (o
);
6040 gpointer res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), error
);
6041 return_val_if_nok (error
, NULL
);
6043 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6044 MonoMethod
*method
= mono_marshal_get_struct_to_ptr (mono_handle_class (o
));
6045 MonoBoolean delete_old
= FALSE
;
6046 gpointer pa
[ ] = { MONO_HANDLE_RAW (o
), &res
, &delete_old
};
6048 mono_runtime_invoke_handle_void (method
, NULL_HANDLE
, pa
, error
);
6049 return_val_if_nok (error
, NULL
);
6057 mono_error_set_argument (error
, "", "No PInvoke conversion exists for value passed to Object-typed parameter.");
6062 * mono_marshal_free_asany:
6063 * This is a JIT icall, it sets the pending exception (in wrapper)
6066 mono_marshal_free_asany_impl (MonoObjectHandle o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
, MonoError
*error
)
6071 if (MONO_HANDLE_IS_NULL (o
))
6074 t
= m_class_get_byval_arg (mono_handle_class (o
));
6076 case MONO_TYPE_STRING
:
6077 switch (string_encoding
) {
6078 case MONO_NATIVE_LPWSTR
:
6079 case MONO_NATIVE_LPSTR
:
6080 case MONO_NATIVE_UTF8STR
:
6081 mono_marshal_free (ptr
);
6084 g_warning ("marshaling conversion %d not implemented", string_encoding
);
6085 g_assert_not_reached ();
6088 case MONO_TYPE_CLASS
:
6089 case MONO_TYPE_VALUETYPE
: {
6090 klass
= t
->data
.klass
;
6092 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
6095 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
6096 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (mono_handle_class (o
));
6100 pa
[1] = MONO_HANDLE_RAW (o
);
6102 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
6103 if (!mono_error_ok (error
))
6107 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
6108 mono_struct_delete_old (klass
, (char *)ptr
);
6111 mono_marshal_free (ptr
);
6119 #ifndef ENABLE_ILGEN
6121 emit_generic_array_helper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6127 * mono_marshal_get_generic_array_helper:
6129 * Return a wrapper which is used to implement the implicit interfaces on arrays.
6130 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
6133 mono_marshal_get_generic_array_helper (MonoClass
*klass
, const gchar
*name
, MonoMethod
*method
)
6135 MonoMethodSignature
*sig
, *csig
;
6136 MonoMethodBuilder
*mb
;
6140 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
6141 mb
->method
->slot
= -1;
6143 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
6144 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
6146 sig
= mono_method_signature_internal (method
);
6147 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
6148 csig
->generic_param_count
= 0;
6150 get_marshal_cb ()->emit_generic_array_helper (mb
, method
, csig
);
6152 /* We can corlib internal methods */
6153 get_marshal_cb ()->mb_skip_visibility (mb
);
6155 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
6156 info
->d
.generic_array_helper
.method
= method
;
6157 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
6165 * The mono_win32_compat_* functions are implementations of inline
6166 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
6167 * although not exported by kernel32.
6169 * We map the appropiate kernel32 entries to these functions using
6170 * dllmaps declared in the global etc/mono/config.
6174 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
6176 if (!dest
|| !source
)
6179 memcpy (dest
, source
, length
);
6183 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
6185 memset (dest
, fill
, length
);
6189 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
6191 if (!dest
|| !source
)
6194 memmove (dest
, source
, length
);
6198 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
6200 memset (dest
, 0, length
);
6204 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
6209 for (i
= 0; i
< len
; ++i
)
6216 while (byte
&& !(byte
& 1))
6218 g_assert (byte
== 1);
6224 #ifndef ENABLE_ILGEN
6226 emit_thunk_invoke_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6232 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
6234 MonoMethodBuilder
*mb
;
6235 MonoMethodSignature
*sig
, *csig
;
6240 int i
, param_count
, sig_size
;
6244 klass
= method
->klass
;
6245 image
= m_class_get_image (klass
);
6247 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
6249 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
6252 MonoType
*object_type
= mono_get_object_type ();
6254 sig
= mono_method_signature_internal (method
);
6255 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
6257 /* add "this" and exception param */
6258 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
6260 /* dup & extend signature */
6261 csig
= mono_metadata_signature_alloc (image
, param_count
);
6262 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
6263 memcpy (csig
, sig
, sig_size
);
6264 csig
->param_count
= param_count
;
6267 csig
->call_convention
= MONO_CALL_DEFAULT
;
6271 csig
->params
[0] = m_class_get_byval_arg (klass
);
6272 /* move params up by one */
6273 for (i
= 0; i
< sig
->param_count
; i
++)
6274 csig
->params
[i
+ 1] = sig
->params
[i
];
6277 /* setup exception param as byref+[out] */
6278 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
, m_class_get_byval_arg (mono_defaults
.exception_class
));
6279 csig
->params
[param_count
- 1]->byref
= 1;
6280 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
6282 /* convert struct return to object */
6283 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6284 csig
->ret
= object_type
;
6286 get_marshal_cb ()->emit_thunk_invoke_wrapper (mb
, method
, csig
);
6288 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
6295 clear_runtime_invoke_method_cache (GHashTable
*table
, MonoMethod
*method
)
6297 MonoWrapperMethodCacheKey hash_key
= {method
, FALSE
, FALSE
};
6299 * Since we have a small set of possible keys, remove each one separately, thus
6300 * avoiding the traversal of the entire hash table, when using foreach_remove.
6302 g_hash_table_remove (table
, &hash_key
);
6303 hash_key
.need_direct_wrapper
= TRUE
;
6304 g_hash_table_remove (table
, &hash_key
);
6305 hash_key
.virtual_
= TRUE
;
6306 g_hash_table_remove (table
, &hash_key
);
6307 hash_key
.need_direct_wrapper
= FALSE
;
6308 g_hash_table_remove (table
, &hash_key
);
6312 * mono_marshal_free_dynamic_wrappers:
6314 * Free wrappers of the dynamic method METHOD.
6317 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
6319 MonoImage
*image
= get_method_image (method
);
6321 g_assert (method_is_dynamic (method
));
6323 /* This could be called during shutdown */
6324 if (marshal_mutex_initialized
)
6325 mono_marshal_lock ();
6327 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
6328 * they could be shared with other methods ?
6330 if (image
->wrapper_caches
.runtime_invoke_method_cache
)
6331 clear_runtime_invoke_method_cache (image
->wrapper_caches
.runtime_invoke_method_cache
, method
);
6332 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
6333 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
6334 // FIXME: Need to clear the caches in other images as well
6335 if (image
->delegate_bound_static_invoke_cache
)
6336 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature_internal (method
));
6338 if (marshal_mutex_initialized
)
6339 mono_marshal_unlock ();
6343 mono_marshal_get_type_object (MonoClass
*klass
)
6346 MonoType
*type
= m_class_get_byval_arg (klass
);
6347 MonoObject
*result
= (MonoObject
*)mono_type_get_object_checked (mono_domain_get (), type
, error
);
6348 mono_error_set_pending_exception (error
);
6353 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
)
6355 get_marshal_cb ()->emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, aot
, check_exceptions
, func_param
);
6358 #ifndef ENABLE_ILGEN
6360 emit_native_wrapper_noilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
)
6365 static MonoMarshalCallbacks marshal_cb
;
6366 static gboolean cb_inited
= FALSE
;
6369 mono_install_marshal_callbacks (MonoMarshalCallbacks
*cb
)
6371 g_assert (!cb_inited
);
6372 g_assert (cb
->version
== MONO_MARSHAL_CALLBACKS_VERSION
);
6373 memcpy (&marshal_cb
, cb
, sizeof (MonoMarshalCallbacks
));
6377 #ifndef ENABLE_ILGEN
6379 install_noilgen (void)
6381 MonoMarshalCallbacks cb
;
6382 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6383 cb
.emit_marshal_array
= emit_marshal_array_noilgen
;
6384 cb
.emit_marshal_boolean
= emit_marshal_boolean_noilgen
;
6385 cb
.emit_marshal_ptr
= emit_marshal_ptr_noilgen
;
6386 cb
.emit_marshal_char
= emit_marshal_char_noilgen
;
6387 cb
.emit_marshal_scalar
= emit_marshal_scalar_noilgen
;
6388 cb
.emit_marshal_custom
= emit_marshal_custom_noilgen
;
6389 cb
.emit_marshal_asany
= emit_marshal_asany_noilgen
;
6390 cb
.emit_marshal_vtype
= emit_marshal_vtype_noilgen
;
6391 cb
.emit_marshal_string
= emit_marshal_string_noilgen
;
6392 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_noilgen
;
6393 cb
.emit_marshal_handleref
= emit_marshal_handleref_noilgen
;
6394 cb
.emit_marshal_object
= emit_marshal_object_noilgen
;
6395 cb
.emit_marshal_variant
= emit_marshal_variant_noilgen
;
6396 cb
.emit_castclass
= emit_castclass_noilgen
;
6397 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_noilgen
;
6398 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_noilgen
;
6399 cb
.emit_isinst
= emit_isinst_noilgen
;
6400 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_noilgen
;
6401 cb
.emit_stelemref
= emit_stelemref_noilgen
;
6402 cb
.emit_array_address
= emit_array_address_noilgen
;
6403 cb
.emit_native_wrapper
= emit_native_wrapper_noilgen
;
6404 cb
.emit_managed_wrapper
= emit_managed_wrapper_noilgen
;
6405 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_noilgen
;
6406 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_noilgen
;
6407 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_noilgen
;
6408 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_noilgen
;
6409 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_noilgen
;
6410 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_noilgen
;
6411 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_noilgen
;
6412 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_noilgen
;
6413 cb
.emit_generic_array_helper
= emit_generic_array_helper_noilgen
;
6414 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_noilgen
;
6415 cb
.emit_create_string_hack
= emit_create_string_hack_noilgen
;
6416 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_noilgen
;
6417 cb
.emit_icall_wrapper
= emit_icall_wrapper_noilgen
;
6418 cb
.emit_return
= emit_return_noilgen
;
6419 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_noilgen
;
6420 cb
.mb_skip_visibility
= mb_skip_visibility_noilgen
;
6421 cb
.mb_set_dynamic
= mb_set_dynamic_noilgen
;
6422 cb
.mb_emit_exception
= mb_emit_exception_noilgen
;
6423 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_noilgen
;
6424 cb
.mb_emit_byte
= mb_emit_byte_noilgen
;
6425 mono_install_marshal_callbacks (&cb
);
6429 static MonoMarshalCallbacks
*
6430 get_marshal_cb (void)
6432 if (G_UNLIKELY (!cb_inited
)) {
6434 mono_marshal_ilgen_init ();