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/utils/mono-counters.h"
50 #include "mono/utils/mono-tls.h"
51 #include "mono/utils/mono-memory-model.h"
52 #include "mono/utils/atomic.h"
53 #include <mono/utils/mono-threads.h>
54 #include <mono/utils/mono-threads-coop.h>
55 #include <mono/utils/mono-error-internals.h>
60 /* #define DEBUG_RUNTIME_CODE */
62 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
66 #include "mono/cil/opcode.def"
72 * This mutex protects the various marshalling related caches in MonoImage
73 * and a few other data structures static to this file.
75 * The marshal lock is a non-recursive complex lock that sits below the domain lock in the
76 * runtime locking latice. Which means it can take simple locks suck as the image lock.
78 #define mono_marshal_lock() mono_locks_os_acquire (&marshal_mutex, MarshalLock)
79 #define mono_marshal_unlock() mono_locks_os_release (&marshal_mutex, MarshalLock)
80 static mono_mutex_t marshal_mutex
;
81 static gboolean marshal_mutex_initialized
;
83 static MonoNativeTlsKey last_error_tls_id
;
85 static MonoNativeTlsKey load_type_info_tls_id
;
87 static gboolean use_aot_wrappers
;
89 static int class_marshal_info_count
;
91 static MonoMarshalCallbacks
*
92 get_marshal_cb (void);
95 delegate_hash_table_add (MonoDelegateHandle d
);
98 delegate_hash_table_remove (MonoDelegate
*d
);
101 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*eltype
, guint32 elnum
);
104 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*eltype
, guint32 elnum
);
107 mono_delegate_handle_to_ftnptr (MonoDelegateHandle delegate
, MonoError
*error
);
110 mono_ftnptr_to_delegate_handle (MonoClass
*klass
, gpointer ftn
, MonoError
*error
);
112 /* Lazy class loading functions */
113 static GENERATE_GET_CLASS_WITH_CACHE (string_builder
, "System.Text", "StringBuilder");
114 static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
117 get_method_image (MonoMethod
*method
)
119 return m_class_get_image (method
->klass
);
123 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean no_wrapper
)
125 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
127 mono_register_jit_icall (func
, name
, sig
, no_wrapper
);
131 register_icall_no_wrapper (gpointer func
, const char *name
, const char *sigstr
)
133 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
135 mono_register_jit_icall (func
, name
, sig
, TRUE
);
139 mono_signature_no_pinvoke (MonoMethod
*method
)
141 MonoMethodSignature
*sig
= mono_method_signature (method
);
143 sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
144 sig
->pinvoke
= FALSE
;
151 mono_marshal_init_tls (void)
153 mono_native_tls_alloc (&last_error_tls_id
, NULL
);
154 mono_native_tls_alloc (&load_type_info_tls_id
, NULL
);
158 mono_object_isinst_icall (MonoObject
*obj
, MonoClass
*klass
)
163 /* This is called from stelemref so it is expected to succeed */
165 if (mono_class_is_interface (klass
)) {
166 MonoVTable
*vt
= obj
->vtable
;
168 if (!m_class_is_inited (klass
))
169 mono_class_init (klass
);
171 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt
, m_class_get_interface_id (klass
)))
176 MonoObject
*result
= mono_object_isinst_checked (obj
, klass
, error
);
177 mono_error_set_pending_exception (error
);
182 ves_icall_mono_string_from_utf16 (gunichar2
*data
)
185 MonoString
*result
= mono_string_from_utf16_checked (data
, error
);
186 mono_error_set_pending_exception (error
);
191 ves_icall_mono_string_to_utf8 (MonoString
*str
)
194 char *result
= mono_string_to_utf8_checked (str
, error
);
195 mono_error_set_pending_exception (error
);
200 ves_icall_string_new_wrapper (const char *text
)
204 MonoString
*res
= mono_string_new_checked (mono_domain_get (), text
, error
);
205 mono_error_set_pending_exception (error
);
213 mono_marshal_init (void)
215 static gboolean module_initialized
= FALSE
;
217 if (!module_initialized
) {
218 module_initialized
= TRUE
;
219 mono_os_mutex_init_recursive (&marshal_mutex
);
220 marshal_mutex_initialized
= TRUE
;
222 register_icall (ves_icall_System_Threading_Thread_ResetAbort
, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE
);
223 register_icall (mono_marshal_string_to_utf16
, "mono_marshal_string_to_utf16", "ptr obj", FALSE
);
224 register_icall (mono_marshal_string_to_utf16_copy
, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE
);
225 register_icall (mono_string_to_utf16
, "mono_string_to_utf16", "ptr obj", FALSE
);
226 register_icall (ves_icall_mono_string_from_utf16
, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE
);
227 register_icall (mono_string_from_byvalstr
, "mono_string_from_byvalstr", "obj ptr int", FALSE
);
228 register_icall (mono_string_from_byvalwstr
, "mono_string_from_byvalwstr", "obj ptr int", FALSE
);
229 register_icall (mono_string_new_wrapper
, "mono_string_new_wrapper", "obj ptr", FALSE
);
230 register_icall (ves_icall_string_new_wrapper
, "ves_icall_string_new_wrapper", "obj ptr", FALSE
);
231 register_icall (mono_string_new_len_wrapper
, "mono_string_new_len_wrapper", "obj ptr int", FALSE
);
232 register_icall (ves_icall_mono_string_to_utf8
, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE
);
233 register_icall (mono_string_to_utf8str
, "mono_string_to_utf8str", "ptr obj", FALSE
);
234 register_icall (mono_string_to_ansibstr
, "mono_string_to_ansibstr", "ptr object", FALSE
);
235 register_icall (mono_string_builder_to_utf8
, "mono_string_builder_to_utf8", "ptr object", FALSE
);
236 register_icall (mono_string_builder_to_utf16
, "mono_string_builder_to_utf16", "ptr object", FALSE
);
237 register_icall (mono_array_to_savearray
, "mono_array_to_savearray", "ptr object", FALSE
);
238 register_icall (mono_array_to_lparray
, "mono_array_to_lparray", "ptr object", FALSE
);
239 register_icall (mono_free_lparray
, "mono_free_lparray", "void object ptr", FALSE
);
240 register_icall (mono_byvalarray_to_array
, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE
);
241 register_icall (mono_byvalarray_to_byte_array
, "mono_byvalarray_to_byte_array", "void object ptr int32", FALSE
);
242 register_icall (mono_array_to_byvalarray
, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE
);
243 register_icall (mono_array_to_byte_byvalarray
, "mono_array_to_byte_byvalarray", "void ptr object int32", FALSE
);
244 register_icall (mono_delegate_to_ftnptr
, "mono_delegate_to_ftnptr", "ptr object", FALSE
);
245 register_icall (mono_ftnptr_to_delegate
, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE
);
246 register_icall (mono_marshal_asany
, "mono_marshal_asany", "ptr object int32 int32", FALSE
);
247 register_icall (mono_marshal_free_asany
, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE
);
248 register_icall (ves_icall_marshal_alloc
, "ves_icall_marshal_alloc", "ptr ptr", FALSE
);
249 register_icall (mono_marshal_free
, "mono_marshal_free", "void ptr", FALSE
);
250 register_icall (mono_marshal_set_last_error
, "mono_marshal_set_last_error", "void", TRUE
);
251 register_icall (mono_marshal_set_last_error_windows
, "mono_marshal_set_last_error_windows", "void int32", TRUE
);
252 register_icall (mono_string_utf8_to_builder
, "mono_string_utf8_to_builder", "void ptr ptr", FALSE
);
253 register_icall (mono_string_utf8_to_builder2
, "mono_string_utf8_to_builder2", "object ptr", FALSE
);
254 register_icall (mono_string_utf16_to_builder
, "mono_string_utf16_to_builder", "void ptr ptr", FALSE
);
255 register_icall (mono_string_utf16_to_builder2
, "mono_string_utf16_to_builder2", "object ptr", FALSE
);
256 register_icall (mono_marshal_free_array
, "mono_marshal_free_array", "void ptr int32", FALSE
);
257 register_icall (mono_string_to_byvalstr
, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE
);
258 register_icall (mono_string_to_byvalwstr
, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE
);
259 register_icall (g_free
, "g_free", "void ptr", FALSE
);
260 register_icall_no_wrapper (mono_object_isinst_icall
, "mono_object_isinst_icall", "object object ptr");
261 register_icall (mono_struct_delete_old
, "mono_struct_delete_old", "void ptr ptr", FALSE
);
262 register_icall (mono_delegate_begin_invoke
, "mono_delegate_begin_invoke", "object object ptr", FALSE
);
263 register_icall (mono_delegate_end_invoke
, "mono_delegate_end_invoke", "object object ptr", FALSE
);
264 register_icall (mono_gc_wbarrier_generic_nostore
, "wb_generic", "void ptr", FALSE
);
265 register_icall (mono_gchandle_get_target
, "mono_gchandle_get_target", "object int32", TRUE
);
266 register_icall (mono_marshal_isinst_with_cache
, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE
);
267 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE
);
268 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE
);
269 register_icall (mono_threads_enter_gc_unsafe_region_unbalanced
, "mono_threads_enter_gc_unsafe_region_unbalanced", "ptr ptr", TRUE
);
270 register_icall (mono_threads_exit_gc_unsafe_region_unbalanced
, "mono_threads_exit_gc_unsafe_region_unbalanced", "void ptr ptr", TRUE
);
271 register_icall (mono_threads_attach_coop
, "mono_threads_attach_coop", "ptr ptr ptr", TRUE
);
272 register_icall (mono_threads_detach_coop
, "mono_threads_detach_coop", "void ptr ptr", TRUE
);
273 register_icall (mono_icall_start
, "mono_icall_start", "ptr ptr ptr", TRUE
);
274 register_icall (mono_icall_end
, "mono_icall_end", "void ptr ptr ptr", TRUE
);
275 register_icall (mono_icall_handle_new
, "mono_icall_handle_new", "ptr ptr", TRUE
);
276 register_icall (mono_icall_handle_new_interior
, "mono_icall_handle_new_interior", "ptr ptr", TRUE
);
278 mono_cominterop_init ();
279 mono_remoting_init ();
281 mono_counters_register ("MonoClass::class_marshal_info_count count",
282 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_marshal_info_count
);
288 mono_marshal_cleanup (void)
290 mono_cominterop_cleanup ();
292 mono_native_tls_free (load_type_info_tls_id
);
293 mono_native_tls_free (last_error_tls_id
);
294 mono_os_mutex_destroy (&marshal_mutex
);
295 marshal_mutex_initialized
= FALSE
;
299 mono_marshal_lock_internal (void)
301 mono_marshal_lock ();
305 mono_marshal_unlock_internal (void)
307 mono_marshal_unlock ();
310 /* This is a JIT icall, it sets the pending exception and return NULL on error */
312 mono_delegate_to_ftnptr (MonoDelegate
*delegate_raw
)
314 HANDLE_FUNCTION_ENTER ();
316 MONO_HANDLE_DCL (MonoDelegate
, delegate
);
317 gpointer result
= mono_delegate_handle_to_ftnptr (delegate
, error
);
318 mono_error_set_pending_exception (error
);
319 HANDLE_FUNCTION_RETURN_VAL (result
);
323 mono_delegate_handle_to_ftnptr (MonoDelegateHandle delegate
, MonoError
*error
)
325 HANDLE_FUNCTION_ENTER ();
326 gpointer result
= NULL
;
328 MonoMethod
*method
, *wrapper
;
330 uint32_t target_handle
= 0;
332 if (MONO_HANDLE_IS_NULL (delegate
))
335 if (MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
)) {
336 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
340 klass
= mono_handle_class (delegate
);
341 g_assert (m_class_is_delegate (klass
));
343 method
= MONO_HANDLE_GETVAL (delegate
, method
);
344 if (MONO_HANDLE_GETVAL (delegate
, method_is_virtual
)) {
345 MonoObjectHandle delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
346 method
= mono_object_handle_get_virtual_method (delegate_target
, method
, error
);
347 goto_if_nok (error
, leave
);
350 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
351 const char *exc_class
, *exc_arg
;
354 ftnptr
= mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
356 g_assert (exc_class
);
357 mono_error_set_generic_error (error
, "System", exc_class
, "%s", exc_arg
);
364 MonoObjectHandle delegate_target
= MONO_HANDLE_NEW_GET (MonoObject
, delegate
, target
);
365 if (!MONO_HANDLE_IS_NULL (delegate_target
)) {
366 /* Produce a location which can be embedded in JITted code */
367 target_handle
= mono_gchandle_new_weakref (MONO_HANDLE_RAW (delegate_target
), FALSE
); /* FIXME: a version of mono_gchandle_new_weakref that takes a coop handle */
370 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
, error
);
371 goto_if_nok (error
, leave
);
373 MONO_HANDLE_SETVAL (delegate
, delegate_trampoline
, gpointer
, mono_compile_method_checked (wrapper
, error
));
374 goto_if_nok (error
, leave
);
376 // Add the delegate to the delegate hash table
377 delegate_hash_table_add (delegate
);
379 /* when the object is collected, collect the dynamic method, too */
380 mono_object_register_finalizer ((MonoObject
*) MONO_HANDLE_RAW (delegate
));
382 result
= MONO_HANDLE_GETVAL (delegate
, delegate_trampoline
);
385 if (!is_ok (error
) && target_handle
!= 0)
386 mono_gchandle_free (target_handle
);
387 HANDLE_FUNCTION_RETURN_VAL (result
);
391 * this hash table maps from a delegate trampoline object to a weak reference
392 * of the delegate. As an optimizations with a non-moving GC we store the
393 * object pointer itself, otherwise we use a GC handle.
395 static GHashTable
*delegate_hash_table
;
398 delegate_hash_table_new (void) {
399 return g_hash_table_new (NULL
, NULL
);
403 delegate_hash_table_remove (MonoDelegate
*d
)
405 guint32 gchandle
= 0;
407 mono_marshal_lock ();
408 if (delegate_hash_table
== NULL
)
409 delegate_hash_table
= delegate_hash_table_new ();
410 if (mono_gc_is_moving ())
411 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
412 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
413 mono_marshal_unlock ();
414 if (gchandle
&& mono_gc_is_moving ())
415 mono_gchandle_free (gchandle
);
419 delegate_hash_table_add (MonoDelegateHandle d
)
422 guint32 old_gchandle
;
424 mono_marshal_lock ();
425 if (delegate_hash_table
== NULL
)
426 delegate_hash_table
= delegate_hash_table_new ();
427 gpointer delegate_trampoline
= MONO_HANDLE_GETVAL (d
, delegate_trampoline
);
428 if (mono_gc_is_moving ()) {
429 gchandle
= mono_gchandle_new_weakref ((MonoObject
*) MONO_HANDLE_RAW (d
), FALSE
);
430 old_gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, delegate_trampoline
));
431 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
433 mono_gchandle_free (old_gchandle
);
435 g_hash_table_insert (delegate_hash_table
, delegate_trampoline
, MONO_HANDLE_RAW (d
));
437 mono_marshal_unlock ();
441 * mono_marshal_use_aot_wrappers:
443 * Instructs this module to use AOT compatible wrappers.
446 mono_marshal_use_aot_wrappers (gboolean use
)
448 use_aot_wrappers
= use
;
452 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
455 MonoCustomAttrInfo
*cinfo
;
456 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
458 /* The attribute is only available in Net 2.0 */
459 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
461 * The pinvoke attributes are stored in a real custom attribute so we have to
464 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
465 if (!mono_error_ok (error
)) {
466 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
467 mono_error_cleanup (error
);
469 if (cinfo
&& !mono_runtime_get_no_exec ()) {
470 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), error
);
472 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
474 if (!mono_error_ok (error
)) {
475 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (error
));
476 mono_error_cleanup (error
);
480 mono_custom_attrs_free (cinfo
);
485 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
487 mono_ftnptr_to_delegate (MonoClass
*klass
, gpointer ftn
)
489 HANDLE_FUNCTION_ENTER ();
491 MonoDelegateHandle result
= mono_ftnptr_to_delegate_handle (klass
, ftn
, error
);
492 mono_error_set_pending_exception (error
);
493 HANDLE_FUNCTION_RETURN_OBJ (result
);
497 mono_ftnptr_to_delegate_handle (MonoClass
*klass
, gpointer ftn
, MonoError
*error
)
499 HANDLE_FUNCTION_ENTER ();
502 MonoDelegateHandle d
= MONO_HANDLE_NEW (MonoDelegate
, NULL
);
507 mono_marshal_lock ();
508 if (delegate_hash_table
== NULL
)
509 delegate_hash_table
= delegate_hash_table_new ();
511 if (mono_gc_is_moving ()) {
512 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
513 mono_marshal_unlock ();
515 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_CAST (MonoDelegate
, mono_gchandle_get_target_handle (gchandle
)));
517 MONO_HANDLE_ASSIGN (d
, MONO_HANDLE_NEW (MonoDelegate
, g_hash_table_lookup (delegate_hash_table
, ftn
)));
518 mono_marshal_unlock ();
520 if (MONO_HANDLE_IS_NULL (d
)) {
521 /* This is a native function, so construct a delegate for it */
522 MonoMethodSignature
*sig
;
524 MonoMarshalSpec
**mspecs
;
525 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
526 MonoMethodPInvoke piinfo
;
527 MonoObjectHandle this_obj
;
530 if (use_aot_wrappers
) {
531 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
532 this_obj
= MONO_HANDLE_NEW (MonoObject
, mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, error
));
533 goto_if_nok (error
, leave
);
535 memset (&piinfo
, 0, sizeof (piinfo
));
536 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
538 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
539 mono_method_get_marshal_info (invoke
, mspecs
);
540 /* Freed below so don't alloc from mempool */
541 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
544 wrapper
= mono_marshal_get_native_func_wrapper (m_class_get_image (klass
), sig
, &piinfo
, mspecs
, ftn
);
545 this_obj
= MONO_HANDLE_NEW (MonoObject
, NULL
);
547 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
549 mono_metadata_free_marshal_spec (mspecs
[i
]);
554 MONO_HANDLE_ASSIGN (d
, mono_object_new_handle (mono_domain_get (), klass
, error
));
555 goto_if_nok (error
, leave
);
556 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, error
);
557 goto_if_nok (error
, leave
);
559 mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject
, d
), this_obj
, compiled_ptr
, wrapper
, error
);
560 goto_if_nok (error
, leave
);
563 g_assert (!MONO_HANDLE_IS_NULL (d
));
564 if (MONO_HANDLE_DOMAIN (d
) != mono_domain_get ())
565 mono_error_set_not_supported (error
, "Delegates cannot be marshalled from native code into a domain other than their home domain");
568 HANDLE_FUNCTION_RETURN_REF (MonoDelegate
, d
);
572 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
577 delegate_hash_table_remove (delegate
);
579 ptr
= (gpointer
)mono_atomic_xchg_ptr (&delegate
->delegate_trampoline
, NULL
);
581 if (!delegate
->target
) {
582 /* The wrapper method is shared between delegates -> no need to free it */
591 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
592 /* FIXME we leak wrapper with the interpreter */
596 method
= mono_jit_info_get_method (ji
);
597 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
599 /*the target gchandle is the first entry after size and the wrapper itself.*/
600 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
603 mono_gchandle_free (gchandle
);
605 mono_runtime_free_method (mono_object_domain (delegate
), method
);
609 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
611 mono_string_from_byvalstr (const char *data
, int max_len
)
614 MonoDomain
*domain
= mono_domain_get ();
620 while (len
< max_len
- 1 && data
[len
])
623 MonoString
*result
= mono_string_new_len_checked (domain
, data
, len
, error
);
624 mono_error_set_pending_exception (error
);
628 /* This is a JIT icall, it sets the pending exception and return NULL on error */
630 mono_string_from_byvalwstr (gunichar2
*data
, int max_len
)
633 MonoString
*res
= NULL
;
634 MonoDomain
*domain
= mono_domain_get ();
640 while (data
[len
]) len
++;
642 res
= mono_string_new_utf16_checked (domain
, data
, MIN (len
, max_len
), error
);
643 if (!mono_error_ok (error
)) {
644 mono_error_set_pending_exception (error
);
651 mono_array_to_savearray (MonoArray
*array
)
656 g_assert_not_reached ();
661 mono_array_to_lparray (MonoArray
*array
)
664 gpointer
*nativeArray
= NULL
;
665 int nativeArraySize
= 0;
676 klass
= array
->obj
.vtable
->klass
;
677 MonoClass
*klass_element_class
= m_class_get_element_class (klass
);
679 switch (m_class_get_byval_arg (klass_element_class
)->type
) {
681 g_assert_not_reached ();
683 case MONO_TYPE_CLASS
:
684 nativeArraySize
= array
->max_length
;
685 nativeArray
= (void **)g_malloc (sizeof(gpointer
) * nativeArraySize
);
686 for(i
= 0; i
< nativeArraySize
; ++i
) {
687 nativeArray
[i
] = mono_cominterop_get_com_interface (((MonoObject
**)array
->vector
)[i
], klass_element_class
, error
);
688 if (mono_error_set_pending_exception (error
))
693 case MONO_TYPE_BOOLEAN
:
706 case MONO_TYPE_VALUETYPE
:
710 case MONO_TYPE_GENERICINST
:
711 case MONO_TYPE_OBJECT
:
712 case MONO_TYPE_ARRAY
:
713 case MONO_TYPE_SZARRAY
:
714 case MONO_TYPE_STRING
:
716 g_warning ("type 0x%x not handled", m_class_get_byval_arg (klass_element_class
)->type
);
717 g_assert_not_reached ();
720 return array
->vector
;
724 mono_free_lparray (MonoArray
*array
, gpointer
* nativeArray
)
734 klass
= array
->obj
.vtable
->klass
;
736 if (m_class_get_byval_arg (m_class_get_element_class (klass
))->type
== MONO_TYPE_CLASS
)
737 g_free (nativeArray
);
742 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*elclass
, guint32 elnum
)
744 g_assert (m_class_get_element_class (mono_object_class (&arr
->obj
)) == mono_defaults
.char_class
);
746 if (elclass
== mono_defaults
.byte_class
) {
747 GError
*gerror
= NULL
;
751 ut
= g_utf8_to_utf16 ((const gchar
*)native_arr
, elnum
, NULL
, &items_written
, &gerror
);
754 memcpy (mono_array_addr (arr
, guint16
, 0), ut
, items_written
* sizeof (guint16
));
758 g_error_free (gerror
);
761 g_assert_not_reached ();
765 mono_byvalarray_to_byte_array (MonoArray
*arr
, gpointer native_arr
, guint32 elnum
)
767 mono_byvalarray_to_array (arr
, native_arr
, mono_defaults
.byte_class
, elnum
);
770 /* This is a JIT icall, it sets the pending exception and returns on error */
772 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*elclass
, guint32 elnum
)
774 g_assert (m_class_get_element_class (mono_object_class (&arr
->obj
)) == mono_defaults
.char_class
);
776 if (elclass
== mono_defaults
.byte_class
) {
778 GError
*gerror
= NULL
;
780 as
= g_utf16_to_utf8 (mono_array_addr (arr
, gunichar2
, 0), mono_array_length (arr
), NULL
, NULL
, &gerror
);
782 mono_set_pending_exception (mono_get_exception_argument ("string", gerror
->message
));
783 g_error_free (gerror
);
787 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
790 g_assert_not_reached ();
795 mono_array_to_byte_byvalarray (gpointer native_arr
, MonoArray
*arr
, guint32 elnum
)
797 mono_array_to_byvalarray (native_arr
, arr
, mono_defaults
.byte_class
, elnum
);
800 static MonoStringBuilder
*
801 mono_string_builder_new (int starting_string_length
)
803 static MonoClass
*string_builder_class
;
804 static MonoMethod
*sb_ctor
;
805 static void *args
[1];
808 int initial_len
= starting_string_length
;
814 MonoMethodDesc
*desc
;
817 string_builder_class
= mono_class_get_string_builder_class ();
818 g_assert (string_builder_class
);
819 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
820 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
822 mono_method_desc_free (desc
);
823 mono_memory_barrier ();
827 // We make a new array in the _to_builder function, so this
828 // array will always be garbage collected.
829 args
[0] = &initial_len
;
831 MonoStringBuilder
*sb
= (MonoStringBuilder
*)mono_object_new_checked (mono_domain_get (), string_builder_class
, error
);
832 mono_error_assert_ok (error
);
835 mono_runtime_try_invoke (sb_ctor
, sb
, args
, &exc
, error
);
836 g_assert (exc
== NULL
);
837 mono_error_assert_ok (error
);
839 g_assert (sb
->chunkChars
->max_length
>= initial_len
);
845 mono_string_utf16_to_builder_copy (MonoStringBuilder
*sb
, gunichar2
*text
, size_t string_len
)
847 gunichar2
*charDst
= (gunichar2
*)sb
->chunkChars
->vector
;
848 gunichar2
*charSrc
= (gunichar2
*)text
;
849 memcpy (charDst
, charSrc
, sizeof (gunichar2
) * string_len
);
851 sb
->chunkLength
= string_len
;
857 mono_string_utf16_to_builder2 (gunichar2
*text
)
863 for (len
= 0; text
[len
] != 0; ++len
);
865 MonoStringBuilder
*sb
= mono_string_builder_new (len
);
866 mono_string_utf16_to_builder (sb
, text
);
872 mono_string_utf8_to_builder (MonoStringBuilder
*sb
, char *text
)
877 GError
*gerror
= NULL
;
879 gunichar2
* ut
= g_utf8_to_utf16 (text
, strlen (text
), NULL
, &copied
, &gerror
);
880 int capacity
= mono_string_builder_capacity (sb
);
882 if (copied
> capacity
)
886 MONO_OBJECT_SETREF (sb
, chunkPrevious
, NULL
);
887 mono_string_utf16_to_builder_copy (sb
, ut
, copied
);
889 g_error_free (gerror
);
895 mono_string_utf8_to_builder2 (char *text
)
900 int len
= strlen (text
);
901 MonoStringBuilder
*sb
= mono_string_builder_new (len
);
902 mono_string_utf8_to_builder (sb
, text
);
908 mono_string_utf16_to_builder (MonoStringBuilder
*sb
, gunichar2
*text
)
914 for (len
= 0; text
[len
] != 0; ++len
);
916 if (len
> mono_string_builder_capacity (sb
))
917 len
= mono_string_builder_capacity (sb
);
919 mono_string_utf16_to_builder_copy (sb
, text
, len
);
923 * mono_string_builder_to_utf8:
924 * \param sb the string builder
926 * Converts to utf8 the contents of the \c MonoStringBuilder .
928 * \returns a utf8 string with the contents of the \c StringBuilder .
930 * The return value must be released with mono_marshal_free.
932 * This is a JIT icall, it sets the pending exception and returns NULL on error.
935 mono_string_builder_to_utf8 (MonoStringBuilder
*sb
)
938 GError
*gerror
= NULL
;
943 gunichar2
*str_utf16
= mono_string_builder_to_utf16 (sb
);
945 guint str_len
= mono_string_builder_string_length (sb
);
947 gchar
*tmp
= g_utf16_to_utf8 (str_utf16
, str_len
, NULL
, &byte_count
, &gerror
);
950 g_error_free (gerror
);
951 mono_marshal_free (str_utf16
);
952 mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
955 guint len
= mono_string_builder_capacity (sb
) + 1;
956 gchar
*res
= (gchar
*)mono_marshal_alloc (MAX (byte_count
+1, len
* sizeof (gchar
)), error
);
957 if (!mono_error_ok (error
)) {
958 mono_marshal_free (str_utf16
);
960 mono_error_set_pending_exception (error
);
964 memcpy (res
, tmp
, byte_count
);
965 res
[byte_count
] = '\0';
967 mono_marshal_free (str_utf16
);
974 * mono_string_builder_to_utf16:
975 * \param sb the string builder
977 * Converts to utf16 the contents of the \c MonoStringBuilder .
979 * Returns: a utf16 string with the contents of the \c StringBuilder .
981 * The return value must be released with mono_marshal_free.
983 * This is a JIT icall, it sets the pending exception and returns NULL on error.
986 mono_string_builder_to_utf16 (MonoStringBuilder
*sb
)
993 g_assert (sb
->chunkChars
);
995 guint len
= mono_string_builder_capacity (sb
);
1000 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((len
+ 1) * sizeof (gunichar2
), error
);
1001 if (!mono_error_ok (error
)) {
1002 mono_error_set_pending_exception (error
);
1011 MonoStringBuilder
* chunk
= sb
;
1013 if (chunk
->chunkLength
> 0) {
1014 // Check that we will not overrun our boundaries.
1015 gunichar2
*source
= (gunichar2
*)chunk
->chunkChars
->vector
;
1017 g_assertf (chunk
->chunkLength
<= len
, "A chunk in the StringBuilder had a length longer than expected from the offset.");
1018 memcpy (str
+ chunk
->chunkOffset
, source
, chunk
->chunkLength
* sizeof(gunichar2
));
1020 len
-= chunk
->chunkLength
;
1022 chunk
= chunk
->chunkPrevious
;
1023 } while (chunk
!= NULL
);
1029 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1031 mono_string_to_utf8str (MonoString
*s
)
1034 char *result
= mono_string_to_utf8_checked (s
, error
);
1035 mono_error_set_pending_exception (error
);
1041 mono_string_to_ansibstr (MonoString
*string_obj
)
1043 g_error ("UnmanagedMarshal.BStr is not implemented.");
1048 * mono_string_to_byvalstr:
1049 * \param dst Where to store the null-terminated utf8 decoded string.
1050 * \param src the \c MonoString to copy.
1051 * \param size the maximum number of bytes to copy.
1053 * Copies the \c MonoString pointed to by \p src as a utf8 string
1054 * into \p dst, it copies at most \p size bytes into the destination.
1057 mono_string_to_byvalstr (gpointer dst
, MonoString
*src
, int size
)
1063 g_assert (dst
!= NULL
);
1064 g_assert (size
> 0);
1066 memset (dst
, 0, size
);
1070 s
= mono_string_to_utf8_checked (src
, error
);
1071 if (mono_error_set_pending_exception (error
))
1073 len
= MIN (size
, strlen (s
));
1076 memcpy (dst
, s
, len
);
1081 * mono_string_to_byvalwstr:
1082 * \param dst Where to store the null-terminated utf16 decoded string.
1083 * \param src the \c MonoString to copy.
1084 * \param size the maximum number of wide characters to copy (each consumes 2 bytes)
1086 * Copies the \c MonoString pointed to by \p src as a utf16 string into
1087 * \p dst, it copies at most \p size bytes into the destination (including
1088 * a terminating 16-bit zero terminator).
1091 mono_string_to_byvalwstr (gpointer dst
, MonoString
*src
, int size
)
1095 g_assert (dst
!= NULL
);
1096 g_assert (size
> 1);
1099 memset (dst
, 0, size
* 2);
1103 len
= MIN (size
, (mono_string_length (src
)));
1104 memcpy (dst
, mono_string_chars (src
), len
* 2);
1105 if (size
<= mono_string_length (src
))
1107 *((gunichar2
*) dst
+ len
) = 0;
1110 /* this is an icall, it sets the pending exception and returns NULL on error */
1112 mono_string_new_len_wrapper (const char *text
, guint length
)
1115 MonoString
*result
= mono_string_new_len_checked (mono_domain_get (), text
, length
, error
);
1116 mono_error_set_pending_exception (error
);
1121 mono_type_to_ldind (MonoType
*type
)
1127 switch (type
->type
) {
1129 return CEE_LDIND_I1
;
1131 case MONO_TYPE_BOOLEAN
:
1132 return CEE_LDIND_U1
;
1134 return CEE_LDIND_I2
;
1136 case MONO_TYPE_CHAR
:
1137 return CEE_LDIND_U2
;
1139 return CEE_LDIND_I4
;
1141 return CEE_LDIND_U4
;
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_LDIND_REF
;
1155 return CEE_LDIND_I8
;
1157 return CEE_LDIND_R4
;
1159 return CEE_LDIND_R8
;
1160 case MONO_TYPE_VALUETYPE
:
1161 if (m_class_is_enumtype (type
->data
.klass
)) {
1162 type
= mono_class_enum_basetype (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_ldind", type
->type
);
1178 mono_type_to_stind (MonoType
*type
)
1181 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1185 switch (type
->type
) {
1188 case MONO_TYPE_BOOLEAN
:
1189 return CEE_STIND_I1
;
1192 case MONO_TYPE_CHAR
:
1193 return CEE_STIND_I2
;
1196 return CEE_STIND_I4
;
1200 case MONO_TYPE_FNPTR
:
1202 case MONO_TYPE_CLASS
:
1203 case MONO_TYPE_STRING
:
1204 case MONO_TYPE_OBJECT
:
1205 case MONO_TYPE_SZARRAY
:
1206 case MONO_TYPE_ARRAY
:
1207 return CEE_STIND_REF
;
1210 return CEE_STIND_I8
;
1212 return CEE_STIND_R4
;
1214 return CEE_STIND_R8
;
1215 case MONO_TYPE_VALUETYPE
:
1216 if (m_class_is_enumtype (type
->data
.klass
)) {
1217 type
= mono_class_enum_basetype (type
->data
.klass
);
1221 case MONO_TYPE_TYPEDBYREF
:
1223 case MONO_TYPE_GENERICINST
:
1224 type
= m_class_get_byval_arg (type
->data
.generic_class
->container_class
);
1227 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1232 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1234 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1237 MonoMulticastDelegate
*mcast_delegate
;
1241 g_assert (delegate
);
1242 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
1243 if (mcast_delegate
->delegates
!= NULL
) {
1244 mono_set_pending_exception (mono_get_exception_argument (NULL
, "The delegate must have only one target"));
1248 #ifndef DISABLE_REMOTING
1249 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1250 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1251 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
1252 /* If the target is a proxy, make a direct call. Is proxy's work
1253 // to make the call asynchronous.
1255 MonoMethodMessage
*msg
;
1256 MonoDelegate
*async_callback
;
1258 MonoAsyncResult
*ares
;
1260 MonoArray
*out_args
;
1261 method
= delegate
->method
;
1263 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, error
);
1264 if (mono_error_set_pending_exception (error
))
1266 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, error
);
1267 if (mono_error_set_pending_exception (error
))
1269 MONO_OBJECT_SETREF (ares
, async_delegate
, (MonoObject
*)delegate
);
1270 MONO_OBJECT_SETREF (ares
, async_callback
, (MonoObject
*)async_callback
);
1271 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
1272 msg
->call_type
= CallType_BeginInvoke
;
1275 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
1276 if (!mono_error_ok (error
)) {
1277 mono_error_set_pending_exception (error
);
1281 mono_set_pending_exception ((MonoException
*) exc
);
1287 klass
= delegate
->object
.vtable
->klass
;
1289 method
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
1291 method
= mono_get_delegate_invoke (klass
);
1294 MonoAsyncResult
*result
= mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, error
);
1295 mono_error_set_pending_exception (error
);
1300 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
1304 GString
*res
= g_string_new ("");
1307 g_string_append (res
, prefix
);
1308 g_string_append_c (res
, '_');
1311 mono_type_get_desc (res
, sig
->ret
, FALSE
);
1314 g_string_append (res
, "__this__");
1316 for (i
= 0; i
< sig
->param_count
; ++i
) {
1317 g_string_append_c (res
, '_');
1318 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
1321 g_string_free (res
, FALSE
);
1326 * mono_marshal_get_string_encoding:
1328 * Return the string encoding which should be used for a given parameter.
1331 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1333 /* First try the parameter marshal info */
1335 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
1336 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
1337 return spec
->data
.array_data
.elem_type
;
1340 return spec
->native
;
1344 return MONO_NATIVE_LPSTR
;
1346 /* Then try the method level marshal info */
1347 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1348 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1349 return MONO_NATIVE_LPSTR
;
1350 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1351 return MONO_NATIVE_LPWSTR
;
1352 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1354 return MONO_NATIVE_LPWSTR
;
1356 return MONO_NATIVE_LPSTR
;
1359 return MONO_NATIVE_LPSTR
;
1364 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1366 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1369 case MONO_NATIVE_LPWSTR
:
1370 return MONO_MARSHAL_CONV_STR_LPWSTR
;
1371 case MONO_NATIVE_LPSTR
:
1372 case MONO_NATIVE_VBBYREFSTR
:
1373 return MONO_MARSHAL_CONV_STR_LPSTR
;
1374 case MONO_NATIVE_LPTSTR
:
1375 return MONO_MARSHAL_CONV_STR_LPTSTR
;
1376 case MONO_NATIVE_BSTR
:
1377 return MONO_MARSHAL_CONV_STR_BSTR
;
1378 case MONO_NATIVE_UTF8STR
:
1379 return MONO_MARSHAL_CONV_STR_UTF8STR
;
1381 return MONO_MARSHAL_CONV_INVALID
;
1386 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1388 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1391 case MONO_NATIVE_LPWSTR
:
1392 return MONO_MARSHAL_CONV_SB_LPWSTR
;
1393 case MONO_NATIVE_LPSTR
:
1394 return MONO_MARSHAL_CONV_SB_LPSTR
;
1395 case MONO_NATIVE_UTF8STR
:
1396 return MONO_MARSHAL_CONV_SB_UTF8STR
;
1397 case MONO_NATIVE_LPTSTR
:
1398 return MONO_MARSHAL_CONV_SB_LPTSTR
;
1400 return MONO_MARSHAL_CONV_INVALID
;
1405 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1407 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1412 case MONO_NATIVE_LPWSTR
:
1414 return MONO_MARSHAL_CONV_LPWSTR_STR
;
1415 case MONO_NATIVE_UTF8STR
:
1416 return MONO_MARSHAL_CONV_UTF8STR_STR
;
1417 case MONO_NATIVE_LPSTR
:
1418 case MONO_NATIVE_VBBYREFSTR
:
1419 return MONO_MARSHAL_CONV_LPSTR_STR
;
1420 case MONO_NATIVE_LPTSTR
:
1424 return MONO_MARSHAL_CONV_LPTSTR_STR
;
1425 case MONO_NATIVE_BSTR
:
1426 return MONO_MARSHAL_CONV_BSTR_STR
;
1428 return MONO_MARSHAL_CONV_INVALID
;
1433 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
1435 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1440 case MONO_NATIVE_LPWSTR
:
1442 * mono_string_builder_to_utf16 does not allocate a
1443 * new buffer, so no need to free it.
1446 return MONO_MARSHAL_CONV_LPWSTR_SB
;
1447 case MONO_NATIVE_UTF8STR
:
1448 return MONO_MARSHAL_CONV_UTF8STR_SB
;
1449 case MONO_NATIVE_LPSTR
:
1450 return MONO_MARSHAL_CONV_LPSTR_SB
;
1452 case MONO_NATIVE_LPTSTR
:
1453 return MONO_MARSHAL_CONV_LPTSTR_SB
;
1456 return MONO_MARSHAL_CONV_INVALID
;
1461 * Return whenever a field of a native structure or an array member needs to
1465 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
1467 MonoMarshalNative encoding
;
1470 case MONO_TYPE_VALUETYPE
:
1471 /* FIXME: Optimize this */
1473 case MONO_TYPE_OBJECT
:
1474 case MONO_TYPE_CLASS
:
1475 if (t
->data
.klass
== mono_defaults
.stringbuilder_class
) {
1477 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
1481 case MONO_TYPE_STRING
:
1482 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
1483 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
1490 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
1493 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1496 mono_marshal_lock ();
1499 g_hash_table_new (hash_func
, equal_func
);
1500 mono_memory_barrier ();
1503 mono_marshal_unlock ();
1509 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
1511 return get_cache (var
, hash_func
, equal_func
);
1515 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
1519 mono_marshal_lock ();
1520 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1521 mono_marshal_unlock ();
1528 * Create a MonoMethod from MB, set INFO as wrapper info.
1531 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1532 int max_stack
, WrapperInfo
*info
)
1536 res
= mono_mb_create_method (mb
, sig
, max_stack
);
1538 mono_marshal_set_wrapper_info (res
, info
);
1542 /* Create the method from the builder and place it in the cache */
1544 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
1545 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1546 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
1553 mono_marshal_lock ();
1554 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1555 mono_marshal_unlock ();
1558 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
1559 mono_marshal_lock ();
1560 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1563 g_hash_table_insert (cache
, key
, res
);
1564 mono_marshal_set_wrapper_info (res
, info
);
1565 mono_marshal_unlock ();
1569 mono_marshal_unlock ();
1570 mono_free_method (newm
);
1578 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
1579 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
1582 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
1586 * mono_marshal_method_from_wrapper:
1589 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
1592 int wrapper_type
= wrapper
->wrapper_type
;
1595 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1598 info
= mono_marshal_get_wrapper_info (wrapper
);
1600 switch (wrapper_type
) {
1601 case MONO_WRAPPER_REMOTING_INVOKE
:
1602 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
1603 case MONO_WRAPPER_XDOMAIN_INVOKE
:
1604 m
= info
->d
.remoting
.method
;
1605 if (wrapper
->is_inflated
) {
1609 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
1610 * contains an uninflated method.
1612 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1613 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1617 case MONO_WRAPPER_SYNCHRONIZED
:
1618 m
= info
->d
.synchronized
.method
;
1619 if (wrapper
->is_inflated
) {
1622 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), error
);
1623 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1627 case MONO_WRAPPER_UNBOX
:
1628 return info
->d
.unbox
.method
;
1629 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
1630 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
1631 return info
->d
.managed_to_native
.method
;
1634 case MONO_WRAPPER_RUNTIME_INVOKE
:
1635 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
1636 return info
->d
.runtime_invoke
.method
;
1639 case MONO_WRAPPER_DELEGATE_INVOKE
:
1641 return info
->d
.delegate_invoke
.method
;
1650 * mono_marshal_get_wrapper_info:
1652 * Retrieve the WrapperInfo structure associated with WRAPPER.
1655 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
1657 g_assert (wrapper
->wrapper_type
);
1659 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
1663 * mono_marshal_set_wrapper_info:
1665 * Set the WrapperInfo structure associated with the wrapper
1666 * method METHOD to INFO.
1669 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
1673 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
1676 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
1681 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
1685 info
= (WrapperInfo
*)mono_image_alloc0 (get_method_image (mb
->method
), sizeof (WrapperInfo
));
1686 info
->subtype
= subtype
;
1691 * get_wrapper_target_class:
1693 * Return the class where a wrapper method should be placed.
1696 get_wrapper_target_class (MonoImage
*image
)
1703 * - can't put all wrappers into an mscorlib class, because they reference
1704 * metadata (signature) so they should be put into the same image as the
1705 * method they wrap, so they are unloaded together.
1706 * - putting them into a class with a type initalizer could cause the
1707 * initializer to be executed which can be a problem if the wrappers are
1709 * - putting them into an inflated class can cause problems if the the
1710 * class is deleted because it references an image which is unloaded.
1711 * To avoid these problems, we put the wrappers into the <Module> class of
1714 if (image_is_dynamic (image
)) {
1715 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
1717 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), error
);
1718 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1726 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
1727 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
1731 * check_generic_wrapper_cache:
1733 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
1734 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
1735 * generic method definition.
1738 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
1741 MonoMethod
*inst
, *def
;
1742 MonoGenericContext
*ctx
;
1744 g_assert (orig_method
->is_inflated
);
1745 ctx
= mono_method_get_context (orig_method
);
1748 * Look for the instance
1750 res
= mono_marshal_find_in_cache (cache
, key
);
1755 * Look for the definition
1757 def
= mono_marshal_find_in_cache (cache
, def_key
);
1760 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1761 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1763 mono_memory_barrier ();
1764 mono_marshal_lock ();
1765 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1767 g_hash_table_insert (cache
, key
, inst
);
1770 mono_marshal_unlock ();
1777 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
1780 MonoMethod
*inst
, *res
;
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 */
1787 mono_memory_barrier ();
1788 mono_marshal_lock ();
1789 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
1791 g_hash_table_insert (cache
, key
, inst
);
1794 mono_marshal_unlock ();
1799 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
1803 MonoMethod
*inst
, *def
;
1806 * Look for the instance
1808 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
1813 * Look for the definition
1815 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
1817 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1818 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1821 mono_memory_barrier ();
1822 mono_marshal_lock ();
1823 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1825 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1828 mono_marshal_unlock ();
1835 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
1838 MonoMethod
*inst
, *res
;
1839 WrapperInfo
*ginfo
, *info
;
1842 * We use the same cache for the generic definition and the instances.
1844 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, error
);
1845 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
1847 ginfo
= mono_marshal_get_wrapper_info (def
);
1849 info
= (WrapperInfo
*)mono_image_alloc0 (m_class_get_image (def
->klass
), sizeof (WrapperInfo
));
1850 info
->subtype
= ginfo
->subtype
;
1851 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
1852 info
->d
.delegate_invoke
.method
= mono_class_inflate_generic_method_checked (ginfo
->d
.delegate_invoke
.method
, ctx
, error
);
1853 mono_error_assert_ok (error
);
1857 mono_memory_barrier ();
1858 mono_marshal_lock ();
1859 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
1861 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
1864 mono_marshal_unlock ();
1869 emit_delegate_begin_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1874 * mono_marshal_get_delegate_begin_invoke:
1877 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
1879 MonoMethodSignature
*sig
;
1880 MonoMethodBuilder
*mb
;
1884 MonoGenericContext
*ctx
= NULL
;
1885 MonoMethod
*orig_method
= NULL
;
1887 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
1888 !strcmp (method
->name
, "BeginInvoke"));
1891 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
1893 if (method
->is_inflated
) {
1894 orig_method
= method
;
1895 ctx
= &((MonoMethodInflated
*)method
)->context
;
1896 method
= ((MonoMethodInflated
*)method
)->declaring
;
1899 sig
= mono_signature_no_pinvoke (method
);
1905 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1906 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
1910 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_begin_invoke_cache
,
1911 (GHashFunc
)mono_signature_hash
,
1912 (GCompareFunc
)mono_metadata_signature_equal
);
1913 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
1917 g_assert (sig
->hasthis
);
1919 name
= mono_signature_to_name (sig
, "begin_invoke");
1921 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1923 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
1926 get_marshal_cb ()->emit_delegate_begin_invoke (mb
, sig
);
1930 def
= mono_mb_create_and_cache (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16);
1931 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
1933 res
= mono_mb_create_and_cache (cache
, sig
, mb
, sig
, sig
->param_count
+ 16);
1940 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1942 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
1945 MonoDomain
*domain
= mono_domain_get ();
1946 MonoAsyncResult
*ares
;
1947 MonoMethod
*method
= NULL
;
1948 MonoMethodSignature
*sig
;
1949 MonoMethodMessage
*msg
;
1950 MonoObject
*res
, *exc
;
1951 MonoArray
*out_args
;
1954 g_assert (delegate
);
1956 if (!delegate
->method_info
) {
1957 g_assert (delegate
->method
);
1958 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, error
);
1959 if (!mono_error_ok (error
)) {
1960 mono_error_set_pending_exception (error
);
1963 MONO_OBJECT_SETREF (delegate
, method_info
, rm
);
1966 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
1967 g_assert_not_reached ();
1969 klass
= delegate
->object
.vtable
->klass
;
1971 method
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
1972 g_assert (method
!= NULL
);
1974 sig
= mono_signature_no_pinvoke (method
);
1976 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, error
);
1977 if (mono_error_set_pending_exception (error
))
1980 ares
= (MonoAsyncResult
*)mono_array_get (msg
->args
, gpointer
, sig
->param_count
- 1);
1982 mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults
.corlib
, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
1986 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
1987 mono_set_pending_exception (mono_get_exception_invalid_operation (
1988 "The IAsyncResult object provided does not match this delegate."));
1992 #ifndef DISABLE_REMOTING
1993 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1994 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
1995 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, error
);
1996 if (!mono_error_ok (error
)) {
1997 mono_error_set_pending_exception (error
);
2000 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, error
);
2001 if (mono_error_set_pending_exception (error
))
2003 msg
->call_type
= CallType_EndInvoke
;
2004 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
2005 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, error
);
2006 if (!mono_error_ok (error
)) {
2007 mono_error_set_pending_exception (error
);
2013 res
= mono_threadpool_end_invoke (ares
, &out_args
, &exc
, error
);
2014 if (mono_error_set_pending_exception (error
))
2019 if (((MonoException
*)exc
)->stack_trace
) {
2020 ERROR_DECL_VALUE (inner_error
);
2021 char *strace
= mono_string_to_utf8_checked (((MonoException
*)exc
)->stack_trace
, &inner_error
);
2022 if (is_ok (&inner_error
)) {
2024 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
2026 MonoString
*tmp_str
= mono_string_new_checked (domain
, tmp
, &inner_error
);
2028 if (is_ok (&inner_error
))
2029 MONO_OBJECT_SETREF (((MonoException
*)exc
), stack_trace
, tmp_str
);
2031 if (!is_ok (&inner_error
))
2032 mono_error_cleanup (&inner_error
); /* no stack trace, but at least throw the original exception */
2034 mono_set_pending_exception ((MonoException
*)exc
);
2037 mono_method_return_message_restore (method
, params
, out_args
, error
);
2038 mono_error_set_pending_exception (error
);
2043 emit_delegate_end_invoke_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
2048 * mono_marshal_get_delegate_end_invoke:
2051 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
2053 MonoMethodSignature
*sig
;
2054 MonoMethodBuilder
*mb
;
2058 MonoGenericContext
*ctx
= NULL
;
2059 MonoMethod
*orig_method
= NULL
;
2061 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2062 !strcmp (method
->name
, "EndInvoke"));
2065 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
2067 if (method
->is_inflated
) {
2068 orig_method
= method
;
2069 ctx
= &((MonoMethodInflated
*)method
)->context
;
2070 method
= ((MonoMethodInflated
*)method
)->declaring
;
2073 sig
= mono_signature_no_pinvoke (method
);
2079 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2080 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2084 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_end_invoke_cache
,
2085 (GHashFunc
)mono_signature_hash
,
2086 (GCompareFunc
)mono_metadata_signature_equal
);
2087 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2091 g_assert (sig
->hasthis
);
2093 name
= mono_signature_to_name (sig
, "end_invoke");
2095 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2097 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2100 get_marshal_cb ()->emit_delegate_end_invoke (mb
, sig
);
2104 def
= mono_mb_create_and_cache (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16);
2105 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2107 res
= mono_mb_create_and_cache (cache
, sig
,
2108 mb
, sig
, sig
->param_count
+ 16);
2117 MonoMethodSignature
*sig
;
2119 } SignaturePointerPair
;
2122 signature_pointer_pair_hash (gconstpointer data
)
2124 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
2126 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
2130 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
2132 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
2133 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
2137 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
2139 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
2141 return pair
->pointer
== user_data
;
2145 free_signature_pointer_pair (SignaturePointerPair
*pair
)
2151 mb_skip_visibility_noilgen (MonoMethodBuilder
*mb
)
2156 mb_set_dynamic_noilgen (MonoMethodBuilder
*mb
)
2161 mb_emit_exception_noilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
2166 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
)
2171 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
2173 MonoMethodSignature
*sig
, *static_sig
, *invoke_sig
;
2174 MonoMethodBuilder
*mb
;
2177 gpointer cache_key
= NULL
;
2178 SignaturePointerPair key
= { NULL
, NULL
};
2179 SignaturePointerPair
*new_key
;
2181 MonoClass
*target_class
= NULL
;
2182 gboolean closed_over_null
= FALSE
;
2183 MonoGenericContext
*ctx
= NULL
;
2184 MonoGenericContainer
*container
= NULL
;
2185 MonoMethod
*orig_method
= method
;
2187 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
2190 g_assert (method
&& m_class_get_parent (method
->klass
) == mono_defaults
.multicastdelegate_class
&&
2191 !strcmp (method
->name
, "Invoke"));
2193 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2196 * If the delegate target is null, and the target method is not static, a virtual
2197 * call is made to that method with the first delegate argument as this. This is
2198 * a non-documented .NET feature.
2201 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
2202 if (target_method
->is_inflated
) {
2204 MonoType
*target_type
;
2206 g_assert (method
->signature
->hasthis
);
2207 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
2208 mono_method_get_context (method
), error
);
2209 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
2210 target_class
= mono_class_from_mono_type (target_type
);
2212 target_class
= target_method
->klass
;
2215 closed_over_null
= sig
->param_count
== mono_method_signature (target_method
)->param_count
;
2218 if (static_method_with_first_arg_bound
) {
2219 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
2220 g_assert (!callvirt
);
2221 invoke_sig
= mono_method_signature (target_method
);
2225 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
2227 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
2228 ctx
= &((MonoMethodInflated
*)method
)->context
;
2229 method
= ((MonoMethodInflated
*)method
)->declaring
;
2231 container
= mono_method_get_generic_container (method
);
2233 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
2234 g_assert (container
);
2236 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
2243 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2244 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2247 cache_key
= method
->klass
;
2248 } else if (static_method_with_first_arg_bound
) {
2249 cache
= get_cache (&get_method_image (method
)->delegate_bound_static_invoke_cache
,
2250 (GHashFunc
)mono_signature_hash
,
2251 (GCompareFunc
)mono_metadata_signature_equal
);
2253 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
2255 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
2258 cache_key
= invoke_sig
;
2259 } else if (callvirt
) {
2260 GHashTable
**cache_ptr
;
2262 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
2264 /* We need to cache the signature+method pair */
2265 mono_marshal_lock ();
2267 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
2269 key
.sig
= invoke_sig
;
2270 key
.pointer
= target_method
;
2271 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
2272 mono_marshal_unlock ();
2276 // Inflated methods should not be in this cache because it's not stored on the imageset.
2277 g_assert (!method
->is_inflated
);
2278 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.delegate_invoke_cache
,
2279 (GHashFunc
)mono_signature_hash
,
2280 (GCompareFunc
)mono_metadata_signature_equal
);
2281 res
= mono_marshal_find_in_cache (cache
, sig
);
2287 static_sig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
2288 static_sig
->hasthis
= 0;
2289 if (!static_method_with_first_arg_bound
)
2290 invoke_sig
= static_sig
;
2292 if (static_method_with_first_arg_bound
)
2293 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
2294 else if (closed_over_null
)
2295 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
2297 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
2299 name
= mono_signature_to_name (invoke_sig
, "invoke");
2301 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2303 mb
= mono_mb_new (get_wrapper_target_class (get_method_image (method
)), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
2306 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
);
2308 get_marshal_cb ()->mb_skip_visibility (mb
);
2310 info
= mono_wrapper_info_create (mb
, subtype
);
2311 info
->d
.delegate_invoke
.method
= method
;
2316 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2317 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2318 } else if (callvirt
) {
2319 new_key
= g_new0 (SignaturePointerPair
, 1);
2322 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
2326 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
2330 /* mono_method_print_code (res); */
2336 * mono_marshal_get_delegate_invoke:
2337 * The returned method invokes all methods in a multicast delegate.
2340 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
2342 gboolean callvirt
= FALSE
;
2343 gboolean static_method_with_first_arg_bound
= FALSE
;
2344 MonoMethod
*target_method
= NULL
;
2345 MonoMethodSignature
*sig
;
2347 sig
= mono_signature_no_pinvoke (method
);
2349 if (del
&& !del
->target
&& del
->method
&& mono_method_signature (del
->method
)->hasthis
) {
2351 target_method
= del
->method
;
2354 if (del
&& del
->method
&& mono_method_signature (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2355 static_method_with_first_arg_bound
= TRUE
;
2356 target_method
= del
->method
;
2359 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
2363 MonoMethodSignature
*ctor_sig
;
2364 MonoMethodSignature
*sig
;
2367 /* protected by the marshal lock, contains CtorSigPair pointers */
2368 static GSList
*strsig_list
= NULL
;
2370 static MonoMethodSignature
*
2371 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
2373 MonoMethodSignature
*callsig
;
2377 mono_marshal_lock ();
2379 for (item
= strsig_list
; item
; item
= item
->next
) {
2380 cs
= (CtorSigPair
*)item
->data
;
2381 /* mono_metadata_signature_equal () is safe to call with the marshal lock
2382 * because it is lock-free.
2384 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
2389 mono_marshal_unlock ();
2393 static MonoMethodSignature
*
2394 add_string_ctor_signature (MonoMethod
*method
)
2396 MonoMethodSignature
*callsig
;
2399 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature (method
));
2400 callsig
->ret
= m_class_get_byval_arg (mono_defaults
.string_class
);
2401 cs
= g_new (CtorSigPair
, 1);
2403 cs
->ctor_sig
= mono_method_signature (method
);
2405 mono_marshal_lock ();
2406 strsig_list
= g_slist_prepend (strsig_list
, cs
);
2407 mono_marshal_unlock ();
2412 * mono_marshal_get_string_ctor_signature:
2414 * Return the modified signature used by string ctors (they return the newly created
2417 MonoMethodSignature
*
2418 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
2420 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature (method
));
2422 sig
= add_string_ctor_signature (method
);
2428 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
2431 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
2433 /* Can't share this with 'I' as that needs another indirection */
2434 return m_class_get_this_arg (mono_defaults
.int_class
);
2437 if (MONO_TYPE_IS_REFERENCE (t
))
2438 return m_class_get_byval_arg (mono_defaults
.object_class
);
2441 /* The result needs to be boxed */
2446 /* Can't share these as the argument needs to be loaded using sign/zero extension */
2449 return &mono_defaults.sbyte_class->byval_arg;
2451 return &mono_defaults.int16_class->byval_arg;
2453 return &mono_defaults.int32_class->byval_arg;
2456 return m_class_get_byval_arg (mono_defaults
.int64_class
);
2457 case MONO_TYPE_BOOLEAN
:
2458 return m_class_get_byval_arg (mono_defaults
.byte_class
);
2459 case MONO_TYPE_CHAR
:
2460 return m_class_get_byval_arg (mono_defaults
.uint16_class
);
2462 return m_class_get_byval_arg (mono_defaults
.int_class
);
2463 case MONO_TYPE_VALUETYPE
:
2464 if (m_class_is_enumtype (t
->data
.klass
)) {
2465 t
= mono_class_enum_basetype (t
->data
.klass
);
2475 * mono_marshal_get_runtime_invoke_sig:
2477 * Return a common signature used for sharing runtime invoke wrappers.
2479 static MonoMethodSignature
*
2480 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
2482 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
2485 res
->generic_param_count
= 0;
2486 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
2487 for (i
= 0; i
< res
->param_count
; ++i
)
2488 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
2494 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
2496 /* Can't share wrappers which return a vtype since it needs to be boxed */
2497 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
))
2500 return mono_metadata_signature_equal (sig1
, sig2
);
2505 * mono_marshal_get_runtime_invoke:
2506 * Generates IL code for the runtime invoke function:
2508 * <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
2510 * We also catch exceptions if \p exc is not NULL.
2511 * If \p virtual is TRUE, then \p method is invoked virtually on \p this. This is useful since
2512 * it means that the compiled code for \p method does not have to be looked up
2513 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
2514 * its \p method argument.
2517 mono_marshal_get_runtime_invoke_full (MonoMethod
*method
, gboolean virtual_
, gboolean need_direct_wrapper
)
2519 MonoMethodSignature
*sig
, *csig
, *callsig
;
2520 MonoMethodBuilder
*mb
;
2521 GHashTable
*cache
= NULL
;
2522 MonoClass
*target_klass
;
2523 MonoMethod
*res
= NULL
;
2524 static MonoMethodSignature
*cctor_signature
= NULL
;
2525 static MonoMethodSignature
*finalize_signature
= NULL
;
2527 const char *param_names
[16];
2532 if (!cctor_signature
) {
2533 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2534 cctor_signature
->ret
= m_class_get_byval_arg (mono_defaults
.void_class
);
2536 if (!finalize_signature
) {
2537 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
2538 finalize_signature
->ret
= m_class_get_byval_arg (mono_defaults
.void_class
);
2539 finalize_signature
->hasthis
= 1;
2543 * Use a separate cache indexed by methods to speed things up and to avoid the
2544 * boundless mempool growth caused by the signature_dup stuff below.
2547 cache
= get_cache (&get_method_image (method
)->runtime_invoke_vcall_cache
, mono_aligned_addr_hash
, NULL
);
2549 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->runtime_invoke_direct_cache
, mono_aligned_addr_hash
, NULL
);
2551 res
= mono_marshal_find_in_cache (cache
, method
);
2555 if (method
->string_ctor
) {
2556 callsig
= lookup_string_ctor_signature (mono_method_signature (method
));
2558 callsig
= add_string_ctor_signature (method
);
2560 if (method_is_dynamic (method
))
2561 callsig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature (method
));
2563 callsig
= mono_method_signature (method
);
2566 sig
= mono_method_signature (method
);
2568 target_klass
= get_wrapper_target_class (m_class_get_image (method
->klass
));
2570 /* Try to share wrappers for non-corlib methods with simple signatures */
2571 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
2572 callsig
= cctor_signature
;
2573 target_klass
= mono_defaults
.object_class
;
2574 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
2575 callsig
= finalize_signature
;
2576 target_klass
= mono_defaults
.object_class
;
2579 if (need_direct_wrapper
) {
2580 /* Already searched at the start */
2582 MonoMethodSignature
*tmp_sig
;
2584 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
2585 GHashTable
**cache_table
= NULL
;
2587 if (m_class_is_valuetype (method
->klass
) && mono_method_signature (method
)->hasthis
)
2588 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_vtype_cache
;
2590 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_cache
;
2592 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
2593 (GCompareFunc
)runtime_invoke_signature_equal
);
2595 /* from mono_marshal_find_in_cache */
2596 mono_marshal_lock ();
2597 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2598 mono_marshal_unlock ();
2605 /* Make a copy of the signature from the image mempool */
2607 callsig
= mono_metadata_signature_dup_full (m_class_get_image (target_klass
), callsig
);
2611 csig
= mono_metadata_signature_alloc (m_class_get_image (target_klass
), 4);
2613 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
2614 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2616 csig
->ret
= object_type
;
2617 if (m_class_is_valuetype (method
->klass
) && mono_method_signature (method
)->hasthis
)
2618 csig
->params
[0] = get_runtime_invoke_type (m_class_get_this_arg (method
->klass
), FALSE
);
2620 csig
->params
[0] = object_type
;
2621 csig
->params
[1] = int_type
;
2622 csig
->params
[2] = int_type
;
2623 csig
->params
[3] = int_type
;
2626 /* This is called from runtime code so it has to be cdecl */
2627 csig
->call_convention
= MONO_CALL_C
;
2630 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : (need_direct_wrapper
? "runtime_invoke_direct" : "runtime_invoke"));
2631 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2634 param_names
[0] = "this";
2635 param_names
[1] = "params";
2636 param_names
[2] = "exc";
2637 param_names
[3] = "method";
2639 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, m_class_get_image (target_klass
), method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
2641 if (need_direct_wrapper
) {
2642 get_marshal_cb ()->mb_skip_visibility (mb
);
2643 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
2644 info
->d
.runtime_invoke
.method
= method
;
2645 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
2647 /* taken from mono_mb_create_and_cache */
2648 mono_marshal_lock ();
2649 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2650 mono_marshal_unlock ();
2652 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2653 info
->d
.runtime_invoke
.sig
= callsig
;
2655 /* Somebody may have created it before us */
2658 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2660 mono_marshal_lock ();
2661 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2663 GHashTable
*direct_cache
;
2665 g_hash_table_insert (cache
, callsig
, res
);
2666 /* Can't insert it into wrapper_hash since the key is a signature */
2667 direct_cache
= mono_method_get_wrapper_cache (method
)->runtime_invoke_direct_cache
;
2669 g_hash_table_insert (direct_cache
, method
, res
);
2671 mono_free_method (newm
);
2673 mono_marshal_unlock ();
2676 /* end mono_mb_create_and_cache */
2685 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
2687 gboolean need_direct_wrapper
= FALSE
;
2690 need_direct_wrapper
= TRUE
;
2692 if (method
->dynamic
)
2693 need_direct_wrapper
= TRUE
;
2695 if (m_class_get_rank (method
->klass
) && (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
2696 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
2698 * Array Get/Set/Address methods. The JIT implements them using inline code
2699 * so we need to create an invoke wrapper which calls the method directly.
2701 need_direct_wrapper
= TRUE
;
2704 if (method
->string_ctor
) {
2705 /* Can't share this as we push a string as this */
2706 need_direct_wrapper
= TRUE
;
2709 return mono_marshal_get_runtime_invoke_full (method
, virtual_
, need_direct_wrapper
);
2713 emit_runtime_invoke_body_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
2714 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
2715 gboolean virtual_
, gboolean need_direct_wrapper
)
2720 emit_runtime_invoke_dynamic_noilgen (MonoMethodBuilder
*mb
)
2725 * mono_marshal_get_runtime_invoke_dynamic:
2727 * Return a method which can be used to invoke managed methods from native code
2729 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
2730 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
2731 * ARGS should point to an architecture specific structure containing
2732 * the arguments and space for the return value.
2733 * The other arguments are the same as for runtime_invoke (), except that
2734 * ARGS should contain the this argument too.
2735 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
2736 * is only one copy of it, which is useful in full-aot.
2739 mono_marshal_get_runtime_invoke_dynamic (void)
2741 static MonoMethod
*method
;
2742 MonoMethodSignature
*csig
;
2743 MonoMethodBuilder
*mb
;
2750 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
2752 MonoType
*void_type
= m_class_get_byval_arg (mono_defaults
.void_class
);
2753 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2755 csig
->ret
= void_type
;
2756 csig
->params
[0] = int_type
;
2757 csig
->params
[1] = int_type
;
2758 csig
->params
[2] = int_type
;
2759 csig
->params
[3] = int_type
;
2761 name
= g_strdup ("runtime_invoke_dynamic");
2762 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2765 get_marshal_cb ()->emit_runtime_invoke_dynamic (mb
);
2767 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
2769 mono_marshal_lock ();
2770 /* double-checked locking */
2772 method
= mono_mb_create (mb
, csig
, 16, info
);
2774 mono_marshal_unlock ();
2782 * mono_marshal_get_runtime_invoke_for_sig:
2784 * Return a runtime invoke wrapper for a given signature.
2787 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
2789 MonoMethodSignature
*csig
, *callsig
;
2790 MonoMethodBuilder
*mb
;
2792 GHashTable
*cache
= NULL
;
2793 GHashTable
**cache_table
= NULL
;
2794 MonoMethod
*res
= NULL
;
2796 const char *param_names
[16];
2799 /* A simplified version of mono_marshal_get_runtime_invoke */
2801 image
= mono_defaults
.corlib
;
2803 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
2805 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
2807 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
2808 (GCompareFunc
)runtime_invoke_signature_equal
);
2810 /* from mono_marshal_find_in_cache */
2811 mono_marshal_lock ();
2812 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2813 mono_marshal_unlock ();
2820 /* Make a copy of the signature from the image mempool */
2821 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
2823 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
2824 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2825 csig
= mono_metadata_signature_alloc (image
, 4);
2826 csig
->ret
= object_type
;
2827 csig
->params
[0] = object_type
;
2828 csig
->params
[1] = int_type
;
2829 csig
->params
[2] = int_type
;
2830 csig
->params
[3] = int_type
;
2833 /* This is called from runtime code so it has to be cdecl */
2834 csig
->call_convention
= MONO_CALL_C
;
2837 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
2838 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
2841 param_names
[0] = "this";
2842 param_names
[1] = "params";
2843 param_names
[2] = "exc";
2844 param_names
[3] = "method";
2846 get_marshal_cb ()->emit_runtime_invoke_body (mb
, param_names
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
2848 /* taken from mono_mb_create_and_cache */
2849 mono_marshal_lock ();
2850 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2851 mono_marshal_unlock ();
2853 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
2854 info
->d
.runtime_invoke
.sig
= callsig
;
2856 /* Somebody may have created it before us */
2859 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
2861 mono_marshal_lock ();
2862 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
2865 g_hash_table_insert (cache
, callsig
, res
);
2867 mono_free_method (newm
);
2869 mono_marshal_unlock ();
2872 /* end mono_mb_create_and_cache */
2880 emit_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gconstpointer func
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
2885 * mono_marshal_get_icall_wrapper:
2886 * Generates IL code for the icall wrapper. The generated method
2887 * calls the unmanaged code in \p func.
2890 mono_marshal_get_icall_wrapper (MonoMethodSignature
*sig
, const char *name
, gconstpointer func
, gboolean check_exceptions
)
2892 MonoMethodSignature
*csig
, *csig2
;
2893 MonoMethodBuilder
*mb
;
2897 GHashTable
*cache
= get_cache (& m_class_get_image (mono_defaults
.object_class
)->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
2898 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
2901 g_assert (sig
->pinvoke
);
2903 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
2905 mb
->method
->save_lmf
= 1;
2907 /* Add an explicit this argument */
2909 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
2911 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2913 get_marshal_cb ()->emit_icall_wrapper (mb
, sig
, func
, csig2
, check_exceptions
);
2915 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
2917 if (csig
->call_convention
== MONO_CALL_VARARG
)
2918 csig
->call_convention
= 0;
2920 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
2921 info
->d
.icall
.func
= (gpointer
)func
;
2922 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
2929 emit_marshal_custom_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2930 MonoMarshalSpec
*spec
,
2931 int conv_arg
, MonoType
**conv_arg_type
,
2932 MarshalAction action
)
2934 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2935 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
2936 *conv_arg_type
= int_type
;
2941 emit_marshal_asany_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2942 MonoMarshalSpec
*spec
,
2943 int conv_arg
, MonoType
**conv_arg_type
,
2944 MarshalAction action
)
2950 emit_marshal_vtype_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2951 MonoMarshalSpec
*spec
,
2952 int conv_arg
, MonoType
**conv_arg_type
,
2953 MarshalAction action
)
2959 emit_marshal_string_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2960 MonoMarshalSpec
*spec
,
2961 int conv_arg
, MonoType
**conv_arg_type
,
2962 MarshalAction action
)
2964 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2966 case MARSHAL_ACTION_CONV_IN
:
2967 *conv_arg_type
= int_type
;
2969 case MARSHAL_ACTION_MANAGED_CONV_IN
:
2970 *conv_arg_type
= int_type
;
2978 emit_marshal_safehandle_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2979 MonoMarshalSpec
*spec
, int conv_arg
,
2980 MonoType
**conv_arg_type
, MarshalAction action
)
2982 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2983 if (action
== MARSHAL_ACTION_CONV_IN
)
2984 *conv_arg_type
= int_type
;
2990 emit_marshal_handleref_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2991 MonoMarshalSpec
*spec
, int conv_arg
,
2992 MonoType
**conv_arg_type
, MarshalAction action
)
2994 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
2995 if (action
== MARSHAL_ACTION_CONV_IN
)
2996 *conv_arg_type
= int_type
;
3002 emit_marshal_object_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3003 MonoMarshalSpec
*spec
,
3004 int conv_arg
, MonoType
**conv_arg_type
,
3005 MarshalAction action
)
3007 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
3008 if (action
== MARSHAL_ACTION_CONV_IN
)
3009 *conv_arg_type
= int_type
;
3014 emit_marshal_variant_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3015 MonoMarshalSpec
*spec
,
3016 int conv_arg
, MonoType
**conv_arg_type
,
3017 MarshalAction action
)
3019 g_assert_not_reached ();
3023 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
3025 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
3026 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
3028 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
3030 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
3041 emit_marshal_array_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3042 MonoMarshalSpec
*spec
,
3043 int conv_arg
, MonoType
**conv_arg_type
,
3044 MarshalAction action
)
3046 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
3047 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
3049 case MARSHAL_ACTION_CONV_IN
:
3050 *conv_arg_type
= object_type
;
3052 case MARSHAL_ACTION_MANAGED_CONV_IN
:
3053 *conv_arg_type
= int_type
;
3060 mono_marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
3063 return m_class_get_byval_arg (mono_defaults
.int32_class
);
3065 switch (spec
->native
) {
3066 case MONO_NATIVE_I1
:
3067 case MONO_NATIVE_U1
:
3068 return m_class_get_byval_arg (mono_defaults
.byte_class
);
3069 case MONO_NATIVE_VARIANTBOOL
:
3070 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
3071 return m_class_get_byval_arg (mono_defaults
.int16_class
);
3072 case MONO_NATIVE_BOOLEAN
:
3073 return m_class_get_byval_arg (mono_defaults
.int32_class
);
3075 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3076 return m_class_get_byval_arg (mono_defaults
.int32_class
);
3082 mono_marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
3084 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3086 switch (spec
->native
) {
3087 case MONO_NATIVE_I1
:
3088 case MONO_NATIVE_U1
:
3089 conv_arg_class
= mono_defaults
.byte_class
;
3090 if (ldop
) *ldop
= CEE_LDIND_I1
;
3092 case MONO_NATIVE_VARIANTBOOL
:
3093 conv_arg_class
= mono_defaults
.int16_class
;
3094 if (ldop
) *ldop
= CEE_LDIND_I2
;
3096 case MONO_NATIVE_BOOLEAN
:
3099 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
3102 return conv_arg_class
;
3106 emit_marshal_boolean_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3107 MonoMarshalSpec
*spec
,
3108 int conv_arg
, MonoType
**conv_arg_type
,
3109 MarshalAction action
)
3111 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
3113 case MARSHAL_ACTION_CONV_IN
:
3115 *conv_arg_type
= int_type
;
3117 *conv_arg_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, NULL
);
3120 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3121 MonoClass
* conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
3123 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3125 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3134 emit_marshal_ptr_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3135 MonoMarshalSpec
*spec
, int conv_arg
,
3136 MonoType
**conv_arg_type
, MarshalAction action
)
3142 emit_marshal_char_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3143 MonoMarshalSpec
*spec
, int conv_arg
,
3144 MonoType
**conv_arg_type
, MarshalAction action
)
3150 emit_marshal_scalar_noilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3151 MonoMarshalSpec
*spec
, int conv_arg
,
3152 MonoType
**conv_arg_type
, MarshalAction action
)
3158 mono_emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3159 MonoMarshalSpec
*spec
, int conv_arg
,
3160 MonoType
**conv_arg_type
, MarshalAction action
)
3162 /* Ensure that we have marshalling info for this param */
3163 mono_marshal_load_type_info (mono_class_from_mono_type (t
));
3165 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
3166 return get_marshal_cb ()->emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3168 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
3169 return get_marshal_cb ()->emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3172 case MONO_TYPE_VALUETYPE
:
3173 if (t
->data
.klass
== mono_defaults
.handleref_class
)
3174 return get_marshal_cb ()->emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3176 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3177 case MONO_TYPE_STRING
:
3178 return get_marshal_cb ()->emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3179 case MONO_TYPE_CLASS
:
3180 case MONO_TYPE_OBJECT
:
3181 #if !defined(DISABLE_COM)
3182 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
3183 return get_marshal_cb ()->emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3186 #if !defined(DISABLE_COM)
3187 if (spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
3188 spec
->native
== MONO_NATIVE_IDISPATCH
||
3189 spec
->native
== MONO_NATIVE_INTERFACE
))
3190 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3191 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
3192 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
3193 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
3194 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3197 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
3198 mono_class_is_subclass_of (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
3199 return get_marshal_cb ()->emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3201 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3202 case MONO_TYPE_ARRAY
:
3203 case MONO_TYPE_SZARRAY
:
3204 return get_marshal_cb ()->emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3205 case MONO_TYPE_BOOLEAN
:
3206 return get_marshal_cb ()->emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3208 return get_marshal_cb ()->emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3209 case MONO_TYPE_CHAR
:
3210 return get_marshal_cb ()->emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3223 case MONO_TYPE_FNPTR
:
3224 return get_marshal_cb ()->emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3225 case MONO_TYPE_GENERICINST
:
3226 if (mono_type_generic_inst_is_valuetype (t
))
3227 return get_marshal_cb ()->emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3229 return get_marshal_cb ()->emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
3236 emit_create_string_hack_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
3241 emit_native_icall_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*pinfo
)
3246 * mono_marshal_get_native_wrapper:
3247 * \param method The \c MonoMethod to wrap.
3248 * \param check_exceptions Whenever to check for pending exceptions
3250 * Generates IL code for the pinvoke wrapper. The generated method
3251 * calls the unmanaged code in \c piinfo->addr.
3254 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
3256 MonoMethodSignature
*sig
, *csig
;
3257 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
3258 MonoMethodBuilder
*mb
;
3259 MonoMarshalSpec
**mspecs
;
3262 gboolean pinvoke
= FALSE
;
3265 const char *exc_class
= "MissingMethodException";
3266 const char *exc_arg
= NULL
;
3269 g_assert (method
!= NULL
);
3270 g_assert (mono_method_signature (method
)->pinvoke
);
3272 GHashTable
**cache_ptr
;
3274 MonoType
*string_type
= m_class_get_byval_arg (mono_defaults
.string_class
);
3277 if (check_exceptions
)
3278 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
3280 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
3282 if (check_exceptions
)
3283 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
3285 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
3288 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
3290 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3293 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
3294 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
3298 return mono_cominterop_get_native_wrapper (method
);
3300 g_assert_not_reached ();
3304 sig
= mono_method_signature (method
);
3306 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
3307 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
3310 if (!piinfo
->addr
) {
3312 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
3313 exc_arg
= "Method contains unsupported native code";
3315 mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
3317 piinfo
->addr
= mono_lookup_internal_call (method
);
3321 /* hack - redirect certain string constructors to CreateString */
3322 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
3323 g_assert (!pinvoke
);
3324 g_assert (method
->string_ctor
);
3325 g_assert (sig
->hasthis
);
3327 /* CreateString returns a value */
3328 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3329 csig
->ret
= string_type
;
3333 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
3334 if (!strcmp ("CreateString", res
->name
) &&
3335 mono_metadata_signature_equal (csig
, mono_method_signature (res
))) {
3338 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
3339 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
3341 /* create a wrapper to preserve .ctor in stack trace */
3342 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
3344 get_marshal_cb ()->emit_create_string_hack (mb
, csig
, res
);
3346 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
3347 info
->d
.string_ctor
.method
= method
;
3349 /* use native_wrapper_cache because internal calls are looked up there */
3350 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3351 csig
->param_count
+ 1, info
, NULL
);
3358 /* exception will be thrown */
3359 piinfo
->addr
= NULL
;
3360 g_warning ("cannot find CreateString for .ctor");
3363 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3365 mb
->method
->save_lmf
= 1;
3368 * In AOT mode and embedding scenarios, it is possible that the icall is not
3369 * registered in the runtime doing the AOT compilation.
3371 if (!piinfo
->addr
&& !aot
) {
3372 get_marshal_cb ()->mb_emit_exception (mb
, "System", exc_class
, exc_arg
);
3373 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3374 info
->d
.managed_to_native
.method
= method
;
3376 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3378 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
3379 csig
->param_count
+ 16, info
, NULL
);
3385 /* internal calls: we simply push all arguments and call the method (no conversions) */
3386 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
3388 csig
= mono_metadata_signature_dup_add_this (get_method_image (method
), sig
, method
->klass
);
3390 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3392 //printf ("%s\n", mono_method_full_name (method, 1));
3394 /* hack - string constructors returns a value */
3395 if (method
->string_ctor
)
3396 csig
->ret
= string_type
;
3398 get_marshal_cb ()->emit_native_icall_wrapper (mb
, method
, csig
, check_exceptions
, aot
, piinfo
);
3400 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3401 info
->d
.managed_to_native
.method
= method
;
3403 csig
= mono_metadata_signature_dup_full (get_method_image (method
), csig
);
3405 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3414 g_assert (piinfo
->addr
);
3416 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
3417 mono_method_get_marshal_info (method
, mspecs
);
3419 mono_marshal_emit_native_wrapper (get_method_image (mb
->method
), mb
, sig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
);
3420 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
3421 info
->d
.managed_to_native
.method
= method
;
3423 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
3425 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
3429 for (i
= sig
->param_count
; i
>= 0; i
--)
3431 mono_metadata_free_marshal_spec (mspecs
[i
]);
3434 /* mono_method_print_code (res); */
3440 * mono_marshal_get_native_func_wrapper:
3441 * \param image The image to use for memory allocation and for looking up custom marshallers.
3442 * \param sig The signature of the function
3443 * \param func The native function to wrap
3445 * \returns a wrapper method around native functions, similar to the pinvoke
3449 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
3450 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
3452 MonoMethodSignature
*csig
;
3454 SignaturePointerPair key
, *new_key
;
3455 MonoMethodBuilder
*mb
;
3464 // Generic types are not safe to place in MonoImage caches.
3465 g_assert (!sig
->is_inflated
);
3467 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
3468 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
3471 name
= g_strdup_printf ("wrapper_native_%p", func
);
3472 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3473 mb
->method
->save_lmf
= 1;
3475 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
);
3477 csig
= mono_metadata_signature_dup_full (image
, sig
);
3480 new_key
= g_new (SignaturePointerPair
,1);
3481 new_key
->sig
= csig
;
3482 new_key
->pointer
= func
;
3484 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
3490 mono_marshal_set_wrapper_info (res
, NULL
);
3496 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
3500 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
3502 MonoMethodSignature
*sig
, *csig
;
3503 MonoMethodBuilder
*mb
;
3508 MonoMethodPInvoke mpiinfo
;
3509 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
3510 MonoMarshalSpec
**mspecs
;
3511 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
3512 MonoImage
*image
= get_method_image (invoke
);
3515 // FIXME: include UnmanagedFunctionPointerAttribute info
3518 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
3520 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
3522 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
3525 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
3526 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
3528 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
3529 mono_method_get_marshal_info (invoke
, mspecs
);
3530 /* Freed below so don't alloc from mempool */
3531 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
3534 name
= g_strdup_printf ("wrapper_aot_native");
3535 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3536 mb
->method
->save_lmf
= 1;
3538 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
);
3540 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
3541 info
->d
.managed_to_native
.method
= invoke
;
3543 g_assert (!sig
->hasthis
);
3544 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
3546 res
= mono_mb_create_and_cache_full (cache
, invoke
,
3547 mb
, csig
, csig
->param_count
+ 16,
3551 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
3553 mono_metadata_free_marshal_spec (mspecs
[i
]);
3561 * mono_marshal_emit_managed_wrapper:
3563 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
3564 * the delegate which wraps the managed method to be called. For closed delegates,
3565 * it could have fewer parameters than the method it wraps.
3566 * THIS_LOC is the memory location where the target of the delegate is stored.
3569 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3571 get_marshal_cb ()->emit_managed_wrapper (mb
, invoke_sig
, mspecs
, m
, method
, target_handle
);
3575 emit_managed_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
3577 MonoMethodSignature
*sig
, *csig
;
3579 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
3584 /* we first do all conversions */
3585 for (i
= 0; i
< sig
->param_count
; i
++) {
3586 MonoType
*t
= sig
->params
[i
];
3589 case MONO_TYPE_OBJECT
:
3590 case MONO_TYPE_CLASS
:
3591 case MONO_TYPE_VALUETYPE
:
3592 case MONO_TYPE_ARRAY
:
3593 case MONO_TYPE_SZARRAY
:
3594 case MONO_TYPE_STRING
:
3595 case MONO_TYPE_BOOLEAN
:
3596 mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
3600 if (!sig
->ret
->byref
) {
3601 switch (sig
->ret
->type
) {
3602 case MONO_TYPE_STRING
:
3603 csig
->ret
= int_type
;
3612 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
)
3614 MonoMethodSignature
*sig
;
3619 * Under windows, delegates passed to native code must use the STDCALL
3620 * calling convention.
3622 csig
->call_convention
= MONO_CALL_STDCALL
;
3625 sig
= mono_method_signature (method
);
3627 /* Change default calling convention if needed */
3628 /* Why is this a modopt ? */
3629 if (sig
->ret
&& sig
->ret
->num_mods
) {
3630 for (i
= 0; i
< sig
->ret
->num_mods
; ++i
) {
3632 MonoClass
*cmod_class
= mono_class_get_checked (get_method_image (method
), sig
->ret
->modifiers
[i
].token
, error
);
3633 g_assert (mono_error_ok (error
));
3634 if ((m_class_get_image (cmod_class
) == mono_defaults
.corlib
) && !strcmp (m_class_get_name_space (cmod_class
), "System.Runtime.CompilerServices")) {
3635 const char *cmod_class_name
= m_class_get_name (cmod_class
);
3636 if (!strcmp (cmod_class_name
, "CallConvCdecl"))
3637 csig
->call_convention
= MONO_CALL_C
;
3638 else if (!strcmp (cmod_class_name
, "CallConvStdcall"))
3639 csig
->call_convention
= MONO_CALL_STDCALL
;
3640 else if (!strcmp (cmod_class_name
, "CallConvFastcall"))
3641 csig
->call_convention
= MONO_CALL_FASTCALL
;
3642 else if (!strcmp (cmod_class_name
, "CallConvThiscall"))
3643 csig
->call_convention
= MONO_CALL_THISCALL
;
3650 * mono_marshal_get_managed_wrapper:
3651 * Generates IL code to call managed methods from unmanaged code
3652 * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
3655 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
, MonoError
*error
)
3657 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
3658 MonoMethodBuilder
*mb
;
3659 MonoMethod
*res
, *invoke
;
3660 MonoMarshalSpec
**mspecs
;
3661 MonoMethodPInvoke piinfo
;
3664 EmitMarshalContext m
;
3666 g_assert (method
!= NULL
);
3669 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
3670 mono_error_set_invalid_program (error
, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method
, TRUE
));
3675 * FIXME: Should cache the method+delegate type pair, since the same method
3676 * could be called with different delegates, thus different marshalling
3679 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
3681 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
3684 invoke
= mono_get_delegate_invoke (delegate_klass
);
3685 invoke_sig
= mono_method_signature (invoke
);
3687 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
3688 mono_method_get_marshal_info (invoke
, mspecs
);
3690 sig
= mono_method_signature (method
);
3692 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3694 /*the target gchandle must be the first entry after size and the wrapper itself.*/
3695 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
3697 /* we copy the signature, so that we can modify it */
3699 /* Need to free this later */
3700 csig
= mono_metadata_signature_dup (invoke_sig
);
3702 csig
= mono_metadata_signature_dup_full (get_method_image (method
), invoke_sig
);
3706 memset (&m
, 0, sizeof (m
));
3712 m
.image
= get_method_image (method
);
3714 mono_marshal_set_callconv_from_modopt (invoke
, csig
);
3716 /* The attribute is only available in Net 2.0 */
3717 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
3718 MonoCustomAttrInfo
*cinfo
;
3719 MonoCustomAttrEntry
*attr
;
3722 * The pinvoke attributes are stored in a real custom attribute. Obtain the
3723 * contents of the attribute without constructing it, as that might not be
3724 * possible when running in cross-compiling mode.
3726 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, error
);
3727 mono_error_assert_ok (error
);
3730 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3731 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3732 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
3733 attr
= &cinfo
->attrs
[i
];
3739 MonoArray
*typed_args
, *named_args
;
3740 CattrNamedArg
*arginfo
;
3744 MonoBoolean set_last_error
= 0;
3747 mono_reflection_create_custom_attr_data_args (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
, error
);
3748 g_assert (mono_error_ok (error
));
3749 g_assert (mono_array_length (typed_args
) == 1);
3752 o
= mono_array_get (typed_args
, MonoObject
*, 0);
3753 call_conv
= *(gint32
*)mono_object_unbox (o
);
3756 for (i
= 0; i
< mono_array_length (named_args
); ++i
) {
3757 CattrNamedArg
*narg
= &arginfo
[i
];
3759 o
= mono_array_get (named_args
, MonoObject
*, i
);
3761 g_assert (narg
->field
);
3762 if (!strcmp (narg
->field
->name
, "CharSet")) {
3763 charset
= *(gint32
*)mono_object_unbox (o
);
3764 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
3765 set_last_error
= *(MonoBoolean
*)mono_object_unbox (o
);
3766 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
3767 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox (o);
3768 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
3769 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox (o);
3771 g_assert_not_reached ();
3777 memset (&piinfo
, 0, sizeof (piinfo
));
3779 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
3781 csig
->call_convention
= call_conv
- 1;
3784 if (cinfo
&& !cinfo
->cached
)
3785 mono_custom_attrs_free (cinfo
);
3788 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
3790 if (!target_handle
) {
3793 // FIXME: Associate it with the method+delegate_klass pair
3794 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
3795 info
->d
.native_to_managed
.method
= method
;
3796 info
->d
.native_to_managed
.klass
= delegate_klass
;
3798 res
= mono_mb_create_and_cache_full (cache
, method
,
3799 mb
, csig
, sig
->param_count
+ 16,
3802 get_marshal_cb ()->mb_set_dynamic (mb
);
3803 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
3807 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
3809 mono_metadata_free_marshal_spec (mspecs
[i
]);
3812 /* mono_method_print_code (res); */
3818 emit_vtfixup_ftnptr_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
3823 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
3827 MonoMethodSignature
*sig
;
3828 MonoMethodBuilder
*mb
;
3833 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, error
);
3835 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (error
));
3838 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
3839 MonoMethodSignature
*csig
;
3840 MonoMarshalSpec
**mspecs
;
3841 EmitMarshalContext m
;
3843 sig
= mono_method_signature (method
);
3844 g_assert (!sig
->hasthis
);
3846 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
3847 mono_method_get_marshal_info (method
, mspecs
);
3849 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
3850 csig
= mono_metadata_signature_dup_full (image
, sig
);
3854 memset (&m
, 0, sizeof (m
));
3862 mono_marshal_set_callconv_from_modopt (method
, csig
);
3864 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
3866 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
3868 get_marshal_cb ()->mb_set_dynamic (mb
);
3869 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
3872 for (i
= sig
->param_count
; i
>= 0; i
--)
3874 mono_metadata_free_marshal_spec (mspecs
[i
]);
3877 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
3878 mono_error_assert_ok (error
);
3879 return compiled_ptr
;
3882 sig
= mono_method_signature (method
);
3883 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
3885 param_count
= sig
->param_count
+ sig
->hasthis
;
3886 get_marshal_cb ()->emit_vtfixup_ftnptr (mb
, method
, param_count
, type
);
3887 get_marshal_cb ()->mb_set_dynamic (mb
);
3889 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
3892 gpointer compiled_ptr
= mono_compile_method_checked (method
, error
);
3893 mono_error_assert_ok (error
);
3894 return compiled_ptr
;
3898 emit_castclass_noilgen (MonoMethodBuilder
*mb
)
3903 * mono_marshal_get_castclass_with_cache:
3904 * This does the equivalent of \c mono_object_castclass_with_cache.
3907 mono_marshal_get_castclass_with_cache (void)
3909 static MonoMethod
*cached
;
3911 MonoMethodBuilder
*mb
;
3912 MonoMethodSignature
*sig
;
3918 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
3919 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
3921 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
3922 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3923 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
3924 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
3925 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
3926 sig
->ret
= object_type
;
3929 get_marshal_cb ()->emit_castclass (mb
);
3931 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
3932 res
= mono_mb_create (mb
, sig
, 8, info
);
3935 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
3936 mono_free_method (res
);
3937 mono_metadata_free_method_signature (sig
);
3944 /* this is an icall */
3946 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
3949 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, error
);
3950 if (mono_error_set_pending_exception (error
))
3953 if (mono_object_is_transparent_proxy (obj
))
3956 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
3958 cache_update
= cache_update
| 0x1;
3960 *cache
= cache_update
;
3966 emit_isinst_noilgen (MonoMethodBuilder
*mb
)
3971 * mono_marshal_get_isinst_with_cache:
3972 * This does the equivalent of \c mono_marshal_isinst_with_cache.
3975 mono_marshal_get_isinst_with_cache (void)
3977 static MonoMethod
*cached
;
3979 MonoMethodBuilder
*mb
;
3980 MonoMethodSignature
*sig
;
3986 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
3987 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
3989 mb
= mono_mb_new (mono_defaults
.object_class
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
3990 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3992 sig
->params
[TYPECHECK_OBJECT_ARG_POS
] = object_type
;
3994 sig
->params
[TYPECHECK_CLASS_ARG_POS
] = int_type
;
3996 sig
->params
[TYPECHECK_CACHE_ARG_POS
] = int_type
;
3997 sig
->ret
= object_type
;
4000 get_marshal_cb ()->emit_isinst (mb
);
4002 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
4003 res
= mono_mb_create (mb
, sig
, 8, info
);
4006 if (mono_atomic_cas_ptr ((volatile gpointer
*)&cached
, res
, NULL
)) {
4007 mono_free_method (res
);
4008 mono_metadata_free_method_signature (sig
);
4016 emit_struct_to_ptr_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4021 * mono_marshal_get_struct_to_ptr:
4022 * \param klass \c MonoClass
4024 * Generates IL code for <code>StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)</code>
4027 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
4029 MonoMethodBuilder
*mb
;
4030 static MonoMethod
*stoptr
= NULL
;
4034 g_assert (klass
!= NULL
);
4036 mono_marshal_load_type_info (klass
);
4038 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4039 if (marshal_info
->str_to_ptr
)
4040 return marshal_info
->str_to_ptr
;
4043 stoptr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "StructureToPtr", 3);
4046 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_UNKNOWN
);
4048 get_marshal_cb ()->emit_struct_to_ptr (mb
, klass
);
4050 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
4051 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
4054 mono_marshal_lock ();
4055 if (!marshal_info
->str_to_ptr
)
4056 marshal_info
->str_to_ptr
= res
;
4058 res
= marshal_info
->str_to_ptr
;
4059 mono_marshal_unlock ();
4064 emit_ptr_to_struct_noilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4069 * mono_marshal_get_ptr_to_struct:
4070 * \param klass \c MonoClass
4071 * Generates IL code for <code>PtrToStructure (IntPtr src, object structure)</code>
4074 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
4076 MonoMethodBuilder
*mb
;
4077 static MonoMethodSignature
*ptostr
= NULL
;
4081 g_assert (klass
!= NULL
);
4083 mono_marshal_load_type_info (klass
);
4085 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
4086 if (marshal_info
->ptr_to_str
)
4087 return marshal_info
->ptr_to_str
;
4090 MonoMethodSignature
*sig
;
4092 /* Create the signature corresponding to
4093 static void PtrToStructure (IntPtr ptr, object structure);
4094 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
4095 sig
= mono_create_icall_signature ("void ptr object");
4096 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4098 mono_memory_barrier ();
4102 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_UNKNOWN
);
4104 get_marshal_cb ()->emit_ptr_to_struct (mb
, klass
);
4106 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
4107 res
= mono_mb_create (mb
, ptostr
, 0, info
);
4110 mono_marshal_lock ();
4111 if (!marshal_info
->ptr_to_str
)
4112 marshal_info
->ptr_to_str
= res
;
4114 res
= marshal_info
->ptr_to_str
;
4115 mono_marshal_unlock ();
4120 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
4121 * This is used to avoid infinite recursion since it is hard to determine where to
4122 * replace a method with its synchronized wrapper, and where not.
4123 * The runtime should execute METHOD instead of the wrapper.
4126 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
4128 MonoMethodBuilder
*mb
;
4130 MonoMethodSignature
*sig
;
4132 MonoGenericContext
*ctx
= NULL
;
4133 MonoGenericContainer
*container
= NULL
;
4135 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4136 ctx
= &((MonoMethodInflated
*)method
)->context
;
4137 method
= ((MonoMethodInflated
*)method
)->declaring
;
4138 container
= mono_method_get_generic_container (method
);
4140 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4141 g_assert (container
);
4144 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNKNOWN
);
4145 get_marshal_cb ()->mb_emit_exception (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
4146 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4148 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature (method
));
4150 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
4151 info
->d
.synchronized_inner
.method
= method
;
4152 res
= mono_mb_create (mb
, sig
, 0, info
);
4156 res
= mono_class_inflate_generic_method_checked (res
, ctx
, error
);
4157 g_assert (mono_error_ok (error
)); /* FIXME don't swallow the error */
4163 emit_synchronized_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4165 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4166 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4167 mono_class_set_type_load_failure (method
->klass
, "");
4174 * mono_marshal_get_synchronized_wrapper:
4175 * Generates IL code for the synchronized wrapper: the generated method
4176 * calls \p method while locking \c this or the parent type.
4179 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
4181 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
4182 MonoMethodSignature
*sig
;
4183 MonoMethodBuilder
*mb
;
4187 MonoGenericContext
*ctx
= NULL
;
4188 MonoMethod
*orig_method
= NULL
;
4189 MonoGenericContainer
*container
= NULL
;
4193 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
4196 /* FIXME: Support generic methods too */
4197 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
4198 orig_method
= method
;
4199 ctx
= &((MonoMethodInflated
*)method
)->context
;
4200 method
= ((MonoMethodInflated
*)method
)->declaring
;
4201 container
= mono_method_get_generic_container (method
);
4203 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
4204 g_assert (container
);
4211 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4212 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
4216 cache
= get_cache (&get_method_image (method
)->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
4217 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4221 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature (method
));
4224 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
4226 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4227 info
->d
.synchronized
.method
= method
;
4229 mono_marshal_lock ();
4231 if (!enter_method
) {
4232 MonoMethodDesc
*desc
;
4234 desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
4235 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4236 g_assert (enter_method
);
4237 mono_method_desc_free (desc
);
4239 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
4240 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
4241 g_assert (exit_method
);
4242 mono_method_desc_free (desc
);
4244 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
4245 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
4246 g_assert (gettypefromhandle_method
);
4247 mono_method_desc_free (desc
);
4250 mono_marshal_unlock ();
4252 get_marshal_cb ()->mb_skip_visibility (mb
);
4253 get_marshal_cb ()->emit_synchronized_wrapper (mb
, method
, ctx
, container
, enter_method
, exit_method
, gettypefromhandle_method
);
4257 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4258 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4260 res
= mono_mb_create_and_cache_full (cache
, method
,
4261 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4269 emit_unbox_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4274 * mono_marshal_get_unbox_wrapper:
4275 * The returned method calls \p method unboxing the \c this argument.
4278 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
4280 MonoMethodSignature
*sig
= mono_method_signature (method
);
4281 MonoMethodBuilder
*mb
;
4286 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4288 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4291 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
4293 g_assert (sig
->hasthis
);
4295 get_marshal_cb ()->emit_unbox_wrapper (mb
, method
);
4297 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4298 info
->d
.unbox
.method
= method
;
4300 res
= mono_mb_create_and_cache_full (cache
, method
,
4301 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4304 /* mono_method_print_code (res); */
4310 is_monomorphic_array (MonoClass
*klass
)
4312 MonoClass
*element_class
;
4313 if (m_class_get_rank (klass
) != 1)
4316 element_class
= m_class_get_element_class (klass
);
4317 return mono_class_is_sealed (element_class
) || m_class_is_valuetype (element_class
);
4320 static MonoStelemrefKind
4321 get_virtual_stelemref_kind (MonoClass
*element_class
)
4323 if (element_class
== mono_defaults
.object_class
)
4324 return STELEMREF_OBJECT
;
4325 if (is_monomorphic_array (element_class
))
4326 return STELEMREF_SEALED_CLASS
;
4328 /* magic ifaces requires aditional checks for when the element type is an array */
4329 if (MONO_CLASS_IS_INTERFACE (element_class
) && m_class_is_array_special_interface (element_class
))
4330 return STELEMREF_COMPLEX
;
4332 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
4333 if (MONO_CLASS_IS_INTERFACE (element_class
) && !mono_class_has_variant_generic_params (element_class
))
4334 #ifdef COMPRESSED_INTERFACE_BITMAP
4335 return STELEMREF_COMPLEX
;
4337 return STELEMREF_INTERFACE
;
4339 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
4340 if (mono_class_is_marshalbyref (element_class
) || m_class_get_rank (element_class
) || mono_class_has_variant_generic_params (element_class
))
4341 return STELEMREF_COMPLEX
;
4342 if (mono_class_is_sealed (element_class
))
4343 return STELEMREF_SEALED_CLASS
;
4344 if (m_class_get_idepth (element_class
) <= MONO_DEFAULT_SUPERTABLE_SIZE
)
4345 return STELEMREF_CLASS_SMALL_IDEPTH
;
4347 return STELEMREF_CLASS
;
4352 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
4354 char *name
= mono_type_get_full_name (m_class_element_class (mono_object_class (array
)));
4355 printf ("slow vstore of %s\n", name
);
4361 emit_virtual_stelemref_noilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
4365 static const char *strelemref_wrapper_name
[] = {
4366 "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
4369 static const gchar
*
4370 mono_marshal_get_strelemref_wrapper_name (MonoStelemrefKind kind
)
4372 return strelemref_wrapper_name
[kind
];
4377 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
4378 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
4379 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
4380 * - Add a case for arrays of arrays.
4383 get_virtual_stelemref_wrapper (MonoStelemrefKind kind
)
4385 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
4386 static MonoMethodSignature
*signature
;
4387 MonoMethodBuilder
*mb
;
4390 const char *param_names
[16];
4393 if (cached_methods
[kind
])
4394 return cached_methods
[kind
];
4396 MonoType
*void_type
= m_class_get_byval_arg (mono_defaults
.void_class
);
4397 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
4398 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
4400 name
= g_strdup_printf ("virt_stelemref_%s", mono_marshal_get_strelemref_wrapper_name (kind
));
4401 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
4405 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
4407 /* void this::stelemref (size_t idx, void* value) */
4408 sig
->ret
= void_type
;
4409 sig
->hasthis
= TRUE
;
4410 sig
->params
[0] = int_type
; /* this is a natural sized int */
4411 sig
->params
[1] = object_type
;
4415 param_names
[0] = "index";
4416 param_names
[1] = "value";
4417 get_marshal_cb ()->emit_virtual_stelemref (mb
, param_names
, kind
);
4419 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
4420 info
->d
.virtual_stelemref
.kind
= kind
;
4421 res
= mono_mb_create (mb
, signature
, 4, info
);
4422 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
4424 mono_marshal_lock ();
4425 if (!cached_methods
[kind
]) {
4426 cached_methods
[kind
] = res
;
4427 mono_marshal_unlock ();
4429 mono_marshal_unlock ();
4430 mono_free_method (res
);
4434 return cached_methods
[kind
];
4438 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
4440 MonoStelemrefKind kind
;
4442 g_assert (m_class_get_rank (array_class
) == 1);
4443 kind
= get_virtual_stelemref_kind (m_class_get_element_class (array_class
));
4445 return get_virtual_stelemref_wrapper (kind
);
4449 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
4454 *nwrappers
= STELEMREF_KIND_COUNT
;
4455 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
4456 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
4457 res
[i
] = get_virtual_stelemref_wrapper (i
);
4462 emit_stelemref_noilgen (MonoMethodBuilder
*mb
)
4467 * mono_marshal_get_stelemref:
4470 mono_marshal_get_stelemref (void)
4472 static MonoMethod
* ret
= NULL
;
4473 MonoMethodSignature
*sig
;
4474 MonoMethodBuilder
*mb
;
4480 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
4483 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4485 MonoType
*void_type
= m_class_get_byval_arg (mono_defaults
.void_class
);
4486 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
4487 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
4490 /* void stelemref (void* array, int idx, void* value) */
4491 sig
->ret
= void_type
;
4492 sig
->params
[0] = object_type
;
4493 sig
->params
[1] = int_type
; /* this is a natural sized int */
4494 sig
->params
[2] = object_type
;
4496 get_marshal_cb ()->emit_stelemref (mb
);
4498 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
4499 ret
= mono_mb_create (mb
, sig
, 4, info
);
4506 mb_emit_byte_noilgen (MonoMethodBuilder
*mb
, guint8 op
)
4511 * mono_marshal_get_gsharedvt_in_wrapper:
4513 * This wrapper handles calls from normal code to gsharedvt code.
4516 mono_marshal_get_gsharedvt_in_wrapper (void)
4518 static MonoMethod
* ret
= NULL
;
4519 MonoMethodSignature
*sig
;
4520 MonoMethodBuilder
*mb
;
4526 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_UNKNOWN
);
4528 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4529 sig
->ret
= m_class_get_byval_arg (mono_defaults
.void_class
);
4532 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4534 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4536 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
4537 ret
= mono_mb_create (mb
, sig
, 4, info
);
4544 * mono_marshal_get_gsharedvt_out_wrapper:
4546 * This wrapper handles calls from gsharedvt code to normal code.
4549 mono_marshal_get_gsharedvt_out_wrapper (void)
4551 static MonoMethod
* ret
= NULL
;
4552 MonoMethodSignature
*sig
;
4553 MonoMethodBuilder
*mb
;
4559 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_UNKNOWN
);
4561 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4562 sig
->ret
= m_class_get_byval_arg (mono_defaults
.void_class
);
4565 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
4567 get_marshal_cb ()->mb_emit_byte (mb
, CEE_RET
);
4569 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
4570 ret
= mono_mb_create (mb
, sig
, 4, info
);
4577 emit_array_address_noilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
4587 /* LOCKING: vars accessed under the marshal lock */
4588 static ArrayElemAddr
*elem_addr_cache
= NULL
;
4589 static int elem_addr_cache_size
= 0;
4590 static int elem_addr_cache_next
= 0;
4593 * mono_marshal_get_array_address:
4594 * \param rank rank of the array type
4595 * \param elem_size size in bytes of an element of an array.
4597 * Returns a MonoMethod that implements the code to get the address
4598 * of an element in a multi-dimenasional array of \p rank dimensions.
4599 * The returned method takes an array as the first argument and then
4600 * \p rank indexes for the \p rank dimensions.
4601 * If ELEM_SIZE is 0, read the array size from the array object.
4604 mono_marshal_get_array_address (int rank
, int elem_size
)
4607 MonoMethodBuilder
*mb
;
4608 MonoMethodSignature
*sig
;
4614 mono_marshal_lock ();
4615 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4616 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4617 ret
= elem_addr_cache
[i
].method
;
4621 mono_marshal_unlock ();
4625 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
4626 MonoType
*int_type
= m_class_get_byval_arg (mono_defaults
.int_class
);
4627 MonoType
*int32_type
= m_class_get_byval_arg (mono_defaults
.int32_class
);
4629 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
4631 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
4632 sig
->ret
= int_type
;
4633 sig
->params
[0] = object_type
;
4634 for (int i
= 0; i
< rank
; ++i
) {
4635 sig
->params
[i
+ 1] = int32_type
;
4638 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
4639 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
4642 get_marshal_cb ()->emit_array_address (mb
, rank
, elem_size
);
4644 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
4645 info
->d
.element_addr
.rank
= rank
;
4646 info
->d
.element_addr
.elem_size
= elem_size
;
4647 ret
= mono_mb_create (mb
, sig
, 4, info
);
4650 /* cache the result */
4652 mono_marshal_lock ();
4653 for (int i
= 0; i
< elem_addr_cache_next
; ++i
) {
4654 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
4655 /* FIXME: free ret */
4656 ret
= elem_addr_cache
[i
].method
;
4662 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
4663 int new_size
= elem_addr_cache_size
+ 4;
4664 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
4665 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
4666 g_free (elem_addr_cache
);
4667 elem_addr_cache
= new_array
;
4668 elem_addr_cache_size
= new_size
;
4670 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
4671 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
4672 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
4673 elem_addr_cache_next
++;
4675 mono_marshal_unlock ();
4680 emit_array_accessor_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4685 * mono_marshal_get_array_accessor_wrapper:
4687 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
4690 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
4692 MonoMethodSignature
*sig
;
4693 MonoMethodBuilder
*mb
;
4696 MonoGenericContext
*ctx
= NULL
;
4697 MonoMethod
*orig_method
= NULL
;
4701 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
4702 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
4703 * FIXME: Use generic methods.
4710 g_assert_not_reached ();
4712 cache
= get_cache (&get_method_image (method
)->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
4713 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
4717 sig
= mono_metadata_signature_dup_full (get_method_image (method
), mono_method_signature (method
));
4720 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNKNOWN
);
4722 get_marshal_cb ()->emit_array_accessor_wrapper (mb
, method
, sig
, ctx
);
4724 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
4725 info
->d
.array_accessor
.method
= method
;
4729 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
4730 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
4732 res
= mono_mb_create_and_cache_full (cache
, method
,
4733 mb
, sig
, sig
->param_count
+ 16,
4743 mono_marshal_alloc_co_task_mem (size_t size
)
4745 if ((gulong
)size
== 0)
4746 /* This returns a valid pointer for size 0 on MS.NET */
4749 return g_try_malloc ((gulong
)size
);
4754 * mono_marshal_alloc:
4757 mono_marshal_alloc (gsize size
, MonoError
*error
)
4763 res
= mono_marshal_alloc_co_task_mem (size
);
4765 mono_error_set_out_of_memory (error
, "Could not allocate %lu bytes", size
);
4770 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
4772 ves_icall_marshal_alloc (gsize size
)
4775 void *ret
= mono_marshal_alloc (size
, error
);
4776 if (!mono_error_ok (error
)) {
4777 mono_error_set_pending_exception (error
);
4786 mono_marshal_free_co_task_mem (void *ptr
)
4794 * mono_marshal_free:
4797 mono_marshal_free (gpointer ptr
)
4799 mono_marshal_free_co_task_mem (ptr
);
4803 * mono_marshal_free_array:
4806 mono_marshal_free_array (gpointer
*ptr
, int size
)
4813 for (i
= 0; i
< size
; i
++)
4819 mono_marshal_string_to_utf16 (MonoString
*s
)
4821 return s
? mono_string_chars (s
) : NULL
;
4824 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
4826 mono_marshal_string_to_utf16_copy (MonoString
*s
)
4832 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((mono_string_length (s
) * 2) + 2, error
);
4833 if (!mono_error_ok (error
)) {
4834 mono_error_set_pending_exception (error
);
4837 memcpy (res
, mono_string_chars (s
), mono_string_length (s
) * 2);
4838 res
[mono_string_length (s
)] = 0;
4844 * mono_marshal_set_last_error:
4846 * This function is invoked to set the last error value from a P/Invoke call
4847 * which has \c SetLastError set.
4850 mono_marshal_set_last_error (void)
4852 /* This icall is called just after a P/Invoke call before the P/Invoke
4853 * wrapper transitions the runtime back to running mode. */
4854 MONO_REQ_GC_SAFE_MODE
;
4856 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
4858 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
4863 mono_marshal_set_last_error_windows (int error
)
4866 /* This icall is called just after a P/Invoke call before the P/Invoke
4867 * wrapper transitions the runtime back to running mode. */
4868 MONO_REQ_GC_SAFE_MODE
;
4869 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
4874 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray
*src
, gint32 start_index
,
4875 gpointer dest
, gint32 length
)
4880 MONO_CHECK_ARG_NULL (src
,);
4881 MONO_CHECK_ARG_NULL (dest
,);
4883 if (m_class_get_rank (mono_object_class (&src
->obj
)) != 1) {
4884 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
4887 if (start_index
< 0) {
4888 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
4892 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
4895 if (start_index
+ length
> mono_array_length (src
)) {
4896 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
4900 element_size
= mono_array_element_size (src
->obj
.vtable
->klass
);
4902 /* no references should be involved */
4903 source_addr
= mono_array_addr_with_size_fast (src
, element_size
, start_index
);
4905 memcpy (dest
, source_addr
, length
* element_size
);
4909 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src
, gint32 start_index
,
4910 MonoArray
*dest
, gint32 length
)
4915 MONO_CHECK_ARG_NULL (src
,);
4916 MONO_CHECK_ARG_NULL (dest
,);
4918 if (m_class_get_rank (mono_object_class (&dest
->obj
)) != 1) {
4919 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
4922 if (start_index
< 0) {
4923 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
4927 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
4930 if (start_index
+ length
> mono_array_length (dest
)) {
4931 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
4934 element_size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
4936 /* no references should be involved */
4937 dest_addr
= mono_array_addr_with_size_fast (dest
, element_size
, start_index
);
4939 memcpy (dest_addr
, src
, length
* element_size
);
4943 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr
, MonoError
*error
)
4947 return MONO_HANDLE_CAST (MonoString
, NULL_HANDLE
);
4949 return mono_string_new_handle (mono_domain_get (), ptr
, error
);
4953 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr
, gint32 len
)
4956 MonoString
*result
= NULL
;
4959 mono_error_set_argument_null (error
, "ptr", "");
4961 result
= mono_string_new_len_checked (mono_domain_get (), ptr
, len
, error
);
4962 mono_error_set_pending_exception (error
);
4967 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16
*ptr
)
4970 MonoString
*res
= NULL
;
4971 MonoDomain
*domain
= mono_domain_get ();
4981 res
= mono_string_new_utf16_checked (domain
, ptr
, len
, error
);
4982 if (!mono_error_ok (error
)) {
4983 mono_error_set_pending_exception (error
);
4990 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16
*ptr
, gint32 len
)
4993 MonoString
*res
= NULL
;
4994 MonoDomain
*domain
= mono_domain_get ();
5000 mono_error_set_argument_null (error
, "ptr", "");
5002 res
= mono_string_new_utf16_checked (domain
, ptr
, len
, error
);
5005 if (!mono_error_ok (error
))
5006 mono_error_set_pending_exception (error
);
5011 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5013 return (GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
)));
5017 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype
, MonoError
*error
)
5021 guint32 layout
, align
;
5026 if (MONO_HANDLE_IS_NULL (rtype
)) {
5027 mono_error_set_argument_null (error
, "type", "");
5031 type
= MONO_HANDLE_GETVAL (rtype
, type
);
5032 klass
= mono_class_from_mono_type (type
);
5033 if (!mono_class_init (klass
)) {
5034 mono_error_set_for_class_failure (error
, klass
);
5038 layout
= (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
);
5040 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
5041 return sizeof (gpointer
);
5042 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5043 mono_error_set_argument (error
, "t", "Type %s cannot be marshaled as an unmanaged structure.", m_class_get_name (klass
));
5047 result
= mono_marshal_type_size (type
, NULL
, &align
, FALSE
, m_class_is_unicode (klass
));
5048 return (guint32
)result
;
5052 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject
*obj
, gpointer dst
, MonoBoolean delete_old
)
5058 MONO_CHECK_ARG_NULL (obj
,);
5059 MONO_CHECK_ARG_NULL (dst
,);
5061 method
= mono_marshal_get_struct_to_ptr (obj
->vtable
->klass
);
5065 pa
[2] = &delete_old
;
5067 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5068 if (!mono_error_ok (error
))
5069 mono_error_set_pending_exception (error
);
5073 ptr_to_structure (gpointer src
, MonoObject
*dst
, MonoError
*error
)
5080 method
= mono_marshal_get_ptr_to_struct (dst
->vtable
->klass
);
5085 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5089 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src
, MonoObject
*dst
)
5094 MONO_CHECK_ARG_NULL (src
,);
5095 MONO_CHECK_ARG_NULL (dst
,);
5097 t
= mono_type_get_underlying_type (mono_class_get_type (dst
->vtable
->klass
));
5099 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5103 tmp
= g_strdup_printf ("Destination is a boxed value type.");
5104 exc
= mono_get_exception_argument ("dst", tmp
);
5107 mono_set_pending_exception (exc
);
5111 ptr_to_structure (src
, dst
, error
);
5112 if (!mono_error_ok (error
))
5113 mono_error_set_pending_exception (error
);
5117 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src
, MonoReflectionType
*type
)
5121 MonoDomain
*domain
= mono_domain_get ();
5126 MONO_CHECK_ARG_NULL (type
, NULL
);
5128 klass
= mono_class_from_mono_type (type
->type
);
5129 if (!mono_class_init (klass
)) {
5130 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
5134 res
= mono_object_new_checked (domain
, klass
, error
);
5135 if (!mono_error_ok (error
)) {
5136 mono_error_set_pending_exception (error
);
5140 ptr_to_structure (src
, res
, error
);
5141 if (!mono_error_ok (error
)) {
5142 mono_error_set_pending_exception (error
);
5150 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type
, MonoStringHandle field_name
, MonoError
*error
)
5153 if (MONO_HANDLE_IS_NULL (ref_type
)) {
5154 mono_error_set_argument_null (error
, "type", "");
5157 if (MONO_HANDLE_IS_NULL (field_name
)) {
5158 mono_error_set_argument_null (error
, "fieldName", "");
5162 char *fname
= mono_string_handle_to_utf8 (field_name
, error
);
5163 return_val_if_nok (error
, 0);
5165 MonoType
*type
= MONO_HANDLE_GETVAL (ref_type
, type
);
5166 MonoClass
*klass
= mono_class_from_mono_type (type
);
5167 if (!mono_class_init (klass
)) {
5168 mono_error_set_for_class_failure (error
, klass
);
5172 int match_index
= -1;
5173 while (klass
&& match_index
== -1) {
5174 MonoClassField
* field
;
5176 gpointer iter
= NULL
;
5177 while ((field
= mono_class_get_fields (klass
, &iter
))) {
5178 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5180 if (!strcmp (fname
, mono_field_get_name (field
))) {
5187 if (match_index
== -1)
5188 klass
= m_class_get_parent (klass
);
5193 if(match_index
== -1) {
5194 /* Get back original class instance */
5195 klass
= mono_class_from_mono_type (type
);
5197 mono_error_set_argument (error
, "fieldName", "Field passed in is not a marshaled member of the type %s", m_class_get_name (klass
));
5201 MonoMarshalType
*info
= mono_marshal_load_type_info (klass
);
5202 return info
->fields
[match_index
].offset
;
5207 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString
*string
)
5210 char *ret
= mono_string_to_utf8_checked (string
, error
);
5211 mono_error_set_pending_exception (error
);
5216 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString
*string
)
5221 gunichar2
*res
= (gunichar2
*)g_malloc ((mono_string_length (string
) + 1) * 2);
5223 memcpy (res
, mono_string_chars (string
), mono_string_length (string
) * 2);
5224 res
[mono_string_length (string
)] = 0;
5228 #endif /* !HOST_WIN32 */
5231 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
5233 MonoMarshalType
*info
;
5236 info
= mono_marshal_load_type_info (klass
);
5238 for (i
= 0; i
< info
->num_fields
; i
++) {
5239 MonoMarshalConv conv
;
5240 MonoType
*ftype
= info
->fields
[i
].field
->type
;
5243 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5246 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
5247 m_class_is_unicode (klass
), &conv
);
5249 cpos
= ptr
+ info
->fields
[i
].offset
;
5252 case MONO_MARSHAL_CONV_NONE
:
5253 if (MONO_TYPE_ISSTRUCT (ftype
)) {
5254 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
5258 case MONO_MARSHAL_CONV_STR_LPWSTR
:
5259 /* We assume this field points inside a MonoString */
5261 case MONO_MARSHAL_CONV_STR_LPTSTR
:
5263 /* We assume this field points inside a MonoString
5267 case MONO_MARSHAL_CONV_STR_LPSTR
:
5268 case MONO_MARSHAL_CONV_STR_BSTR
:
5269 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
5270 case MONO_MARSHAL_CONV_STR_TBSTR
:
5271 case MONO_MARSHAL_CONV_STR_UTF8STR
:
5272 mono_marshal_free (*(gpointer
*)cpos
);
5282 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionType
*type
)
5286 MONO_CHECK_ARG_NULL (src
,);
5287 MONO_CHECK_ARG_NULL (type
,);
5289 klass
= mono_class_from_mono_type (type
->type
);
5290 if (!mono_class_init (klass
)) {
5291 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
5295 mono_struct_delete_old (klass
, (char *)src
);
5299 static inline void *
5300 mono_marshal_alloc_hglobal (size_t size
)
5302 return g_try_malloc (size
);
5307 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size
)
5310 size_t s
= (size_t)size
;
5313 /* This returns a valid pointer for size 0 on MS.NET */
5316 res
= mono_marshal_alloc_hglobal (s
);
5319 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
5327 static inline gpointer
5328 mono_marshal_realloc_hglobal (gpointer ptr
, size_t size
)
5330 return g_try_realloc (ptr
, size
);
5335 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gpointer size
)
5338 size_t s
= (size_t)size
;
5341 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
5345 res
= mono_marshal_realloc_hglobal (ptr
, s
);
5348 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
5357 mono_marshal_free_hglobal (gpointer ptr
)
5365 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
5367 mono_marshal_free_hglobal (ptr
);
5371 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
)
5373 void *res
= mono_marshal_alloc_co_task_mem (size
);
5376 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
5383 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gulong size
)
5385 void *res
= mono_marshal_alloc_co_task_mem (size
);
5388 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
5395 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
5397 mono_marshal_free_co_task_mem (ptr
);
5402 static inline gpointer
5403 mono_marshal_realloc_co_task_mem (gpointer ptr
, size_t size
)
5405 return g_try_realloc (ptr
, (gulong
)size
);
5410 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
)
5412 void *res
= mono_marshal_realloc_co_task_mem (ptr
, size
);
5415 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
5422 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray
*arrayobj
, int index
)
5424 return mono_array_addr_with_size_fast (arrayobj
, mono_array_element_size (arrayobj
->obj
.vtable
->klass
), index
);
5428 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionTypeHandle type
, MonoError
*error
)
5431 MonoClass
*klass
= mono_type_get_class (MONO_HANDLE_GETVAL (type
, type
));
5432 if (!mono_class_init (klass
)) {
5433 mono_error_set_for_class_failure (error
, klass
);
5437 return mono_ftnptr_to_delegate_handle (klass
, ftn
, error
);
5441 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate
, MonoError
*error
)
5444 return mono_delegate_handle_to_ftnptr (delegate
, error
);
5448 * mono_marshal_is_loading_type_info:
5450 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
5454 mono_marshal_is_loading_type_info (MonoClass
*klass
)
5456 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5458 return g_slist_find (loads_list
, klass
) != NULL
;
5462 * mono_marshal_load_type_info:
5464 * Initialize \c klass::marshal_info using information from metadata. This function can
5465 * recursively call itself, and the caller is responsible to avoid that by calling
5466 * \c mono_marshal_is_loading_type_info beforehand.
5468 * LOCKING: Acquires the loader lock.
5471 mono_marshal_load_type_info (MonoClass
* klass
)
5474 guint32 native_size
= 0, min_align
= 1, packing
;
5475 MonoMarshalType
*info
;
5476 MonoClassField
* field
;
5481 g_assert (klass
!= NULL
);
5483 info
= mono_class_get_marshal_info (klass
);
5487 if (!m_class_is_inited (klass
))
5488 mono_class_init (klass
);
5490 info
= mono_class_get_marshal_info (klass
);
5495 * This function can recursively call itself, so we keep the list of classes which are
5496 * under initialization in a TLS list.
5498 g_assert (!mono_marshal_is_loading_type_info (klass
));
5499 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5500 loads_list
= g_slist_prepend (loads_list
, klass
);
5501 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5504 while ((field
= mono_class_get_fields (klass
, &iter
))) {
5505 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5507 if (mono_field_is_deleted (field
))
5512 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
5514 info
= (MonoMarshalType
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
5515 info
->num_fields
= count
;
5517 /* Try to find a size for this type in metadata */
5518 mono_metadata_packing_from_typedef (m_class_get_image (klass
), m_class_get_type_token (klass
), NULL
, &native_size
);
5520 if (m_class_get_parent (klass
)) {
5521 int parent_size
= mono_class_native_size (m_class_get_parent (klass
), NULL
);
5523 /* Add parent size to real size */
5524 native_size
+= parent_size
;
5525 info
->native_size
= parent_size
;
5528 packing
= m_class_get_packing_size (klass
) ? m_class_get_packing_size (klass
) : 8;
5531 while ((field
= mono_class_get_fields (klass
, &iter
))) {
5535 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5538 if (mono_field_is_deleted (field
))
5540 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
5541 mono_metadata_field_info_with_mempool (m_class_get_image (klass
), mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
5542 NULL
, NULL
, &info
->fields
[j
].mspec
);
5544 info
->fields
[j
].field
= field
;
5546 if ((mono_class_num_fields (klass
) == 1) && (m_class_get_instance_size (klass
) == sizeof (MonoObject
)) &&
5547 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
5548 /* This field is a hack inserted by MCS to empty structures */
5553 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
5554 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
5555 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5556 &align
, TRUE
, m_class_is_unicode (klass
));
5557 align
= m_class_get_packing_size (klass
) ? MIN (m_class_get_packing_size (klass
), align
): align
;
5558 min_align
= MAX (align
, min_align
);
5559 info
->fields
[j
].offset
= info
->native_size
;
5560 info
->fields
[j
].offset
+= align
- 1;
5561 info
->fields
[j
].offset
&= ~(align
- 1);
5562 info
->native_size
= info
->fields
[j
].offset
+ size
;
5564 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
5565 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
5566 &align
, TRUE
, m_class_is_unicode (klass
));
5567 min_align
= MAX (align
, min_align
);
5568 info
->fields
[j
].offset
= field
->offset
- sizeof (MonoObject
);
5569 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
5575 if (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_PTR
)
5576 info
->native_size
= sizeof (gpointer
);
5578 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5579 info
->native_size
= MAX (native_size
, info
->native_size
);
5581 * If the provided Size is equal or larger than the calculated size, and there
5582 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
5584 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
5585 if (native_size
&& native_size
== info
->native_size
&& m_class_get_packing_size (klass
) == 0)
5588 min_align
= MIN (min_align
, packing
);
5592 if (info
->native_size
& (min_align
- 1)) {
5593 info
->native_size
+= min_align
- 1;
5594 info
->native_size
&= ~(min_align
- 1);
5597 info
->min_align
= min_align
;
5599 /* Update the class's blittable info, if the layouts don't match */
5600 if (info
->native_size
!= mono_class_value_size (klass
, NULL
)) {
5601 mono_class_set_nonblittable (klass
); /* FIXME - how is this justified? what if we previously thought the class was blittable? */
5604 /* If this is an array type, ensure that we have element info */
5605 if (m_class_get_rank (klass
) && !mono_marshal_is_loading_type_info (m_class_get_element_class (klass
))) {
5606 mono_marshal_load_type_info (m_class_get_element_class (klass
));
5609 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
5610 loads_list
= g_slist_remove (loads_list
, klass
);
5611 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
5613 mono_marshal_lock ();
5614 MonoMarshalType
*info2
= mono_class_get_marshal_info (klass
);
5616 /*We do double-checking locking on marshal_info */
5617 mono_memory_barrier ();
5618 mono_class_set_marshal_info (klass
, info
);
5619 ++class_marshal_info_count
;
5622 mono_marshal_unlock ();
5628 * mono_class_native_size:
5629 * \param klass a class
5630 * \returns the native size of an object instance (when marshaled
5631 * to unmanaged code)
5634 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
5636 MonoMarshalType
*info
= mono_class_get_marshal_info (klass
);
5638 if (mono_marshal_is_loading_type_info (klass
)) {
5643 mono_marshal_load_type_info (klass
);
5645 info
= mono_class_get_marshal_info (klass
);
5649 *align
= info
->min_align
;
5651 return info
->native_size
;
5655 * mono_type_native_stack_size:
5656 * @t: the type to return the size it uses on the stack
5658 * Returns: the number of bytes required to hold an instance of this
5659 * type on the native stack
5662 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
5666 g_assert (t
!= NULL
);
5672 *align
= sizeof (gpointer
);
5673 return sizeof (gpointer
);
5677 case MONO_TYPE_BOOLEAN
:
5678 case MONO_TYPE_CHAR
:
5689 case MONO_TYPE_STRING
:
5690 case MONO_TYPE_OBJECT
:
5691 case MONO_TYPE_CLASS
:
5692 case MONO_TYPE_SZARRAY
:
5694 case MONO_TYPE_FNPTR
:
5695 case MONO_TYPE_ARRAY
:
5696 *align
= sizeof (gpointer
);
5697 return sizeof (gpointer
);
5702 *align
= MONO_ABI_ALIGNOF (double);
5706 *align
= MONO_ABI_ALIGNOF (gint64
);
5708 case MONO_TYPE_GENERICINST
:
5709 if (!mono_type_generic_inst_is_valuetype (t
)) {
5710 *align
= sizeof (gpointer
);
5711 return sizeof (gpointer
);
5714 case MONO_TYPE_TYPEDBYREF
:
5715 case MONO_TYPE_VALUETYPE
: {
5717 MonoClass
*klass
= mono_class_from_mono_type (t
);
5719 if (m_class_is_enumtype (klass
))
5720 return mono_type_native_stack_size (mono_class_enum_basetype (klass
), align
);
5722 size
= mono_class_native_size (klass
, align
);
5723 *align
= *align
+ 3;
5733 g_error ("type 0x%02x unknown", t
->type
);
5739 * mono_marshal_type_size:
5742 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
5743 gboolean as_field
, gboolean unicode
)
5746 MonoMarshalNative native_type
= mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
5749 switch (native_type
) {
5750 case MONO_NATIVE_BOOLEAN
:
5753 case MONO_NATIVE_I1
:
5754 case MONO_NATIVE_U1
:
5757 case MONO_NATIVE_I2
:
5758 case MONO_NATIVE_U2
:
5759 case MONO_NATIVE_VARIANTBOOL
:
5762 case MONO_NATIVE_I4
:
5763 case MONO_NATIVE_U4
:
5764 case MONO_NATIVE_ERROR
:
5767 case MONO_NATIVE_I8
:
5768 case MONO_NATIVE_U8
:
5769 *align
= MONO_ABI_ALIGNOF (gint64
);
5771 case MONO_NATIVE_R4
:
5774 case MONO_NATIVE_R8
:
5775 *align
= MONO_ABI_ALIGNOF (double);
5777 case MONO_NATIVE_INT
:
5778 case MONO_NATIVE_UINT
:
5779 case MONO_NATIVE_LPSTR
:
5780 case MONO_NATIVE_LPWSTR
:
5781 case MONO_NATIVE_LPTSTR
:
5782 case MONO_NATIVE_BSTR
:
5783 case MONO_NATIVE_ANSIBSTR
:
5784 case MONO_NATIVE_TBSTR
:
5785 case MONO_NATIVE_UTF8STR
:
5786 case MONO_NATIVE_LPARRAY
:
5787 case MONO_NATIVE_SAFEARRAY
:
5788 case MONO_NATIVE_IUNKNOWN
:
5789 case MONO_NATIVE_IDISPATCH
:
5790 case MONO_NATIVE_INTERFACE
:
5791 case MONO_NATIVE_ASANY
:
5792 case MONO_NATIVE_FUNC
:
5793 case MONO_NATIVE_LPSTRUCT
:
5794 *align
= MONO_ABI_ALIGNOF (gpointer
);
5795 return sizeof (gpointer
);
5796 case MONO_NATIVE_STRUCT
:
5797 klass
= mono_class_from_mono_type (type
);
5798 if (klass
== mono_defaults
.object_class
&&
5799 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
5803 padded_size
= mono_class_native_size (klass
, align
);
5804 if (padded_size
== 0)
5807 case MONO_NATIVE_BYVALTSTR
: {
5808 int esize
= unicode
? 2: 1;
5811 return mspec
->data
.array_data
.num_elem
* esize
;
5813 case MONO_NATIVE_BYVALARRAY
: {
5814 // FIXME: Have to consider ArraySubType
5816 klass
= mono_class_from_mono_type (type
);
5817 if (m_class_get_element_class (klass
) == mono_defaults
.char_class
) {
5818 esize
= unicode
? 2 : 1;
5821 esize
= mono_class_native_size (m_class_get_element_class (klass
), align
);
5824 return mspec
->data
.array_data
.num_elem
* esize
;
5826 case MONO_NATIVE_CUSTOM
:
5827 *align
= sizeof (gpointer
);
5828 return sizeof (gpointer
);
5830 case MONO_NATIVE_CURRENCY
:
5831 case MONO_NATIVE_VBBYREFSTR
:
5833 g_error ("native type %02x not implemented", native_type
);
5836 g_assert_not_reached ();
5841 * mono_marshal_asany:
5842 * This is a JIT icall, it sets the pending exception and returns NULL on error.
5845 mono_marshal_asany (MonoObject
*o
, MonoMarshalNative string_encoding
, int param_attrs
)
5854 t
= m_class_get_byval_arg (mono_object_class (o
));
5861 case MONO_TYPE_BOOLEAN
:
5864 case MONO_TYPE_CHAR
:
5869 return mono_object_unbox (o
);
5871 case MONO_TYPE_STRING
:
5872 switch (string_encoding
) {
5873 case MONO_NATIVE_LPWSTR
:
5874 return mono_marshal_string_to_utf16_copy ((MonoString
*)o
);
5875 case MONO_NATIVE_LPSTR
:
5876 case MONO_NATIVE_UTF8STR
:
5877 // Same code path, because in Mono, we treated strings as Utf8
5878 return mono_string_to_utf8str ((MonoString
*)o
);
5880 g_warning ("marshaling conversion %d not implemented", string_encoding
);
5881 g_assert_not_reached ();
5884 case MONO_TYPE_CLASS
:
5885 case MONO_TYPE_VALUETYPE
: {
5889 MonoBoolean delete_old
= FALSE
;
5891 klass
= t
->data
.klass
;
5893 if (mono_class_is_auto_layout (klass
))
5896 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
5897 return mono_object_unbox (o
);
5899 res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), error
);
5900 if (!mono_error_ok (error
)) {
5901 mono_error_set_pending_exception (error
);
5905 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
5906 method
= mono_marshal_get_struct_to_ptr (o
->vtable
->klass
);
5910 pa
[2] = &delete_old
;
5912 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5913 if (!mono_error_ok (error
)) {
5914 mono_error_set_pending_exception (error
);
5924 mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
5929 * mono_marshal_free_asany:
5930 * This is a JIT icall, it sets the pending exception
5933 mono_marshal_free_asany (MonoObject
*o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
)
5942 t
= m_class_get_byval_arg (mono_object_class (o
));
5944 case MONO_TYPE_STRING
:
5945 switch (string_encoding
) {
5946 case MONO_NATIVE_LPWSTR
:
5947 case MONO_NATIVE_LPSTR
:
5948 case MONO_NATIVE_UTF8STR
:
5949 mono_marshal_free (ptr
);
5952 g_warning ("marshaling conversion %d not implemented", string_encoding
);
5953 g_assert_not_reached ();
5956 case MONO_TYPE_CLASS
:
5957 case MONO_TYPE_VALUETYPE
: {
5958 klass
= t
->data
.klass
;
5960 if (m_class_is_valuetype (klass
) && (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)))
5963 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
5964 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (o
->vtable
->klass
);
5970 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
5971 if (!mono_error_ok (error
)) {
5972 mono_error_set_pending_exception (error
);
5977 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
5978 mono_struct_delete_old (klass
, (char *)ptr
);
5981 mono_marshal_free (ptr
);
5990 emit_generic_array_helper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
5995 * mono_marshal_get_generic_array_helper:
5997 * Return a wrapper which is used to implement the implicit interfaces on arrays.
5998 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
6001 mono_marshal_get_generic_array_helper (MonoClass
*klass
, gchar
*name
, MonoMethod
*method
)
6003 MonoMethodSignature
*sig
, *csig
;
6004 MonoMethodBuilder
*mb
;
6008 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
6009 mb
->method
->slot
= -1;
6011 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
6012 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
6014 sig
= mono_method_signature (method
);
6015 csig
= mono_metadata_signature_dup_full (get_method_image (method
), sig
);
6016 csig
->generic_param_count
= 0;
6018 get_marshal_cb ()->emit_generic_array_helper (mb
, method
, csig
);
6020 /* We can corlib internal methods */
6021 get_marshal_cb ()->mb_skip_visibility (mb
);
6023 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
6024 info
->d
.generic_array_helper
.method
= method
;
6025 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
6033 * The mono_win32_compat_* functions are implementations of inline
6034 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
6035 * although not exported by kernel32.
6037 * We map the appropiate kernel32 entries to these functions using
6038 * dllmaps declared in the global etc/mono/config.
6042 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
6044 if (!dest
|| !source
)
6047 memcpy (dest
, source
, length
);
6051 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
6053 memset (dest
, fill
, length
);
6057 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
6059 if (!dest
|| !source
)
6062 memmove (dest
, source
, length
);
6066 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
6068 memset (dest
, 0, length
);
6072 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
6077 for (i
= 0; i
< len
; ++i
)
6084 while (byte
&& !(byte
& 1))
6086 g_assert (byte
== 1);
6093 emit_thunk_invoke_wrapper_noilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
6098 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
6100 MonoMethodBuilder
*mb
;
6101 MonoMethodSignature
*sig
, *csig
;
6106 int i
, param_count
, sig_size
;
6110 klass
= method
->klass
;
6111 image
= m_class_get_image (klass
);
6113 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
6115 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
6118 MonoType
*object_type
= m_class_get_byval_arg (mono_defaults
.object_class
);
6120 sig
= mono_method_signature (method
);
6121 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
6123 /* add "this" and exception param */
6124 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
6126 /* dup & extend signature */
6127 csig
= mono_metadata_signature_alloc (image
, param_count
);
6128 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
6129 memcpy (csig
, sig
, sig_size
);
6130 csig
->param_count
= param_count
;
6133 csig
->call_convention
= MONO_CALL_DEFAULT
;
6137 csig
->params
[0] = m_class_get_byval_arg (klass
);
6138 /* move params up by one */
6139 for (i
= 0; i
< sig
->param_count
; i
++)
6140 csig
->params
[i
+ 1] = sig
->params
[i
];
6143 /* setup exception param as byref+[out] */
6144 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
, m_class_get_byval_arg (mono_defaults
.exception_class
));
6145 csig
->params
[param_count
- 1]->byref
= 1;
6146 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
6148 /* convert struct return to object */
6149 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6150 csig
->ret
= object_type
;
6152 get_marshal_cb ()->emit_thunk_invoke_wrapper (mb
, method
, csig
);
6154 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
6161 * mono_marshal_free_dynamic_wrappers:
6163 * Free wrappers of the dynamic method METHOD.
6166 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
6168 MonoImage
*image
= get_method_image (method
);
6170 g_assert (method_is_dynamic (method
));
6172 /* This could be called during shutdown */
6173 if (marshal_mutex_initialized
)
6174 mono_marshal_lock ();
6176 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
6177 * they could be shared with other methods ?
6179 if (image
->wrapper_caches
.runtime_invoke_direct_cache
)
6180 g_hash_table_remove (image
->wrapper_caches
.runtime_invoke_direct_cache
, method
);
6181 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
6182 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
6183 // FIXME: Need to clear the caches in other images as well
6184 if (image
->delegate_bound_static_invoke_cache
)
6185 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature (method
));
6187 if (marshal_mutex_initialized
)
6188 mono_marshal_unlock ();
6192 mono_icall_start (HandleStackMark
*stackmark
, MonoError
*error
)
6194 MonoThreadInfo
*info
= mono_thread_info_current ();
6196 mono_stack_mark_init (info
, stackmark
);
6202 mono_icall_end (MonoThreadInfo
*info
, HandleStackMark
*stackmark
, MonoError
*error
)
6204 mono_stack_mark_pop (info
, stackmark
);
6205 if (G_UNLIKELY (!is_ok (error
)))
6206 mono_error_set_pending_exception (error
);
6210 mono_icall_handle_new (gpointer rawobj
)
6212 #ifdef MONO_HANDLE_TRACK_OWNER
6213 return mono_handle_new (rawobj
, "<marshal args>");
6215 return mono_handle_new (rawobj
);
6220 mono_icall_handle_new_interior (gpointer rawobj
)
6222 #ifdef MONO_HANDLE_TRACK_OWNER
6223 return mono_handle_new_interior (rawobj
, "<marshal args>");
6225 return mono_handle_new_interior (rawobj
);
6230 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
)
6232 get_marshal_cb ()->emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, aot
, check_exceptions
, func_param
);
6236 emit_native_wrapper_noilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
)
6240 static MonoMarshalCallbacks marshal_cb
;
6241 static gboolean cb_inited
= FALSE
;
6244 mono_install_marshal_callbacks (MonoMarshalCallbacks
*cb
)
6246 g_assert (!cb_inited
);
6247 g_assert (cb
->version
== MONO_MARSHAL_CALLBACKS_VERSION
);
6248 memcpy (&marshal_cb
, cb
, sizeof (MonoMarshalCallbacks
));
6253 install_noilgen (void)
6255 MonoMarshalCallbacks cb
;
6256 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6257 cb
.emit_marshal_array
= emit_marshal_array_noilgen
;
6258 cb
.emit_marshal_boolean
= emit_marshal_boolean_noilgen
;
6259 cb
.emit_marshal_ptr
= emit_marshal_ptr_noilgen
;
6260 cb
.emit_marshal_char
= emit_marshal_char_noilgen
;
6261 cb
.emit_marshal_scalar
= emit_marshal_scalar_noilgen
;
6262 cb
.emit_marshal_custom
= emit_marshal_custom_noilgen
;
6263 cb
.emit_marshal_asany
= emit_marshal_asany_noilgen
;
6264 cb
.emit_marshal_vtype
= emit_marshal_vtype_noilgen
;
6265 cb
.emit_marshal_string
= emit_marshal_string_noilgen
;
6266 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_noilgen
;
6267 cb
.emit_marshal_handleref
= emit_marshal_handleref_noilgen
;
6268 cb
.emit_marshal_object
= emit_marshal_object_noilgen
;
6269 cb
.emit_marshal_variant
= emit_marshal_variant_noilgen
;
6270 cb
.emit_castclass
= emit_castclass_noilgen
;
6271 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_noilgen
;
6272 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_noilgen
;
6273 cb
.emit_isinst
= emit_isinst_noilgen
;
6274 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_noilgen
;
6275 cb
.emit_stelemref
= emit_stelemref_noilgen
;
6276 cb
.emit_array_address
= emit_array_address_noilgen
;
6277 cb
.emit_native_wrapper
= emit_native_wrapper_noilgen
;
6278 cb
.emit_managed_wrapper
= emit_managed_wrapper_noilgen
;
6279 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_noilgen
;
6280 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_noilgen
;
6281 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_noilgen
;
6282 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_noilgen
;
6283 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_noilgen
;
6284 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_noilgen
;
6285 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_noilgen
;
6286 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_noilgen
;
6287 cb
.emit_generic_array_helper
= emit_generic_array_helper_noilgen
;
6288 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_noilgen
;
6289 cb
.emit_create_string_hack
= emit_create_string_hack_noilgen
;
6290 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_noilgen
;
6291 cb
.emit_icall_wrapper
= emit_icall_wrapper_noilgen
;
6292 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_noilgen
;
6293 cb
.mb_skip_visibility
= mb_skip_visibility_noilgen
;
6294 cb
.mb_set_dynamic
= mb_set_dynamic_noilgen
;
6295 cb
.mb_emit_exception
= mb_emit_exception_noilgen
;
6296 cb
.mb_emit_byte
= mb_emit_byte_noilgen
;
6297 mono_install_marshal_callbacks (&cb
);
6300 static MonoMarshalCallbacks
*
6301 get_marshal_cb (void)
6303 if (G_UNLIKELY (!cb_inited
)) {
6305 mono_marshal_ilgen_init ();