2 * marshal.c: Routines for marshaling complex types in P/Invoke methods.
5 * Paolo Molaro (lupus@ximian.com)
7 * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #include "metadata/marshal.h"
23 #include "metadata/method-builder.h"
24 #include "metadata/tabledefs.h"
25 #include "metadata/exception.h"
26 #include "metadata/appdomain.h"
27 #include "mono/metadata/abi-details.h"
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/threads.h"
30 #include "mono/metadata/monitor.h"
31 #include "mono/metadata/class-internals.h"
32 #include "mono/metadata/metadata-internals.h"
33 #include "mono/metadata/domain-internals.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/metadata/threads-types.h"
36 #include "mono/metadata/string-icalls.h"
37 #include "mono/metadata/attrdefs.h"
38 #include "mono/metadata/gc-internals.h"
39 #include "mono/metadata/cominterop.h"
40 #include "mono/metadata/remoting.h"
41 #include "mono/metadata/reflection-internals.h"
42 #include "mono/metadata/threadpool-ms.h"
43 #include "mono/metadata/handle.h"
44 #include "mono/utils/mono-counters.h"
45 #include "mono/utils/mono-tls.h"
46 #include "mono/utils/mono-memory-model.h"
47 #include "mono/utils/atomic.h"
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include <mono/utils/mono-error-internals.h>
55 #if defined(HOST_WIN32)
59 /* #define DEBUG_RUNTIME_CODE */
61 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
65 #include "mono/cil/opcode.def"
71 * This mutex protects the various marshalling related caches in MonoImage
72 * and a few other data structures static to this file.
74 * The marshal lock is a non-recursive complex lock that sits below the domain lock in the
75 * runtime locking latice. Which means it can take simple locks suck as the image lock.
77 #define mono_marshal_lock() mono_locks_os_acquire (&marshal_mutex, MarshalLock)
78 #define mono_marshal_unlock() mono_locks_os_release (&marshal_mutex, MarshalLock)
79 static mono_mutex_t marshal_mutex
;
80 static gboolean marshal_mutex_initialized
;
82 static MonoNativeTlsKey last_error_tls_id
;
84 static MonoNativeTlsKey load_type_info_tls_id
;
86 static gboolean use_aot_wrappers
;
88 static void ftnptr_eh_callback_default (guint32 gchandle
);
90 static MonoFtnPtrEHCallback ftnptr_eh_callback
= ftnptr_eh_callback_default
;
93 delegate_hash_table_add (MonoDelegate
*d
);
96 delegate_hash_table_remove (MonoDelegate
*d
);
99 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
102 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
, int offset_of_first_child_field
, MonoMarshalNative string_encoding
);
105 mono_struct_delete_old (MonoClass
*klass
, char *ptr
);
108 mono_marshal_string_to_utf16 (MonoString
*s
);
111 mono_marshal_string_to_utf16_copy (MonoString
*s
);
114 mono_string_to_lpstr (MonoString
*string_obj
);
116 static MonoStringBuilder
*
117 mono_string_utf8_to_builder2 (char *text
);
119 static MonoStringBuilder
*
120 mono_string_utf16_to_builder2 (gunichar2
*text
);
123 mono_string_new_len_wrapper (const char *text
, guint length
);
126 mono_string_from_byvalstr (const char *data
, int len
);
129 mono_string_from_byvalwstr (gunichar2
*data
, int len
);
132 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*eltype
, guint32 elnum
);
135 mono_byvalarray_to_byte_array (MonoArray
*arr
, gpointer native_arr
, guint32 elnum
);
138 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*eltype
, guint32 elnum
);
141 mono_array_to_byte_byvalarray (gpointer native_arr
, MonoArray
*arr
, guint32 elnum
);
143 static MonoAsyncResult
*
144 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
);
147 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
);
150 mono_marshal_set_last_error_windows (int error
);
153 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
);
155 static void init_safe_handle (void);
158 ves_icall_marshal_alloc (gulong size
);
161 mono_string_utf8_to_builder (MonoStringBuilder
*sb
, char *text
);
164 mono_string_utf16_to_builder (MonoStringBuilder
*sb
, gunichar2
*text
);
167 mono_string_builder_to_utf8 (MonoStringBuilder
*sb
);
170 mono_string_builder_to_utf16 (MonoStringBuilder
*sb
);
173 mono_string_to_byvalstr (gpointer dst
, MonoString
*src
, int size
);
176 mono_string_to_byvalwstr (gpointer dst
, MonoString
*src
, int size
);
179 mono_delegate_to_ftnptr (MonoDelegate
*delegate
);
182 mono_ftnptr_to_delegate (MonoClass
*klass
, gpointer ftn
);
185 mono_array_to_savearray (MonoArray
*array
);
188 mono_array_to_lparray (MonoArray
*array
);
191 mono_free_lparray (MonoArray
*array
, gpointer
* nativeArray
);
194 mono_marshal_asany (MonoObject
*obj
, MonoMarshalNative string_encoding
, int param_attrs
);
197 mono_marshal_free_asany (MonoObject
*o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
);
200 mono_array_to_savearray (MonoArray
*array
);
203 mono_array_to_lparray (MonoArray
*array
);
206 mono_free_lparray (MonoArray
*array
, gpointer
* nativeArray
);
209 mono_marshal_ftnptr_eh_callback (guint32 gchandle
);
211 static MonoThreadInfo
*
212 mono_icall_start (HandleStackMark
*stackmark
, MonoError
*error
);
215 mono_icall_end (MonoThreadInfo
*info
, HandleStackMark
*stackmark
, MonoError
*error
);
217 /* Lazy class loading functions */
218 static GENERATE_GET_CLASS_WITH_CACHE (string_builder
, System
.Text
, StringBuilder
)
219 static GENERATE_GET_CLASS_WITH_CACHE (date_time
, System
, DateTime
)
220 static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute
, System
.Runtime
.InteropServices
, UnmanagedFunctionPointerAttribute
)
221 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler
, System
.Runtime
.InteropServices
, ICustomMarshaler
)
223 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
224 static MonoMethod
*sh_dangerous_add_ref
;
225 static MonoMethod
*sh_dangerous_release
;
230 sh_dangerous_add_ref
= mono_class_get_method_from_name (
231 mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
232 sh_dangerous_release
= mono_class_get_method_from_name (
233 mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
237 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean no_wrapper
)
239 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
241 mono_register_jit_icall (func
, name
, sig
, no_wrapper
);
245 mono_signature_no_pinvoke (MonoMethod
*method
)
247 MonoMethodSignature
*sig
= mono_method_signature (method
);
249 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
250 sig
->pinvoke
= FALSE
;
257 mono_marshal_init_tls (void)
259 mono_native_tls_alloc (&last_error_tls_id
, NULL
);
260 mono_native_tls_alloc (&load_type_info_tls_id
, NULL
);
264 mono_object_isinst_icall (MonoObject
*obj
, MonoClass
*klass
)
267 MonoObject
*result
= mono_object_isinst_checked (obj
, klass
, &error
);
268 mono_error_set_pending_exception (&error
);
273 ves_icall_mono_string_from_utf16 (gunichar2
*data
)
276 MonoString
*result
= mono_string_from_utf16_checked (data
, &error
);
277 mono_error_set_pending_exception (&error
);
282 ves_icall_mono_string_to_utf8 (MonoString
*str
)
285 char *result
= mono_string_to_utf8_checked (str
, &error
);
286 mono_error_set_pending_exception (&error
);
291 mono_marshal_init (void)
293 static gboolean module_initialized
= FALSE
;
295 if (!module_initialized
) {
296 module_initialized
= TRUE
;
297 mono_os_mutex_init_recursive (&marshal_mutex
);
298 marshal_mutex_initialized
= TRUE
;
300 register_icall (ves_icall_System_Threading_Thread_ResetAbort
, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE
);
301 register_icall (mono_marshal_string_to_utf16
, "mono_marshal_string_to_utf16", "ptr obj", FALSE
);
302 register_icall (mono_marshal_string_to_utf16_copy
, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE
);
303 register_icall (mono_string_to_utf16
, "mono_string_to_utf16", "ptr obj", FALSE
);
304 register_icall (ves_icall_mono_string_from_utf16
, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE
);
305 register_icall (mono_string_from_byvalstr
, "mono_string_from_byvalstr", "obj ptr int", FALSE
);
306 register_icall (mono_string_from_byvalwstr
, "mono_string_from_byvalwstr", "obj ptr int", FALSE
);
307 register_icall (mono_string_new_wrapper
, "mono_string_new_wrapper", "obj ptr", FALSE
);
308 register_icall (mono_string_new_len_wrapper
, "mono_string_new_len_wrapper", "obj ptr int", FALSE
);
309 register_icall (ves_icall_mono_string_to_utf8
, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE
);
310 register_icall (mono_string_to_lpstr
, "mono_string_to_lpstr", "ptr obj", FALSE
);
311 register_icall (mono_string_to_ansibstr
, "mono_string_to_ansibstr", "ptr object", FALSE
);
312 register_icall (mono_string_builder_to_utf8
, "mono_string_builder_to_utf8", "ptr object", FALSE
);
313 register_icall (mono_string_builder_to_utf16
, "mono_string_builder_to_utf16", "ptr object", FALSE
);
314 register_icall (mono_array_to_savearray
, "mono_array_to_savearray", "ptr object", FALSE
);
315 register_icall (mono_array_to_lparray
, "mono_array_to_lparray", "ptr object", FALSE
);
316 register_icall (mono_free_lparray
, "mono_free_lparray", "void object ptr", FALSE
);
317 register_icall (mono_byvalarray_to_array
, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE
);
318 register_icall (mono_byvalarray_to_byte_array
, "mono_byvalarray_to_byte_array", "void object ptr int32", FALSE
);
319 register_icall (mono_array_to_byvalarray
, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE
);
320 register_icall (mono_array_to_byte_byvalarray
, "mono_array_to_byte_byvalarray", "void ptr object int32", FALSE
);
321 register_icall (mono_delegate_to_ftnptr
, "mono_delegate_to_ftnptr", "ptr object", FALSE
);
322 register_icall (mono_ftnptr_to_delegate
, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE
);
323 register_icall (mono_marshal_asany
, "mono_marshal_asany", "ptr object int32 int32", FALSE
);
324 register_icall (mono_marshal_free_asany
, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE
);
325 register_icall (ves_icall_marshal_alloc
, "ves_icall_marshal_alloc", "ptr int32", FALSE
);
326 register_icall (mono_marshal_free
, "mono_marshal_free", "void ptr", FALSE
);
327 register_icall (mono_marshal_set_last_error
, "mono_marshal_set_last_error", "void", FALSE
);
328 register_icall (mono_marshal_set_last_error_windows
, "mono_marshal_set_last_error_windows", "void int32", FALSE
);
329 register_icall (mono_string_utf8_to_builder
, "mono_string_utf8_to_builder", "void ptr ptr", FALSE
);
330 register_icall (mono_string_utf8_to_builder2
, "mono_string_utf8_to_builder2", "object ptr", FALSE
);
331 register_icall (mono_string_utf16_to_builder
, "mono_string_utf16_to_builder", "void ptr ptr", FALSE
);
332 register_icall (mono_string_utf16_to_builder2
, "mono_string_utf16_to_builder2", "object ptr", FALSE
);
333 register_icall (mono_marshal_free_array
, "mono_marshal_free_array", "void ptr int32", FALSE
);
334 register_icall (mono_string_to_byvalstr
, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE
);
335 register_icall (mono_string_to_byvalwstr
, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE
);
336 register_icall (g_free
, "g_free", "void ptr", FALSE
);
337 register_icall (mono_object_isinst_icall
, "mono_object_isinst_icall", "object object ptr", FALSE
);
338 register_icall (mono_struct_delete_old
, "mono_struct_delete_old", "void ptr ptr", FALSE
);
339 register_icall (mono_delegate_begin_invoke
, "mono_delegate_begin_invoke", "object object ptr", FALSE
);
340 register_icall (mono_delegate_end_invoke
, "mono_delegate_end_invoke", "object object ptr", FALSE
);
341 register_icall (mono_context_get
, "mono_context_get", "object", FALSE
);
342 register_icall (mono_context_set
, "mono_context_set", "void object", FALSE
);
343 register_icall (mono_gc_wbarrier_generic_nostore
, "wb_generic", "void ptr", FALSE
);
344 register_icall (mono_gchandle_get_target
, "mono_gchandle_get_target", "object int32", TRUE
);
345 register_icall (mono_gchandle_new
, "mono_gchandle_new", "uint32 object bool", TRUE
);
346 register_icall (mono_marshal_isinst_with_cache
, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE
);
347 register_icall (mono_marshal_ftnptr_eh_callback
, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE
);
348 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE
);
349 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE
);
350 register_icall (mono_threads_attach_coop
, "mono_threads_attach_coop", "ptr ptr ptr", TRUE
);
351 register_icall (mono_threads_detach_coop
, "mono_threads_detach_coop", "void ptr ptr", TRUE
);
352 register_icall (mono_icall_start
, "mono_icall_start", "ptr ptr ptr", TRUE
);
353 register_icall (mono_icall_end
, "mono_icall_end", "void ptr ptr ptr", TRUE
);
354 register_icall (mono_handle_new
, "mono_handle_new", "ptr ptr", TRUE
);
356 mono_cominterop_init ();
357 mono_remoting_init ();
362 mono_marshal_cleanup (void)
364 mono_cominterop_cleanup ();
366 mono_native_tls_free (load_type_info_tls_id
);
367 mono_native_tls_free (last_error_tls_id
);
368 mono_os_mutex_destroy (&marshal_mutex
);
369 marshal_mutex_initialized
= FALSE
;
373 mono_marshal_lock_internal (void)
375 mono_marshal_lock ();
379 mono_marshal_unlock_internal (void)
381 mono_marshal_unlock ();
384 /* This is a JIT icall, it sets the pending exception and return NULL on error */
386 mono_delegate_to_ftnptr (MonoDelegate
*delegate
)
389 MonoMethod
*method
, *wrapper
;
391 uint32_t target_handle
= 0;
396 if (delegate
->delegate_trampoline
)
397 return delegate
->delegate_trampoline
;
399 klass
= ((MonoObject
*)delegate
)->vtable
->klass
;
400 g_assert (klass
->delegate
);
402 method
= delegate
->method
;
403 if (delegate
->method_is_virtual
)
404 method
= mono_object_get_virtual_method (delegate
->target
, method
);
406 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
407 const char *exc_class
, *exc_arg
;
410 ftnptr
= mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
412 g_assert (exc_class
);
413 mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
419 if (delegate
->target
) {
420 /* Produce a location which can be embedded in JITted code */
421 target_handle
= mono_gchandle_new_weakref (delegate
->target
, FALSE
);
424 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
);
426 delegate
->delegate_trampoline
= mono_compile_method_checked (wrapper
, &error
);
430 // Add the delegate to the delegate hash table
431 delegate_hash_table_add (delegate
);
433 /* when the object is collected, collect the dynamic method, too */
434 mono_object_register_finalizer ((MonoObject
*)delegate
);
436 return delegate
->delegate_trampoline
;
439 if (target_handle
!= 0)
440 mono_gchandle_free (target_handle
);
441 mono_error_set_pending_exception (&error
);
446 * this hash table maps from a delegate trampoline object to a weak reference
447 * of the delegate. As an optimizations with a non-moving GC we store the
448 * object pointer itself, otherwise we use a GC handle.
450 static GHashTable
*delegate_hash_table
;
453 delegate_hash_table_new (void) {
454 return g_hash_table_new (NULL
, NULL
);
458 delegate_hash_table_remove (MonoDelegate
*d
)
460 guint32 gchandle
= 0;
462 mono_marshal_lock ();
463 if (delegate_hash_table
== NULL
)
464 delegate_hash_table
= delegate_hash_table_new ();
465 if (mono_gc_is_moving ())
466 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
467 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
468 mono_marshal_unlock ();
469 if (gchandle
&& mono_gc_is_moving ())
470 mono_gchandle_free (gchandle
);
474 delegate_hash_table_add (MonoDelegate
*d
)
477 guint32 old_gchandle
;
479 mono_marshal_lock ();
480 if (delegate_hash_table
== NULL
)
481 delegate_hash_table
= delegate_hash_table_new ();
482 if (mono_gc_is_moving ()) {
483 gchandle
= mono_gchandle_new_weakref ((MonoObject
*)d
, FALSE
);
484 old_gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
485 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
487 mono_gchandle_free (old_gchandle
);
489 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, d
);
491 mono_marshal_unlock ();
495 * mono_marshal_use_aot_wrappers:
497 * Instructs this module to use AOT compatible wrappers.
500 mono_marshal_use_aot_wrappers (gboolean use
)
502 use_aot_wrappers
= use
;
506 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
509 MonoCustomAttrInfo
*cinfo
;
510 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
512 /* The attribute is only available in Net 2.0 */
513 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
515 * The pinvoke attributes are stored in a real custom attribute so we have to
518 cinfo
= mono_custom_attrs_from_class_checked (klass
, &error
);
519 if (!mono_error_ok (&error
)) {
520 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error
));
521 mono_error_cleanup (&error
);
523 if (cinfo
&& !mono_runtime_get_no_exec ()) {
524 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error
);
526 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
528 if (!mono_error_ok (&error
)) {
529 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error
));
530 mono_error_cleanup (&error
);
534 mono_custom_attrs_free (cinfo
);
539 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
541 mono_ftnptr_to_delegate (MonoClass
*klass
, gpointer ftn
)
550 mono_marshal_lock ();
551 if (delegate_hash_table
== NULL
)
552 delegate_hash_table
= delegate_hash_table_new ();
554 if (mono_gc_is_moving ()) {
555 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
556 mono_marshal_unlock ();
558 d
= (MonoDelegate
*)mono_gchandle_get_target (gchandle
);
562 d
= (MonoDelegate
*)g_hash_table_lookup (delegate_hash_table
, ftn
);
563 mono_marshal_unlock ();
566 /* This is a native function, so construct a delegate for it */
567 MonoMethodSignature
*sig
;
569 MonoMarshalSpec
**mspecs
;
570 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
571 MonoMethodPInvoke piinfo
;
572 MonoObject
*this_obj
;
575 if (use_aot_wrappers
) {
576 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
577 this_obj
= mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, &error
);
578 if (!is_ok (&error
)) {
579 mono_error_set_pending_exception (&error
);
583 memset (&piinfo
, 0, sizeof (piinfo
));
584 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
586 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
587 mono_method_get_marshal_info (invoke
, mspecs
);
588 /* Freed below so don't alloc from mempool */
589 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
592 wrapper
= mono_marshal_get_native_func_wrapper (klass
->image
, sig
, &piinfo
, mspecs
, ftn
);
595 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
597 mono_metadata_free_marshal_spec (mspecs
[i
]);
602 d
= (MonoDelegate
*)mono_object_new_checked (mono_domain_get (), klass
, &error
);
603 if (!mono_error_ok (&error
)) {
604 mono_error_set_pending_exception (&error
);
607 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, &error
);
608 if (mono_error_set_pending_exception (&error
))
610 mono_delegate_ctor_with_method ((MonoObject
*)d
, this_obj
, compiled_ptr
, wrapper
, &error
);
611 if (mono_error_set_pending_exception (&error
))
615 if (d
->object
.vtable
->domain
!= mono_domain_get ()) {
616 mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
624 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
629 delegate_hash_table_remove (delegate
);
631 ptr
= (gpointer
)InterlockedExchangePointer (&delegate
->delegate_trampoline
, NULL
);
633 if (!delegate
->target
) {
634 /* The wrapper method is shared between delegates -> no need to free it */
643 ji
= mono_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (ptr
));
646 method
= mono_jit_info_get_method (ji
);
647 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
649 /*the target gchandle is the first entry after size and the wrapper itself.*/
650 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
653 mono_gchandle_free (gchandle
);
655 mono_runtime_free_method (mono_object_domain (delegate
), method
);
659 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
661 mono_string_from_byvalstr (const char *data
, int max_len
)
664 MonoDomain
*domain
= mono_domain_get ();
670 while (len
< max_len
- 1 && data
[len
])
673 MonoString
*result
= mono_string_new_len_checked (domain
, data
, len
, &error
);
674 mono_error_set_pending_exception (&error
);
678 /* This is a JIT icall, it sets the pending exception and return NULL on error */
680 mono_string_from_byvalwstr (gunichar2
*data
, int max_len
)
683 MonoString
*res
= NULL
;
684 MonoDomain
*domain
= mono_domain_get ();
690 while (data
[len
]) len
++;
692 res
= mono_string_new_utf16_checked (domain
, data
, MIN (len
, max_len
), &error
);
693 if (!mono_error_ok (&error
)) {
694 mono_error_set_pending_exception (&error
);
701 mono_array_to_savearray (MonoArray
*array
)
706 g_assert_not_reached ();
711 mono_array_to_lparray (MonoArray
*array
)
714 gpointer
*nativeArray
= NULL
;
715 int nativeArraySize
= 0;
725 klass
= array
->obj
.vtable
->klass
;
727 switch (klass
->element_class
->byval_arg
.type
) {
729 g_assert_not_reached ();
731 case MONO_TYPE_CLASS
:
732 nativeArraySize
= array
->max_length
;
733 nativeArray
= (void **)malloc(sizeof(gpointer
) * nativeArraySize
);
734 for(i
= 0; i
< nativeArraySize
; ++i
)
735 nativeArray
[i
] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((MonoObject
**)array
->vector
)[i
]);
738 case MONO_TYPE_BOOLEAN
:
751 case MONO_TYPE_VALUETYPE
:
755 case MONO_TYPE_GENERICINST
:
756 case MONO_TYPE_OBJECT
:
757 case MONO_TYPE_ARRAY
:
758 case MONO_TYPE_SZARRAY
:
759 case MONO_TYPE_STRING
:
761 g_warning ("type 0x%x not handled", klass
->element_class
->byval_arg
.type
);
762 g_assert_not_reached ();
765 return array
->vector
;
769 mono_free_lparray (MonoArray
*array
, gpointer
* nativeArray
)
780 klass
= array
->obj
.vtable
->klass
;
782 if (klass
->element_class
->byval_arg
.type
== MONO_TYPE_CLASS
) {
783 for(i
= 0; i
< array
->max_length
; ++i
)
784 mono_marshal_free_ccw (mono_array_get (array
, MonoObject
*, i
));
785 g_free (nativeArray
);
791 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*elclass
, guint32 elnum
)
793 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
795 if (elclass
== mono_defaults
.byte_class
) {
796 GError
*error
= NULL
;
800 ut
= g_utf8_to_utf16 ((const gchar
*)native_arr
, elnum
, NULL
, &items_written
, &error
);
803 memcpy (mono_array_addr (arr
, guint16
, 0), ut
, items_written
* sizeof (guint16
));
807 g_error_free (error
);
810 g_assert_not_reached ();
814 mono_byvalarray_to_byte_array (MonoArray
*arr
, gpointer native_arr
, guint32 elnum
)
816 mono_byvalarray_to_array (arr
, native_arr
, mono_defaults
.byte_class
, elnum
);
819 /* This is a JIT icall, it sets the pending exception and returns on error */
821 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*elclass
, guint32 elnum
)
823 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
825 if (elclass
== mono_defaults
.byte_class
) {
827 GError
*error
= NULL
;
829 as
= g_utf16_to_utf8 (mono_array_addr (arr
, gunichar2
, 0), mono_array_length (arr
), NULL
, NULL
, &error
);
831 mono_set_pending_exception (mono_get_exception_argument ("string", error
->message
));
832 g_error_free (error
);
836 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
839 g_assert_not_reached ();
844 mono_array_to_byte_byvalarray (gpointer native_arr
, MonoArray
*arr
, guint32 elnum
)
846 mono_array_to_byvalarray (native_arr
, arr
, mono_defaults
.byte_class
, elnum
);
849 static MonoStringBuilder
*
850 mono_string_builder_new (int starting_string_length
)
852 static MonoClass
*string_builder_class
;
853 static MonoMethod
*sb_ctor
;
854 static void *args
[1];
857 int initial_len
= starting_string_length
;
863 MonoMethodDesc
*desc
;
866 string_builder_class
= mono_class_get_string_builder_class ();
867 g_assert (string_builder_class
);
868 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
869 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
871 mono_method_desc_free (desc
);
872 mono_memory_barrier ();
876 // We make a new array in the _to_builder function, so this
877 // array will always be garbage collected.
878 args
[0] = &initial_len
;
880 MonoStringBuilder
*sb
= (MonoStringBuilder
*)mono_object_new_checked (mono_domain_get (), string_builder_class
, &error
);
881 mono_error_assert_ok (&error
);
884 mono_runtime_try_invoke (sb_ctor
, sb
, args
, &exc
, &error
);
885 g_assert (exc
== NULL
);
886 mono_error_assert_ok (&error
);
888 g_assert (sb
->chunkChars
->max_length
>= initial_len
);
894 mono_string_utf16_to_builder_copy (MonoStringBuilder
*sb
, gunichar2
*text
, size_t string_len
)
896 gunichar2
*charDst
= (gunichar2
*)sb
->chunkChars
->vector
;
897 gunichar2
*charSrc
= (gunichar2
*)text
;
898 memcpy (charDst
, charSrc
, sizeof (gunichar2
) * string_len
);
900 sb
->chunkLength
= string_len
;
906 mono_string_utf16_to_builder2 (gunichar2
*text
)
912 for (len
= 0; text
[len
] != 0; ++len
);
914 MonoStringBuilder
*sb
= mono_string_builder_new (len
);
915 mono_string_utf16_to_builder (sb
, text
);
921 mono_string_utf8_to_builder (MonoStringBuilder
*sb
, char *text
)
926 int len
= strlen (text
);
927 if (len
> mono_string_builder_capacity (sb
))
928 len
= mono_string_builder_capacity (sb
);
930 GError
*error
= NULL
;
932 gunichar2
* ut
= g_utf8_to_utf16 (text
, len
, NULL
, &copied
, &error
);
935 MONO_OBJECT_SETREF (sb
, chunkPrevious
, NULL
);
936 mono_string_utf16_to_builder_copy (sb
, ut
, copied
);
938 g_error_free (error
);
944 mono_string_utf8_to_builder2 (char *text
)
949 int len
= strlen (text
);
950 MonoStringBuilder
*sb
= mono_string_builder_new (len
);
951 mono_string_utf8_to_builder (sb
, text
);
958 mono_string_utf16_to_builder (MonoStringBuilder
*sb
, gunichar2
*text
)
964 for (len
= 0; text
[len
] != 0; ++len
);
966 if (len
> mono_string_builder_capacity (sb
))
967 len
= mono_string_builder_capacity (sb
);
969 mono_string_utf16_to_builder_copy (sb
, text
, len
);
973 * mono_string_builder_to_utf8:
974 * @sb: the string builder
976 * Converts to utf8 the contents of the MonoStringBuilder.
978 * Returns: a utf8 string with the contents of the StringBuilder.
980 * The return value must be released with mono_marshal_free.
982 * This is a JIT icall, it sets the pending exception and returns NULL on error.
985 mono_string_builder_to_utf8 (MonoStringBuilder
*sb
)
988 GError
*gerror
= NULL
;
993 gunichar2
*str_utf16
= mono_string_builder_to_utf16 (sb
);
995 guint str_len
= mono_string_builder_string_length (sb
);
997 gchar
*tmp
= g_utf16_to_utf8 (str_utf16
, str_len
, NULL
, NULL
, &gerror
);
1000 g_error_free (gerror
);
1001 mono_marshal_free (str_utf16
);
1002 mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
1005 guint len
= mono_string_builder_capacity (sb
) + 1;
1006 gchar
*res
= (gchar
*)mono_marshal_alloc (len
* sizeof (gchar
), &error
);
1007 if (!mono_error_ok (&error
)) {
1008 mono_marshal_free (str_utf16
);
1010 mono_error_set_pending_exception (&error
);
1014 g_assert (str_len
< len
);
1015 memcpy (res
, tmp
, str_len
* sizeof (gchar
));
1016 res
[str_len
] = '\0';
1018 mono_marshal_free (str_utf16
);
1025 * mono_string_builder_to_utf16:
1026 * @sb: the string builder
1028 * Converts to utf16 the contents of the MonoStringBuilder.
1030 * Returns: a utf16 string with the contents of the StringBuilder.
1032 * The return value must be released with mono_marshal_free.
1034 * This is a JIT icall, it sets the pending exception and returns NULL on error.
1037 mono_string_builder_to_utf16 (MonoStringBuilder
*sb
)
1044 g_assert (sb
->chunkChars
);
1046 guint len
= mono_string_builder_capacity (sb
);
1051 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((len
+ 1) * sizeof (gunichar2
), &error
);
1052 if (!mono_error_ok (&error
)) {
1053 mono_error_set_pending_exception (&error
);
1062 MonoStringBuilder
* chunk
= sb
;
1064 if (chunk
->chunkLength
> 0) {
1065 // Check that we will not overrun our boundaries.
1066 gunichar2
*source
= (gunichar2
*)chunk
->chunkChars
->vector
;
1068 if (chunk
->chunkLength
<= len
) {
1069 memcpy (str
+ chunk
->chunkOffset
, source
, chunk
->chunkLength
* sizeof(gunichar2
));
1071 g_error ("A chunk in the StringBuilder had a length longer than expected from the offset.");
1074 len
-= chunk
->chunkLength
;
1076 chunk
= chunk
->chunkPrevious
;
1077 } while (chunk
!= NULL
);
1082 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1084 mono_string_to_lpstr (MonoString
*s
)
1089 GError
*error
= NULL
;
1095 as
= CoTaskMemAlloc (1);
1100 tmp
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &len
, &error
);
1102 MonoException
*exc
= mono_get_exception_argument ("string", error
->message
);
1103 g_error_free (error
);
1104 mono_set_pending_exception (exc
);
1107 as
= CoTaskMemAlloc (len
+ 1);
1108 memcpy (as
, tmp
, len
+ 1);
1114 char *result
= mono_string_to_utf8_checked (s
, &error
);
1115 mono_error_set_pending_exception (&error
);
1121 mono_string_to_ansibstr (MonoString
*string_obj
)
1123 g_error ("UnmanagedMarshal.BStr is not implemented.");
1128 * mono_string_to_byvalstr:
1129 * @dst: Where to store the null-terminated utf8 decoded string.
1130 * @src: the MonoString to copy.
1131 * @size: the maximum number of bytes to copy.
1133 * Copies the MonoString pointed to by @src as a utf8 string
1134 * into @dst, it copies at most @size bytes into the destination.
1137 mono_string_to_byvalstr (gpointer dst
, MonoString
*src
, int size
)
1143 g_assert (dst
!= NULL
);
1144 g_assert (size
> 0);
1146 memset (dst
, 0, size
);
1150 s
= mono_string_to_utf8_checked (src
, &error
);
1151 if (mono_error_set_pending_exception (&error
))
1153 len
= MIN (size
, strlen (s
));
1156 memcpy (dst
, s
, len
);
1161 * mono_string_to_byvalwstr:
1162 * @dst: Where to store the null-terminated utf16 decoded string.
1163 * @src: the MonoString to copy.
1164 * @size: the maximum number of bytes to copy.
1166 * Copies the MonoString pointed to by @src as a utf16 string into
1167 * @dst, it copies at most @size bytes into the destination (including
1168 * a terminating 16-bit zero terminator).
1171 mono_string_to_byvalwstr (gpointer dst
, MonoString
*src
, int size
)
1175 g_assert (dst
!= NULL
);
1176 g_assert (size
> 1);
1179 memset (dst
, 0, size
* 2);
1183 len
= MIN (size
, (mono_string_length (src
)));
1184 memcpy (dst
, mono_string_chars (src
), size
* 2);
1185 if (size
<= mono_string_length (src
))
1187 *((gunichar2
*) dst
+ len
) = 0;
1190 /* this is an icall, it sets the pending exception and returns NULL on error */
1192 mono_string_new_len_wrapper (const char *text
, guint length
)
1195 MonoString
*result
= mono_string_new_len_checked (mono_domain_get (), text
, length
, &error
);
1196 mono_error_set_pending_exception (&error
);
1203 * mono_mb_emit_exception_marshal_directive:
1205 * This function assumes ownership of MSG, which should be malloc-ed.
1208 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, char *msg
)
1213 s
= mono_image_strdup (mb
->method
->klass
->image
, msg
);
1218 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", s
);
1221 #endif /* !DISABLE_JIT */
1224 mono_type_to_ldind (MonoType
*type
)
1230 switch (type
->type
) {
1232 return CEE_LDIND_I1
;
1234 case MONO_TYPE_BOOLEAN
:
1235 return CEE_LDIND_U1
;
1237 return CEE_LDIND_I2
;
1239 case MONO_TYPE_CHAR
:
1240 return CEE_LDIND_U2
;
1242 return CEE_LDIND_I4
;
1244 return CEE_LDIND_U4
;
1248 case MONO_TYPE_FNPTR
:
1250 case MONO_TYPE_CLASS
:
1251 case MONO_TYPE_STRING
:
1252 case MONO_TYPE_OBJECT
:
1253 case MONO_TYPE_SZARRAY
:
1254 case MONO_TYPE_ARRAY
:
1255 return CEE_LDIND_REF
;
1258 return CEE_LDIND_I8
;
1260 return CEE_LDIND_R4
;
1262 return CEE_LDIND_R8
;
1263 case MONO_TYPE_VALUETYPE
:
1264 if (type
->data
.klass
->enumtype
) {
1265 type
= mono_class_enum_basetype (type
->data
.klass
);
1269 case MONO_TYPE_TYPEDBYREF
:
1271 case MONO_TYPE_GENERICINST
:
1272 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1275 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1281 mono_type_to_stind (MonoType
*type
)
1284 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1288 switch (type
->type
) {
1291 case MONO_TYPE_BOOLEAN
:
1292 return CEE_STIND_I1
;
1295 case MONO_TYPE_CHAR
:
1296 return CEE_STIND_I2
;
1299 return CEE_STIND_I4
;
1303 case MONO_TYPE_FNPTR
:
1305 case MONO_TYPE_CLASS
:
1306 case MONO_TYPE_STRING
:
1307 case MONO_TYPE_OBJECT
:
1308 case MONO_TYPE_SZARRAY
:
1309 case MONO_TYPE_ARRAY
:
1310 return CEE_STIND_REF
;
1313 return CEE_STIND_I8
;
1315 return CEE_STIND_R4
;
1317 return CEE_STIND_R8
;
1318 case MONO_TYPE_VALUETYPE
:
1319 if (type
->data
.klass
->enumtype
) {
1320 type
= mono_class_enum_basetype (type
->data
.klass
);
1324 case MONO_TYPE_TYPEDBYREF
:
1326 case MONO_TYPE_GENERICINST
:
1327 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1330 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1338 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1341 case MONO_MARSHAL_CONV_BOOL_I4
:
1342 mono_mb_emit_ldloc (mb
, 1);
1343 mono_mb_emit_ldloc (mb
, 0);
1344 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
1345 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1346 mono_mb_emit_byte (mb
, 3);
1347 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1348 mono_mb_emit_byte (mb
, CEE_BR_S
);
1349 mono_mb_emit_byte (mb
, 1);
1350 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1351 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1353 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1354 mono_mb_emit_ldloc (mb
, 1);
1355 mono_mb_emit_ldloc (mb
, 0);
1356 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
1357 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1358 mono_mb_emit_byte (mb
, 3);
1359 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1360 mono_mb_emit_byte (mb
, CEE_BR_S
);
1361 mono_mb_emit_byte (mb
, 1);
1362 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1363 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1365 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1366 MonoClass
*eklass
= NULL
;
1369 if (type
->type
== MONO_TYPE_SZARRAY
) {
1370 eklass
= type
->data
.klass
;
1372 g_assert_not_reached ();
1375 esize
= mono_class_native_size (eklass
, NULL
);
1377 /* create a new array */
1378 mono_mb_emit_ldloc (mb
, 1);
1379 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1380 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
1381 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1383 if (eklass
->blittable
) {
1384 /* copy the elements */
1385 mono_mb_emit_ldloc (mb
, 1);
1386 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1387 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
1388 mono_mb_emit_byte (mb
, CEE_ADD
);
1389 mono_mb_emit_ldloc (mb
, 0);
1390 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1391 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1392 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1395 int array_var
, src_var
, dst_var
, index_var
;
1396 guint32 label2
, label3
;
1398 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1399 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1400 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1403 mono_mb_emit_ldloc (mb
, 1);
1404 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1405 mono_mb_emit_stloc (mb
, array_var
);
1407 /* save the old src pointer */
1408 mono_mb_emit_ldloc (mb
, 0);
1409 mono_mb_emit_stloc (mb
, src_var
);
1410 /* save the old dst pointer */
1411 mono_mb_emit_ldloc (mb
, 1);
1412 mono_mb_emit_stloc (mb
, dst_var
);
1414 /* Emit marshalling loop */
1415 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1416 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1417 mono_mb_emit_stloc (mb
, index_var
);
1420 label2
= mono_mb_get_label (mb
);
1421 mono_mb_emit_ldloc (mb
, index_var
);
1422 mono_mb_emit_ldloc (mb
, array_var
);
1423 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1424 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1426 /* src is already set */
1429 mono_mb_emit_ldloc (mb
, array_var
);
1430 mono_mb_emit_ldloc (mb
, index_var
);
1431 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1432 mono_mb_emit_stloc (mb
, 1);
1434 /* Do the conversion */
1435 emit_struct_conv (mb
, eklass
, TRUE
);
1438 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1440 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
1442 mono_mb_patch_branch (mb
, label3
);
1444 /* restore the old src pointer */
1445 mono_mb_emit_ldloc (mb
, src_var
);
1446 mono_mb_emit_stloc (mb
, 0);
1447 /* restore the old dst pointer */
1448 mono_mb_emit_ldloc (mb
, dst_var
);
1449 mono_mb_emit_stloc (mb
, 1);
1453 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1454 MonoClass
*eclass
= mono_defaults
.char_class
;
1456 /* create a new array */
1457 mono_mb_emit_ldloc (mb
, 1);
1458 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1459 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
1460 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1462 mono_mb_emit_ldloc (mb
, 1);
1463 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1464 mono_mb_emit_ldloc (mb
, 0);
1465 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1466 mono_mb_emit_icall (mb
, mono_byvalarray_to_byte_array
);
1469 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1470 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
1471 mono_mb_emit_ldloc (mb
, 1);
1472 mono_mb_emit_ldloc (mb
, 0);
1473 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1474 mono_mb_emit_icall (mb
, mono_string_from_byvalstr
);
1476 mono_mb_emit_ldloc (mb
, 1);
1477 mono_mb_emit_ldloc (mb
, 0);
1478 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1480 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1482 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
1483 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
1484 mono_mb_emit_ldloc (mb
, 1);
1485 mono_mb_emit_ldloc (mb
, 0);
1486 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1487 mono_mb_emit_icall (mb
, mono_string_from_byvalwstr
);
1489 mono_mb_emit_ldloc (mb
, 1);
1490 mono_mb_emit_ldloc (mb
, 0);
1491 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
1493 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1495 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1496 mono_mb_emit_ldloc (mb
, 1);
1497 mono_mb_emit_ldloc (mb
, 0);
1498 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1500 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
1502 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1504 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1506 case MONO_MARSHAL_CONV_STR_LPSTR
:
1507 mono_mb_emit_ldloc (mb
, 1);
1508 mono_mb_emit_ldloc (mb
, 0);
1509 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1510 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1511 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1513 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1514 mono_mb_emit_ldloc (mb
, 1);
1515 mono_mb_emit_ldloc (mb
, 0);
1516 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1517 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
1518 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1520 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1521 MonoClass
*klass
= mono_class_from_mono_type (type
);
1522 int src_var
, dst_var
;
1524 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1525 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1527 /* *dst = new object */
1528 mono_mb_emit_ldloc (mb
, 1);
1529 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1530 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
1531 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1533 /* save the old src pointer */
1534 mono_mb_emit_ldloc (mb
, 0);
1535 mono_mb_emit_stloc (mb
, src_var
);
1536 /* save the old dst pointer */
1537 mono_mb_emit_ldloc (mb
, 1);
1538 mono_mb_emit_stloc (mb
, dst_var
);
1540 /* dst = pointer to newly created object data */
1541 mono_mb_emit_ldloc (mb
, 1);
1542 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1543 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
1544 mono_mb_emit_byte (mb
, CEE_ADD
);
1545 mono_mb_emit_stloc (mb
, 1);
1547 emit_struct_conv (mb
, klass
, TRUE
);
1549 /* restore the old src pointer */
1550 mono_mb_emit_ldloc (mb
, src_var
);
1551 mono_mb_emit_stloc (mb
, 0);
1552 /* restore the old dst pointer */
1553 mono_mb_emit_ldloc (mb
, dst_var
);
1554 mono_mb_emit_stloc (mb
, 1);
1557 case MONO_MARSHAL_CONV_DEL_FTN
: {
1558 MonoClass
*klass
= mono_class_from_mono_type (type
);
1560 mono_mb_emit_ldloc (mb
, 1);
1561 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1562 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1563 mono_mb_emit_ldloc (mb
, 0);
1564 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1565 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
1566 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1569 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1570 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type
)->name
);
1574 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
1575 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1576 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1577 mono_cominterop_emit_ptr_to_object_conv (mb
, type
, conv
, mspec
);
1579 #endif /* DISABLE_COM */
1581 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1583 * Passing SafeHandles as ref does not allow the unmanaged code
1584 * to change the SafeHandle value. If the value is changed,
1585 * we should issue a diagnostic exception (NotSupportedException)
1586 * that informs the user that changes to handles in unmanaged code
1589 * Since we currently have no access to the original
1590 * SafeHandle that was used during the marshalling,
1591 * for now we just ignore this, and ignore/discard any
1592 * changes that might have happened to the handle.
1597 case MONO_MARSHAL_CONV_HANDLEREF
: {
1599 * Passing HandleRefs in a struct that is ref()ed does not
1600 * copy the values back to the HandleRef
1605 case MONO_MARSHAL_CONV_STR_BSTR
:
1606 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1607 case MONO_MARSHAL_CONV_STR_TBSTR
:
1608 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1610 char *msg
= g_strdup_printf ("marshaling conversion %d not implemented", conv
);
1612 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1619 conv_to_icall (MonoMarshalConv conv
, int *ind_store_type
)
1622 if (!ind_store_type
)
1623 ind_store_type
= &dummy
;
1624 *ind_store_type
= CEE_STIND_I
;
1626 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1627 return mono_marshal_string_to_utf16
;
1628 case MONO_MARSHAL_CONV_LPWSTR_STR
:
1629 *ind_store_type
= CEE_STIND_REF
;
1630 return ves_icall_mono_string_from_utf16
;
1631 case MONO_MARSHAL_CONV_LPTSTR_STR
:
1632 *ind_store_type
= CEE_STIND_REF
;
1633 return mono_string_new_wrapper
;
1634 case MONO_MARSHAL_CONV_LPSTR_STR
:
1635 *ind_store_type
= CEE_STIND_REF
;
1636 return mono_string_new_wrapper
;
1637 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1639 return mono_marshal_string_to_utf16
;
1641 return mono_string_to_lpstr
;
1643 case MONO_MARSHAL_CONV_STR_LPSTR
:
1644 return mono_string_to_lpstr
;
1645 case MONO_MARSHAL_CONV_STR_BSTR
:
1646 return mono_string_to_bstr
;
1647 case MONO_MARSHAL_CONV_BSTR_STR
:
1648 *ind_store_type
= CEE_STIND_REF
;
1649 return mono_string_from_bstr_icall
;
1650 case MONO_MARSHAL_CONV_STR_TBSTR
:
1651 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1652 return mono_string_to_ansibstr
;
1653 case MONO_MARSHAL_CONV_SB_LPSTR
:
1654 return mono_string_builder_to_utf8
;
1655 case MONO_MARSHAL_CONV_SB_LPTSTR
:
1657 return mono_string_builder_to_utf16
;
1659 return mono_string_builder_to_utf8
;
1661 case MONO_MARSHAL_CONV_SB_LPWSTR
:
1662 return mono_string_builder_to_utf16
;
1663 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1664 return mono_array_to_savearray
;
1665 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1666 return mono_array_to_lparray
;
1667 case MONO_MARSHAL_FREE_LPARRAY
:
1668 return mono_free_lparray
;
1669 case MONO_MARSHAL_CONV_DEL_FTN
:
1670 return mono_delegate_to_ftnptr
;
1671 case MONO_MARSHAL_CONV_FTN_DEL
:
1672 *ind_store_type
= CEE_STIND_REF
;
1673 return mono_ftnptr_to_delegate
;
1674 case MONO_MARSHAL_CONV_LPSTR_SB
:
1675 *ind_store_type
= CEE_STIND_REF
;
1676 return mono_string_utf8_to_builder
;
1677 case MONO_MARSHAL_CONV_LPTSTR_SB
:
1678 *ind_store_type
= CEE_STIND_REF
;
1680 return mono_string_utf16_to_builder
;
1682 return mono_string_utf8_to_builder
;
1684 case MONO_MARSHAL_CONV_LPWSTR_SB
:
1685 *ind_store_type
= CEE_STIND_REF
;
1686 return mono_string_utf16_to_builder
;
1687 case MONO_MARSHAL_FREE_ARRAY
:
1688 return mono_marshal_free_array
;
1689 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1690 return mono_string_to_byvalstr
;
1691 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
1692 return mono_string_to_byvalwstr
;
1694 g_assert_not_reached ();
1701 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1707 case MONO_MARSHAL_CONV_BOOL_I4
:
1708 mono_mb_emit_ldloc (mb
, 1);
1709 mono_mb_emit_ldloc (mb
, 0);
1710 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1711 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
1713 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1714 mono_mb_emit_ldloc (mb
, 1);
1715 mono_mb_emit_ldloc (mb
, 0);
1716 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1717 mono_mb_emit_byte (mb
, CEE_NEG
);
1718 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
1720 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1721 case MONO_MARSHAL_CONV_STR_LPSTR
:
1722 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1723 case MONO_MARSHAL_CONV_STR_BSTR
:
1724 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1725 case MONO_MARSHAL_CONV_STR_TBSTR
: {
1728 /* free space if free == true */
1729 mono_mb_emit_ldloc (mb
, 2);
1730 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1731 mono_mb_emit_ldloc (mb
, 1);
1732 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1733 mono_mb_emit_icall (mb
, g_free
);
1734 mono_mb_patch_short_branch (mb
, pos
);
1736 mono_mb_emit_ldloc (mb
, 1);
1737 mono_mb_emit_ldloc (mb
, 0);
1738 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1739 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
1740 mono_mb_emit_byte (mb
, stind_op
);
1743 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1744 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1745 case MONO_MARSHAL_CONV_DEL_FTN
:
1746 mono_mb_emit_ldloc (mb
, 1);
1747 mono_mb_emit_ldloc (mb
, 0);
1748 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1749 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
1750 mono_mb_emit_byte (mb
, stind_op
);
1752 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1753 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
1756 mono_mb_emit_ldloc (mb
, 1); /* dst */
1757 mono_mb_emit_ldloc (mb
, 0);
1758 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
1759 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1760 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
1763 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1764 MonoClass
*eklass
= NULL
;
1767 if (type
->type
== MONO_TYPE_SZARRAY
) {
1768 eklass
= type
->data
.klass
;
1770 g_assert_not_reached ();
1773 if (eklass
->valuetype
)
1774 esize
= mono_class_native_size (eklass
, NULL
);
1776 esize
= sizeof (gpointer
);
1778 mono_mb_emit_ldloc (mb
, 0);
1779 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1780 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1782 if (eklass
->blittable
) {
1783 mono_mb_emit_ldloc (mb
, 1);
1784 mono_mb_emit_ldloc (mb
, 0);
1785 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1786 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
1787 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1788 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1789 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1791 int array_var
, src_var
, dst_var
, index_var
;
1792 guint32 label2
, label3
;
1794 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1795 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1796 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1799 mono_mb_emit_ldloc (mb
, 0);
1800 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1801 mono_mb_emit_stloc (mb
, array_var
);
1803 /* save the old src pointer */
1804 mono_mb_emit_ldloc (mb
, 0);
1805 mono_mb_emit_stloc (mb
, src_var
);
1806 /* save the old dst pointer */
1807 mono_mb_emit_ldloc (mb
, 1);
1808 mono_mb_emit_stloc (mb
, dst_var
);
1810 /* Emit marshalling loop */
1811 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1812 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1813 mono_mb_emit_stloc (mb
, index_var
);
1816 label2
= mono_mb_get_label (mb
);
1817 mono_mb_emit_ldloc (mb
, index_var
);
1818 mono_mb_emit_ldloc (mb
, array_var
);
1819 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1820 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1823 mono_mb_emit_ldloc (mb
, array_var
);
1824 mono_mb_emit_ldloc (mb
, index_var
);
1825 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1826 mono_mb_emit_stloc (mb
, 0);
1828 /* dst is already set */
1830 /* Do the conversion */
1831 emit_struct_conv (mb
, eklass
, FALSE
);
1834 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1836 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
1838 mono_mb_patch_branch (mb
, label3
);
1840 /* restore the old src pointer */
1841 mono_mb_emit_ldloc (mb
, src_var
);
1842 mono_mb_emit_stloc (mb
, 0);
1843 /* restore the old dst pointer */
1844 mono_mb_emit_ldloc (mb
, dst_var
);
1845 mono_mb_emit_stloc (mb
, 1);
1848 mono_mb_patch_branch (mb
, pos
);
1851 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1852 mono_mb_emit_ldloc (mb
, 0);
1853 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1854 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1856 mono_mb_emit_ldloc (mb
, 1);
1857 mono_mb_emit_ldloc (mb
, 0);
1858 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1859 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1860 mono_mb_emit_icall (mb
, mono_array_to_byte_byvalarray
);
1861 mono_mb_patch_short_branch (mb
, pos
);
1864 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1865 int src_var
, dst_var
;
1867 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1868 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1870 mono_mb_emit_ldloc (mb
, 0);
1871 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1872 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1874 /* save the old src pointer */
1875 mono_mb_emit_ldloc (mb
, 0);
1876 mono_mb_emit_stloc (mb
, src_var
);
1877 /* save the old dst pointer */
1878 mono_mb_emit_ldloc (mb
, 1);
1879 mono_mb_emit_stloc (mb
, dst_var
);
1881 /* src = pointer to object data */
1882 mono_mb_emit_ldloc (mb
, 0);
1883 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1884 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
1885 mono_mb_emit_byte (mb
, CEE_ADD
);
1886 mono_mb_emit_stloc (mb
, 0);
1888 emit_struct_conv (mb
, mono_class_from_mono_type (type
), FALSE
);
1890 /* restore the old src pointer */
1891 mono_mb_emit_ldloc (mb
, src_var
);
1892 mono_mb_emit_stloc (mb
, 0);
1893 /* restore the old dst pointer */
1894 mono_mb_emit_ldloc (mb
, dst_var
);
1895 mono_mb_emit_stloc (mb
, 1);
1897 mono_mb_patch_branch (mb
, pos
);
1902 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
1903 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1904 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1905 mono_cominterop_emit_object_to_ptr_conv (mb
, type
, conv
, mspec
);
1907 #endif /* DISABLE_COM */
1909 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1912 mono_mb_emit_ldloc (mb
, 0);
1913 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1914 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1915 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
1916 mono_mb_patch_branch (mb
, pos
);
1918 /* Pull the handle field from SafeHandle */
1919 mono_mb_emit_ldloc (mb
, 1);
1920 mono_mb_emit_ldloc (mb
, 0);
1921 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1922 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
1923 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1924 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1928 case MONO_MARSHAL_CONV_HANDLEREF
: {
1929 mono_mb_emit_ldloc (mb
, 1);
1930 mono_mb_emit_ldloc (mb
, 0);
1931 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
1932 mono_mb_emit_byte (mb
, CEE_ADD
);
1933 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1934 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1939 g_error ("marshalling conversion %d not implemented", conv
);
1944 static int offset_of_first_nonstatic_field(MonoClass
*klass
)
1947 for (i
= 0; i
< klass
->field
.count
; i
++) {
1948 if (!(klass
->fields
[i
].type
->attrs
& FIELD_ATTRIBUTE_STATIC
) && !mono_field_is_deleted (&klass
->fields
[i
]))
1949 return klass
->fields
[i
].offset
- sizeof (MonoObject
);
1956 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
,
1957 int offset_of_first_child_field
, MonoMarshalNative string_encoding
)
1959 MonoMarshalType
*info
;
1963 emit_struct_conv_full (mb
, klass
->parent
, to_object
, offset_of_first_nonstatic_field (klass
), string_encoding
);
1965 info
= mono_marshal_load_type_info (klass
);
1967 if (info
->native_size
== 0)
1970 if (klass
->blittable
) {
1971 int usize
= mono_class_value_size (klass
, NULL
);
1972 g_assert (usize
== info
->native_size
);
1973 mono_mb_emit_ldloc (mb
, 1);
1974 mono_mb_emit_ldloc (mb
, 0);
1975 mono_mb_emit_icon (mb
, usize
);
1976 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1977 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1980 mono_mb_emit_add_to_local (mb
, 0, usize
);
1981 mono_mb_emit_add_to_local (mb
, 1, offset_of_first_child_field
);
1983 mono_mb_emit_add_to_local (mb
, 0, offset_of_first_child_field
);
1984 mono_mb_emit_add_to_local (mb
, 1, usize
);
1989 if (klass
!= mono_class_try_get_safehandle_class ()) {
1990 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
1991 char *msg
= g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
1992 mono_type_full_name (&klass
->byval_arg
));
1993 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1998 for (i
= 0; i
< info
->num_fields
; i
++) {
1999 MonoMarshalNative ntype
;
2000 MonoMarshalConv conv
;
2001 MonoType
*ftype
= info
->fields
[i
].field
->type
;
2004 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
2006 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
2009 ntype
= (MonoMarshalNative
)mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, klass
->unicode
, &conv
);
2012 msize
= klass
->instance_size
- info
->fields
[i
].field
->offset
;
2013 usize
= info
->native_size
- info
->fields
[i
].offset
;
2015 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
2016 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
2019 if (klass
!= mono_class_try_get_safehandle_class ()){
2021 * FIXME: Should really check for usize==0 and msize>0, but we apply
2022 * the layout to the managed structure as well.
2025 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) && (usize
== 0)) {
2026 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
2027 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
2028 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
2029 "reference field at the same offset as another field.",
2030 mono_type_full_name (&klass
->byval_arg
));
2035 case MONO_MARSHAL_CONV_NONE
: {
2038 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
2039 g_assert (!ftype
->byref
);
2040 if (ftype
->type
== MONO_TYPE_I
|| ftype
->type
== MONO_TYPE_U
) {
2041 mono_mb_emit_ldloc (mb
, 1);
2042 mono_mb_emit_ldloc (mb
, 0);
2043 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2044 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2055 case MONO_TYPE_BOOLEAN
:
2058 case MONO_TYPE_CHAR
:
2064 mono_mb_emit_ldloc (mb
, 1);
2065 mono_mb_emit_ldloc (mb
, 0);
2066 if (t
== MONO_TYPE_CHAR
&& ntype
== MONO_NATIVE_U1
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
2068 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
2069 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
2071 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
2072 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
2075 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
2076 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
2079 case MONO_TYPE_VALUETYPE
: {
2080 int src_var
, dst_var
;
2082 if (ftype
->data
.klass
->enumtype
) {
2083 ftype
= mono_class_enum_basetype (ftype
->data
.klass
);
2087 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2088 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2090 /* save the old src pointer */
2091 mono_mb_emit_ldloc (mb
, 0);
2092 mono_mb_emit_stloc (mb
, src_var
);
2093 /* save the old dst pointer */
2094 mono_mb_emit_ldloc (mb
, 1);
2095 mono_mb_emit_stloc (mb
, dst_var
);
2097 emit_struct_conv (mb
, ftype
->data
.klass
, to_object
);
2099 /* restore the old src pointer */
2100 mono_mb_emit_ldloc (mb
, src_var
);
2101 mono_mb_emit_stloc (mb
, 0);
2102 /* restore the old dst pointer */
2103 mono_mb_emit_ldloc (mb
, dst_var
);
2104 mono_mb_emit_stloc (mb
, 1);
2107 case MONO_TYPE_OBJECT
: {
2110 static MonoMethod
*variant_clear
= NULL
;
2111 static MonoMethod
*get_object_for_native_variant
= NULL
;
2114 variant_clear
= mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2115 if (!get_object_for_native_variant
)
2116 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
2117 mono_mb_emit_ldloc (mb
, 1);
2118 mono_mb_emit_ldloc (mb
, 0);
2119 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
2120 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2122 mono_mb_emit_ldloc (mb
, 0);
2123 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
2126 static MonoMethod
*get_native_variant_for_object
= NULL
;
2128 if (!get_native_variant_for_object
)
2129 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
2131 mono_mb_emit_ldloc (mb
, 0);
2132 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
2133 mono_mb_emit_ldloc (mb
, 1);
2134 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
2137 char *msg
= g_strdup_printf ("COM support was disabled at compilation time.");
2138 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2144 g_warning ("marshaling type %02x not implemented", ftype
->type
);
2145 g_assert_not_reached ();
2150 int src_var
, dst_var
;
2152 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2153 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2155 /* save the old src pointer */
2156 mono_mb_emit_ldloc (mb
, 0);
2157 mono_mb_emit_stloc (mb
, src_var
);
2158 /* save the old dst pointer */
2159 mono_mb_emit_ldloc (mb
, 1);
2160 mono_mb_emit_stloc (mb
, dst_var
);
2163 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
2165 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
2167 /* restore the old src pointer */
2168 mono_mb_emit_ldloc (mb
, src_var
);
2169 mono_mb_emit_stloc (mb
, 0);
2170 /* restore the old dst pointer */
2171 mono_mb_emit_ldloc (mb
, dst_var
);
2172 mono_mb_emit_stloc (mb
, 1);
2177 mono_mb_emit_add_to_local (mb
, 0, usize
);
2178 mono_mb_emit_add_to_local (mb
, 1, msize
);
2180 mono_mb_emit_add_to_local (mb
, 0, msize
);
2181 mono_mb_emit_add_to_local (mb
, 1, usize
);
2187 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
2189 emit_struct_conv_full (mb
, klass
, to_object
, 0, (MonoMarshalNative
)-1);
2193 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
2195 /* Call DestroyStructure */
2196 /* FIXME: Only do this if needed */
2197 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2198 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
2199 mono_mb_emit_ldloc (mb
, struct_var
);
2200 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
2204 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, gpointer checkpoint_func
)
2206 int pos_noabort
, pos_noex
;
2208 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2209 mono_mb_emit_byte (mb
, CEE_MONO_LDPTR_INT_REQ_FLAG
);
2210 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
2211 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2213 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2214 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
2216 mono_mb_emit_icall (mb
, checkpoint_func
);
2217 /* Throw the exception returned by the checkpoint function, if any */
2218 mono_mb_emit_byte (mb
, CEE_DUP
);
2219 pos_noex
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2220 mono_mb_emit_byte (mb
, CEE_THROW
);
2221 mono_mb_patch_branch (mb
, pos_noex
);
2222 mono_mb_emit_byte (mb
, CEE_POP
);
2224 mono_mb_patch_branch (mb
, pos_noabort
);
2228 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2230 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
2233 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_interruption_checkpoint
);
2237 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2239 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_force_interruption_checkpoint_noraise
);
2243 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2245 emit_thread_interrupt_checkpoint (mb
);
2249 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2251 emit_thread_force_interrupt_checkpoint (mb
);
2254 #endif /* DISABLE_JIT */
2256 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
2257 static MonoAsyncResult
*
2258 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
2261 MonoMulticastDelegate
*mcast_delegate
;
2265 g_assert (delegate
);
2266 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
2267 if (mcast_delegate
->delegates
!= NULL
) {
2268 mono_set_pending_exception (mono_get_exception_argument (NULL
, "The delegate must have only one target"));
2272 #ifndef DISABLE_REMOTING
2273 if (delegate
->target
&& mono_object_class (delegate
->target
) == mono_defaults
.transparent_proxy_class
) {
2274 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
2275 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
2276 /* If the target is a proxy, make a direct call. Is proxy's work
2277 // to make the call asynchronous.
2279 MonoMethodMessage
*msg
;
2280 MonoDelegate
*async_callback
;
2282 MonoAsyncResult
*ares
;
2284 MonoArray
*out_args
;
2285 method
= delegate
->method
;
2287 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, &error
);
2288 if (mono_error_set_pending_exception (&error
))
2290 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, &error
);
2291 if (mono_error_set_pending_exception (&error
))
2293 MONO_OBJECT_SETREF (ares
, async_delegate
, (MonoObject
*)delegate
);
2294 MONO_OBJECT_SETREF (ares
, async_callback
, (MonoObject
*)async_callback
);
2295 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
2296 msg
->call_type
= CallType_BeginInvoke
;
2299 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, &error
);
2300 if (!mono_error_ok (&error
)) {
2301 mono_error_set_pending_exception (&error
);
2305 mono_set_pending_exception ((MonoException
*) exc
);
2311 klass
= delegate
->object
.vtable
->klass
;
2313 method
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
2315 method
= mono_get_delegate_invoke (klass
);
2318 MonoAsyncResult
*result
= mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, &error
);
2319 mono_error_set_pending_exception (&error
);
2326 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
2328 int i
, params_var
, tmp_var
;
2330 /* allocate local (pointer) *params[] */
2331 params_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2332 /* allocate local (pointer) tmp */
2333 tmp_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2335 /* alloate space on stack to store an array of pointers to the arguments */
2336 mono_mb_emit_icon (mb
, sizeof (gpointer
) * (sig
->param_count
+ 1));
2337 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2338 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2339 mono_mb_emit_stloc (mb
, params_var
);
2342 mono_mb_emit_ldloc (mb
, params_var
);
2343 mono_mb_emit_stloc (mb
, tmp_var
);
2345 if (save_this
&& sig
->hasthis
) {
2346 mono_mb_emit_ldloc (mb
, tmp_var
);
2347 mono_mb_emit_ldarg_addr (mb
, 0);
2348 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2349 /* tmp = tmp + sizeof (gpointer) */
2350 if (sig
->param_count
)
2351 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2355 for (i
= 0; i
< sig
->param_count
; i
++) {
2356 mono_mb_emit_ldloc (mb
, tmp_var
);
2357 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
2358 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2359 /* tmp = tmp + sizeof (gpointer) */
2360 if (i
< (sig
->param_count
- 1))
2361 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2367 #endif /* DISABLE_JIT */
2370 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
2374 GString
*res
= g_string_new ("");
2377 g_string_append (res
, prefix
);
2378 g_string_append_c (res
, '_');
2381 mono_type_get_desc (res
, sig
->ret
, FALSE
);
2384 g_string_append (res
, "__this__");
2386 for (i
= 0; i
< sig
->param_count
; ++i
) {
2387 g_string_append_c (res
, '_');
2388 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
2391 g_string_free (res
, FALSE
);
2396 * mono_marshal_get_string_encoding:
2398 * Return the string encoding which should be used for a given parameter.
2400 static MonoMarshalNative
2401 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2403 /* First try the parameter marshal info */
2405 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
2406 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
2407 return spec
->data
.array_data
.elem_type
;
2410 return spec
->native
;
2414 return MONO_NATIVE_LPSTR
;
2416 /* Then try the method level marshal info */
2417 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
2418 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
2419 return MONO_NATIVE_LPSTR
;
2420 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
2421 return MONO_NATIVE_LPWSTR
;
2422 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
2424 return MONO_NATIVE_LPWSTR
;
2426 return MONO_NATIVE_LPSTR
;
2429 return MONO_NATIVE_LPSTR
;
2433 static MonoMarshalConv
2434 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2436 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2439 case MONO_NATIVE_LPWSTR
:
2440 return MONO_MARSHAL_CONV_STR_LPWSTR
;
2441 case MONO_NATIVE_LPSTR
:
2442 case MONO_NATIVE_VBBYREFSTR
:
2443 return MONO_MARSHAL_CONV_STR_LPSTR
;
2444 case MONO_NATIVE_LPTSTR
:
2445 return MONO_MARSHAL_CONV_STR_LPTSTR
;
2446 case MONO_NATIVE_BSTR
:
2447 return MONO_MARSHAL_CONV_STR_BSTR
;
2449 return MONO_MARSHAL_CONV_INVALID
;
2453 static MonoMarshalConv
2454 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2456 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2459 case MONO_NATIVE_LPWSTR
:
2460 return MONO_MARSHAL_CONV_SB_LPWSTR
;
2462 case MONO_NATIVE_LPSTR
:
2463 return MONO_MARSHAL_CONV_SB_LPSTR
;
2465 case MONO_NATIVE_LPTSTR
:
2466 return MONO_MARSHAL_CONV_SB_LPTSTR
;
2469 return MONO_MARSHAL_CONV_INVALID
;
2473 static MonoMarshalConv
2474 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2476 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2481 case MONO_NATIVE_LPWSTR
:
2483 return MONO_MARSHAL_CONV_LPWSTR_STR
;
2484 case MONO_NATIVE_LPSTR
:
2485 case MONO_NATIVE_VBBYREFSTR
:
2486 return MONO_MARSHAL_CONV_LPSTR_STR
;
2487 case MONO_NATIVE_LPTSTR
:
2488 return MONO_MARSHAL_CONV_LPTSTR_STR
;
2489 case MONO_NATIVE_BSTR
:
2490 return MONO_MARSHAL_CONV_BSTR_STR
;
2492 return MONO_MARSHAL_CONV_INVALID
;
2496 static MonoMarshalConv
2497 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2499 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2504 case MONO_NATIVE_LPWSTR
:
2506 * mono_string_builder_to_utf16 does not allocate a
2507 * new buffer, so no need to free it.
2510 return MONO_MARSHAL_CONV_LPWSTR_SB
;
2511 case MONO_NATIVE_LPSTR
:
2512 return MONO_MARSHAL_CONV_LPSTR_SB
;
2514 case MONO_NATIVE_LPTSTR
:
2515 return MONO_MARSHAL_CONV_LPTSTR_SB
;
2518 return MONO_MARSHAL_CONV_INVALID
;
2523 * Return whenever a field of a native structure or an array member needs to
2527 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2529 MonoMarshalNative encoding
;
2532 case MONO_TYPE_VALUETYPE
:
2533 /* FIXME: Optimize this */
2535 case MONO_TYPE_OBJECT
:
2536 case MONO_TYPE_CLASS
:
2537 if (t
->data
.klass
== mono_defaults
.stringbuilder_class
) {
2539 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
2543 case MONO_TYPE_STRING
:
2544 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2545 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
2552 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
2555 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
2558 mono_marshal_lock ();
2561 g_hash_table_new (hash_func
, equal_func
);
2562 mono_memory_barrier ();
2565 mono_marshal_unlock ();
2571 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
2573 return get_cache (var
, hash_func
, equal_func
);
2577 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
2581 mono_marshal_lock ();
2582 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2583 mono_marshal_unlock ();
2590 * Create a MonoMethod from MB, set INFO as wrapper info.
2593 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2594 int max_stack
, WrapperInfo
*info
)
2598 res
= mono_mb_create_method (mb
, sig
, max_stack
);
2600 mono_marshal_set_wrapper_info (res
, info
);
2604 /* Create the method from the builder and place it in the cache */
2606 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
2607 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2608 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
2615 mono_marshal_lock ();
2616 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2617 mono_marshal_unlock ();
2620 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
2621 mono_marshal_lock ();
2622 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2625 g_hash_table_insert (cache
, key
, res
);
2626 mono_marshal_set_wrapper_info (res
, info
);
2627 mono_marshal_unlock ();
2631 mono_marshal_unlock ();
2632 mono_free_method (newm
);
2640 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
2641 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2644 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
2648 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
2651 int wrapper_type
= wrapper
->wrapper_type
;
2654 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2657 info
= mono_marshal_get_wrapper_info (wrapper
);
2659 switch (wrapper_type
) {
2660 case MONO_WRAPPER_REMOTING_INVOKE
:
2661 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
2662 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2663 m
= info
->d
.remoting
.method
;
2664 if (wrapper
->is_inflated
) {
2668 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
2669 * contains an uninflated method.
2671 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), &error
);
2672 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2676 case MONO_WRAPPER_SYNCHRONIZED
:
2677 m
= info
->d
.synchronized
.method
;
2678 if (wrapper
->is_inflated
) {
2681 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), &error
);
2682 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2686 case MONO_WRAPPER_UNBOX
:
2687 return info
->d
.unbox
.method
;
2688 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
2689 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
2690 return info
->d
.managed_to_native
.method
;
2693 case MONO_WRAPPER_RUNTIME_INVOKE
:
2694 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
2695 return info
->d
.runtime_invoke
.method
;
2698 case MONO_WRAPPER_DELEGATE_INVOKE
:
2700 return info
->d
.delegate_invoke
.method
;
2709 * mono_marshal_get_wrapper_info:
2711 * Retrieve the WrapperInfo structure associated with WRAPPER.
2714 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
2716 g_assert (wrapper
->wrapper_type
);
2718 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
2722 * mono_marshal_set_wrapper_info:
2724 * Set the WrapperInfo structure associated with the wrapper
2725 * method METHOD to INFO.
2728 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
2732 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2735 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
2740 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
2744 info
= (WrapperInfo
*)mono_image_alloc0 (mb
->method
->klass
->image
, sizeof (WrapperInfo
));
2745 info
->subtype
= subtype
;
2750 * get_wrapper_target_class:
2752 * Return the class where a wrapper method should be placed.
2755 get_wrapper_target_class (MonoImage
*image
)
2762 * - can't put all wrappers into an mscorlib class, because they reference
2763 * metadata (signature) so they should be put into the same image as the
2764 * method they wrap, so they are unloaded together.
2765 * - putting them into a class with a type initalizer could cause the
2766 * initializer to be executed which can be a problem if the wrappers are
2768 * - putting them into an inflated class can cause problems if the the
2769 * class is deleted because it references an image which is unloaded.
2770 * To avoid these problems, we put the wrappers into the <Module> class of
2773 if (image_is_dynamic (image
)) {
2774 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
2776 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), &error
);
2777 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2785 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
2786 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
2790 * check_generic_wrapper_cache:
2792 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
2793 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
2794 * generic method definition.
2797 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
2800 MonoMethod
*inst
, *def
;
2801 MonoGenericContext
*ctx
;
2803 g_assert (orig_method
->is_inflated
);
2804 ctx
= mono_method_get_context (orig_method
);
2807 * Look for the instance
2809 res
= mono_marshal_find_in_cache (cache
, key
);
2814 * Look for the definition
2816 def
= mono_marshal_find_in_cache (cache
, def_key
);
2819 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
2820 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2822 mono_memory_barrier ();
2823 mono_marshal_lock ();
2824 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2826 g_hash_table_insert (cache
, key
, inst
);
2829 mono_marshal_unlock ();
2836 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
2839 MonoMethod
*inst
, *res
;
2842 * We use the same cache for the generic definition and the instances.
2844 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
2845 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2846 mono_memory_barrier ();
2847 mono_marshal_lock ();
2848 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2850 g_hash_table_insert (cache
, key
, inst
);
2853 mono_marshal_unlock ();
2858 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
2862 MonoMethod
*inst
, *def
;
2865 * Look for the instance
2867 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
2872 * Look for the definition
2874 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
2876 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
2877 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2880 mono_memory_barrier ();
2881 mono_marshal_lock ();
2882 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
2884 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
2887 mono_marshal_unlock ();
2894 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
2897 MonoMethod
*inst
, *res
;
2900 * We use the same cache for the generic definition and the instances.
2902 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
2903 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2905 mono_memory_barrier ();
2906 mono_marshal_lock ();
2907 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
2909 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
2912 mono_marshal_unlock ();
2917 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
2919 MonoMethodSignature
*sig
;
2920 MonoMethodBuilder
*mb
;
2925 MonoGenericContext
*ctx
= NULL
;
2926 MonoMethod
*orig_method
= NULL
;
2928 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
2929 !strcmp (method
->name
, "BeginInvoke"));
2932 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
2934 if (method
->is_inflated
) {
2935 orig_method
= method
;
2936 ctx
= &((MonoMethodInflated
*)method
)->context
;
2937 method
= ((MonoMethodInflated
*)method
)->declaring
;
2940 sig
= mono_signature_no_pinvoke (method
);
2946 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2947 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
2951 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.delegate_begin_invoke_cache
,
2952 (GHashFunc
)mono_signature_hash
,
2953 (GCompareFunc
)mono_metadata_signature_equal
);
2954 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2958 g_assert (sig
->hasthis
);
2960 name
= mono_signature_to_name (sig
, "begin_invoke");
2962 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
2964 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
2968 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
2970 mono_mb_emit_ldarg (mb
, 0);
2971 mono_mb_emit_ldloc (mb
, params_var
);
2972 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
2973 mono_mb_emit_byte (mb
, CEE_RET
);
2978 def
= mono_mb_create_and_cache (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16);
2979 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
2981 res
= mono_mb_create_and_cache (cache
, sig
, mb
, sig
, sig
->param_count
+ 16);
2988 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
2990 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
2993 MonoDomain
*domain
= mono_domain_get ();
2994 MonoAsyncResult
*ares
;
2995 MonoMethod
*method
= NULL
;
2996 MonoMethodSignature
*sig
;
2997 MonoMethodMessage
*msg
;
2998 MonoObject
*res
, *exc
;
2999 MonoArray
*out_args
;
3002 g_assert (delegate
);
3004 if (!delegate
->method_info
) {
3005 g_assert (delegate
->method
);
3006 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, &error
);
3007 if (!mono_error_ok (&error
)) {
3008 mono_error_set_pending_exception (&error
);
3011 MONO_OBJECT_SETREF (delegate
, method_info
, rm
);
3014 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
3015 g_assert_not_reached ();
3017 klass
= delegate
->object
.vtable
->klass
;
3019 method
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
3020 g_assert (method
!= NULL
);
3022 sig
= mono_signature_no_pinvoke (method
);
3024 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, &error
);
3025 if (mono_error_set_pending_exception (&error
))
3028 ares
= (MonoAsyncResult
*)mono_array_get (msg
->args
, gpointer
, sig
->param_count
- 1);
3030 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."));
3034 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
3035 mono_set_pending_exception (mono_get_exception_invalid_operation (
3036 "The IAsyncResult object provided does not match this delegate."));
3040 #ifndef DISABLE_REMOTING
3041 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
3042 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
3043 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, &error
);
3044 if (!mono_error_ok (&error
)) {
3045 mono_error_set_pending_exception (&error
);
3048 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, &error
);
3049 if (mono_error_set_pending_exception (&error
))
3051 msg
->call_type
= CallType_EndInvoke
;
3052 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
3053 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, &error
);
3054 if (!mono_error_ok (&error
)) {
3055 mono_error_set_pending_exception (&error
);
3061 res
= mono_threadpool_ms_end_invoke (ares
, &out_args
, &exc
, &error
);
3062 if (mono_error_set_pending_exception (&error
))
3067 if (((MonoException
*)exc
)->stack_trace
) {
3068 MonoError inner_error
;
3069 char *strace
= mono_string_to_utf8_checked (((MonoException
*)exc
)->stack_trace
, &inner_error
);
3070 if (is_ok (&inner_error
)) {
3072 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
3074 MONO_OBJECT_SETREF (((MonoException
*)exc
), stack_trace
, mono_string_new (domain
, tmp
));
3077 mono_error_cleanup (&inner_error
); /* no stack trace, but at least throw the original exception */
3079 mono_set_pending_exception ((MonoException
*)exc
);
3082 mono_method_return_message_restore (method
, params
, out_args
, &error
);
3083 mono_error_set_pending_exception (&error
);
3090 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
3092 MonoType
*t
= mono_type_get_underlying_type (return_type
);
3094 if (return_type
->byref
)
3095 return_type
= &mono_defaults
.int_class
->byval_arg
;
3098 case MONO_TYPE_VOID
:
3099 g_assert_not_reached ();
3102 case MONO_TYPE_STRING
:
3103 case MONO_TYPE_CLASS
:
3104 case MONO_TYPE_OBJECT
:
3105 case MONO_TYPE_ARRAY
:
3106 case MONO_TYPE_SZARRAY
:
3110 case MONO_TYPE_BOOLEAN
:
3113 case MONO_TYPE_CHAR
:
3123 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (return_type
));
3124 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
3126 case MONO_TYPE_GENERICINST
:
3127 if (!mono_type_generic_inst_is_valuetype (t
))
3130 case MONO_TYPE_VALUETYPE
: {
3131 MonoClass
*klass
= mono_class_from_mono_type (return_type
);
3132 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
3133 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
3137 case MONO_TYPE_MVAR
: {
3138 MonoClass
*klass
= mono_class_from_mono_type (return_type
);
3139 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, klass
);
3143 g_warning ("type 0x%x not handled", return_type
->type
);
3144 g_assert_not_reached ();
3147 mono_mb_emit_byte (mb
, CEE_RET
);
3150 #endif /* DISABLE_JIT */
3153 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
3155 MonoMethodSignature
*sig
;
3156 MonoMethodBuilder
*mb
;
3161 MonoGenericContext
*ctx
= NULL
;
3162 MonoMethod
*orig_method
= NULL
;
3164 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3165 !strcmp (method
->name
, "EndInvoke"));
3168 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
3170 if (method
->is_inflated
) {
3171 orig_method
= method
;
3172 ctx
= &((MonoMethodInflated
*)method
)->context
;
3173 method
= ((MonoMethodInflated
*)method
)->declaring
;
3176 sig
= mono_signature_no_pinvoke (method
);
3182 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
3183 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
3187 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.delegate_end_invoke_cache
,
3188 (GHashFunc
)mono_signature_hash
,
3189 (GCompareFunc
)mono_metadata_signature_equal
);
3190 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
3194 g_assert (sig
->hasthis
);
3196 name
= mono_signature_to_name (sig
, "end_invoke");
3198 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
3200 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
3204 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3206 mono_mb_emit_ldarg (mb
, 0);
3207 mono_mb_emit_ldloc (mb
, params_var
);
3208 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
3210 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
3211 mono_mb_emit_byte (mb
, CEE_POP
);
3212 mono_mb_emit_byte (mb
, CEE_RET
);
3214 mono_mb_emit_restore_result (mb
, sig
->ret
);
3219 def
= mono_mb_create_and_cache (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16);
3220 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
3222 res
= mono_mb_create_and_cache (cache
, sig
,
3223 mb
, sig
, sig
->param_count
+ 16);
3232 MonoMethodSignature
*sig
;
3234 } SignaturePointerPair
;
3237 signature_pointer_pair_hash (gconstpointer data
)
3239 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
3241 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
3245 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
3247 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
3248 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
3252 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
3254 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
3256 return pair
->pointer
== user_data
;
3260 free_signature_pointer_pair (SignaturePointerPair
*pair
)
3266 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
3268 MonoMethodSignature
*sig
, *static_sig
, *invoke_sig
;
3270 MonoMethodBuilder
*mb
;
3273 gpointer cache_key
= NULL
;
3274 SignaturePointerPair key
;
3275 SignaturePointerPair
*new_key
;
3276 int local_i
, local_len
, local_delegates
, local_d
, local_target
, local_res
;
3277 int pos0
, pos1
, pos2
;
3279 MonoClass
*target_class
= NULL
;
3280 gboolean closed_over_null
= FALSE
;
3281 MonoGenericContext
*ctx
= NULL
;
3282 MonoGenericContainer
*container
= NULL
;
3283 MonoMethod
*orig_method
= method
;
3285 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
3289 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3290 !strcmp (method
->name
, "Invoke"));
3292 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
3295 * If the delegate target is null, and the target method is not static, a virtual
3296 * call is made to that method with the first delegate argument as this. This is
3297 * a non-documented .NET feature.
3300 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
3301 if (target_method
->is_inflated
) {
3303 MonoType
*target_type
;
3305 g_assert (method
->signature
->hasthis
);
3306 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
3307 mono_method_get_context (method
), &error
);
3308 mono_error_assert_ok (&error
); /* FIXME don't swallow the error */
3309 target_class
= mono_class_from_mono_type (target_type
);
3311 target_class
= target_method
->klass
;
3314 closed_over_null
= sig
->param_count
== mono_method_signature (target_method
)->param_count
;
3317 if (static_method_with_first_arg_bound
) {
3318 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
3319 g_assert (!callvirt
);
3320 invoke_sig
= mono_method_signature (target_method
);
3324 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
3326 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
3327 ctx
= &((MonoMethodInflated
*)method
)->context
;
3328 method
= ((MonoMethodInflated
*)method
)->declaring
;
3330 container
= mono_method_get_generic_container (method
);
3332 container
= method
->klass
->generic_container
;
3333 g_assert (container
);
3335 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
3342 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
3343 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
3346 cache_key
= method
->klass
;
3347 } else if (static_method_with_first_arg_bound
) {
3348 cache
= get_cache (&method
->klass
->image
->delegate_bound_static_invoke_cache
,
3349 (GHashFunc
)mono_signature_hash
,
3350 (GCompareFunc
)mono_metadata_signature_equal
);
3352 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
3354 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
3357 cache_key
= invoke_sig
;
3358 } else if (callvirt
) {
3359 GHashTable
**cache_ptr
;
3361 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
3363 /* We need to cache the signature+method pair */
3364 mono_marshal_lock ();
3366 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
3368 key
.sig
= invoke_sig
;
3369 key
.pointer
= target_method
;
3370 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
3371 mono_marshal_unlock ();
3375 // Inflated methods should not be in this cache because it's not stored on the imageset.
3376 g_assert (!method
->is_inflated
);
3377 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.delegate_invoke_cache
,
3378 (GHashFunc
)mono_signature_hash
,
3379 (GCompareFunc
)mono_metadata_signature_equal
);
3380 res
= mono_marshal_find_in_cache (cache
, sig
);
3386 static_sig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
3387 static_sig
->hasthis
= 0;
3388 if (!static_method_with_first_arg_bound
)
3389 invoke_sig
= static_sig
;
3391 if (static_method_with_first_arg_bound
)
3392 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
3393 else if (closed_over_null
)
3394 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
3396 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
3398 name
= mono_signature_to_name (invoke_sig
, "invoke");
3400 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
3402 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
3406 void_ret
= sig
->ret
->type
== MONO_TYPE_VOID
&& !method
->string_ctor
;
3408 /* allocate local 0 (object) */
3409 local_i
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
3410 local_len
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
3411 local_delegates
= mono_mb_add_local (mb
, &mono_defaults
.array_class
->byval_arg
);
3412 local_d
= mono_mb_add_local (mb
, &mono_defaults
.multicastdelegate_class
->byval_arg
);
3413 local_target
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3416 local_res
= mono_mb_add_local (mb
, &mono_class_from_mono_type (sig
->ret
)->byval_arg
);
3418 g_assert (sig
->hasthis
);
3421 * {type: sig->ret} res;
3422 * if (delegates == null) {
3423 * return this.<target> ( args .. );
3425 * int i = 0, len = this.delegates.Length;
3427 * res = this.delegates [i].Invoke ( args .. );
3428 * } while (++i < len);
3433 /* this wrapper can be used in unmanaged-managed transitions */
3434 emit_thread_interrupt_checkpoint (mb
);
3436 /* delegates = this.delegates */
3437 mono_mb_emit_ldarg (mb
, 0);
3438 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoMulticastDelegate
, delegates
));
3439 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3440 mono_mb_emit_stloc (mb
, local_delegates
);
3442 /* if (delegates == null) */
3443 mono_mb_emit_ldloc (mb
, local_delegates
);
3444 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3446 /* return target.<target_method|method_ptr> ( args .. ); */
3448 /* target = d.target; */
3449 mono_mb_emit_ldarg (mb
, 0);
3450 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
3451 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3452 mono_mb_emit_stloc (mb
, local_target
);
3454 /*static methods with bound first arg can have null target and still be bound*/
3455 if (!static_method_with_first_arg_bound
) {
3456 /* if target != null */
3457 mono_mb_emit_ldloc (mb
, local_target
);
3458 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3460 /* then call this->method_ptr nonstatic */
3463 mono_mb_emit_exception_full (mb
, "System", "NotImplementedException", "");
3465 mono_mb_emit_ldloc (mb
, local_target
);
3466 for (i
= 0; i
< sig
->param_count
; ++i
)
3467 mono_mb_emit_ldarg (mb
, i
+ 1);
3468 mono_mb_emit_ldarg (mb
, 0);
3469 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3470 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3471 mono_mb_emit_ldarg (mb
, 0);
3472 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
3473 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3474 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3475 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, sig
);
3476 mono_mb_emit_byte (mb
, CEE_RET
);
3479 /* else [target == null] call this->method_ptr static */
3480 mono_mb_patch_branch (mb
, pos0
);
3484 if (!closed_over_null
) {
3485 if (target_class
->valuetype
) {
3486 mono_mb_emit_ldarg (mb
, 1);
3487 for (i
= 1; i
< sig
->param_count
; ++i
)
3488 mono_mb_emit_ldarg (mb
, i
+ 1);
3489 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3491 mono_mb_emit_ldarg (mb
, 1);
3492 mono_mb_emit_op (mb
, CEE_CASTCLASS
, target_class
);
3493 for (i
= 1; i
< sig
->param_count
; ++i
)
3494 mono_mb_emit_ldarg (mb
, i
+ 1);
3495 mono_mb_emit_op (mb
, CEE_CALLVIRT
, target_method
);
3498 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3499 for (i
= 0; i
< sig
->param_count
; ++i
)
3500 mono_mb_emit_ldarg (mb
, i
+ 1);
3501 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3504 if (static_method_with_first_arg_bound
) {
3505 mono_mb_emit_ldloc (mb
, local_target
);
3506 if (!MONO_TYPE_IS_REFERENCE (invoke_sig
->params
[0]))
3507 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type (invoke_sig
->params
[0]));
3509 for (i
= 0; i
< sig
->param_count
; ++i
)
3510 mono_mb_emit_ldarg (mb
, i
+ 1);
3511 mono_mb_emit_ldarg (mb
, 0);
3512 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3513 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3514 mono_mb_emit_ldarg (mb
, 0);
3515 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
3516 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3517 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3518 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, invoke_sig
);
3521 mono_mb_emit_byte (mb
, CEE_RET
);
3523 /* else [delegates != null] */
3524 mono_mb_patch_branch (mb
, pos2
);
3526 /* len = delegates.Length; */
3527 mono_mb_emit_ldloc (mb
, local_delegates
);
3528 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3529 mono_mb_emit_byte (mb
, CEE_CONV_I4
);
3530 mono_mb_emit_stloc (mb
, local_len
);
3533 mono_mb_emit_icon (mb
, 0);
3534 mono_mb_emit_stloc (mb
, local_i
);
3536 pos1
= mono_mb_get_label (mb
);
3538 /* d = delegates [i]; */
3539 mono_mb_emit_ldloc (mb
, local_delegates
);
3540 mono_mb_emit_ldloc (mb
, local_i
);
3541 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3542 mono_mb_emit_stloc (mb
, local_d
);
3544 /* res = d.Invoke ( args .. ); */
3545 mono_mb_emit_ldloc (mb
, local_d
);
3546 for (i
= 0; i
< sig
->param_count
; i
++)
3547 mono_mb_emit_ldarg (mb
, i
+ 1);
3549 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
3552 mono_mb_emit_op (mb
, CEE_CALLVIRT
, mono_class_inflate_generic_method_checked (method
, &container
->context
, &error
));
3553 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
3556 mono_mb_emit_stloc (mb
, local_res
);
3559 mono_mb_emit_add_to_local (mb
, local_i
, 1);
3562 mono_mb_emit_ldloc (mb
, local_i
);
3563 mono_mb_emit_ldloc (mb
, local_len
);
3564 mono_mb_emit_branch_label (mb
, CEE_BLT
, pos1
);
3568 mono_mb_emit_ldloc (mb
, local_res
);
3569 mono_mb_emit_byte (mb
, CEE_RET
);
3571 mb
->skip_visibility
= 1;
3572 #endif /* DISABLE_JIT */
3574 info
= mono_wrapper_info_create (mb
, subtype
);
3575 info
->d
.delegate_invoke
.method
= orig_method
;
3580 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
3581 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
3582 } else if (callvirt
) {
3583 new_key
= g_new0 (SignaturePointerPair
, 1);
3586 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
3590 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
3594 /* mono_method_print_code (res); */
3600 * the returned method invokes all methods in a multicast delegate.
3603 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
3605 gboolean callvirt
= FALSE
;
3606 gboolean static_method_with_first_arg_bound
= FALSE
;
3607 MonoMethod
*target_method
= NULL
;
3608 MonoMethodSignature
*sig
;
3610 sig
= mono_signature_no_pinvoke (method
);
3612 if (del
&& !del
->target
&& del
->method
&& mono_method_signature (del
->method
)->hasthis
) {
3614 target_method
= del
->method
;
3617 if (del
&& del
->method
&& mono_method_signature (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
3618 static_method_with_first_arg_bound
= TRUE
;
3619 target_method
= del
->method
;
3622 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
3626 MonoMethodSignature
*ctor_sig
;
3627 MonoMethodSignature
*sig
;
3630 /* protected by the marshal lock, contains CtorSigPair pointers */
3631 static GSList
*strsig_list
= NULL
;
3633 static MonoMethodSignature
*
3634 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
3636 MonoMethodSignature
*callsig
;
3640 mono_marshal_lock ();
3642 for (item
= strsig_list
; item
; item
= item
->next
) {
3643 cs
= (CtorSigPair
*)item
->data
;
3644 /* mono_metadata_signature_equal () is safe to call with the marshal lock
3645 * because it is lock-free.
3647 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
3652 mono_marshal_unlock ();
3656 static MonoMethodSignature
*
3657 add_string_ctor_signature (MonoMethod
*method
)
3659 MonoMethodSignature
*callsig
;
3662 callsig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
3663 callsig
->ret
= &mono_defaults
.string_class
->byval_arg
;
3664 cs
= g_new (CtorSigPair
, 1);
3666 cs
->ctor_sig
= mono_method_signature (method
);
3668 mono_marshal_lock ();
3669 strsig_list
= g_slist_prepend (strsig_list
, cs
);
3670 mono_marshal_unlock ();
3675 * mono_marshal_get_string_ctor_signature:
3677 * Return the modified signature used by string ctors (they return the newly created
3680 MonoMethodSignature
*
3681 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
3683 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature (method
));
3685 sig
= add_string_ctor_signature (method
);
3691 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
3694 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
3696 /* Can't share this with 'I' as that needs another indirection */
3697 return &mono_defaults
.int_class
->this_arg
;
3700 if (MONO_TYPE_IS_REFERENCE (t
))
3701 return &mono_defaults
.object_class
->byval_arg
;
3704 /* The result needs to be boxed */
3709 /* Can't share these as the argument needs to be loaded using sign/zero extension */
3712 return &mono_defaults.sbyte_class->byval_arg;
3714 return &mono_defaults.int16_class->byval_arg;
3716 return &mono_defaults.int32_class->byval_arg;
3719 return &mono_defaults
.int64_class
->byval_arg
;
3720 case MONO_TYPE_BOOLEAN
:
3721 return &mono_defaults
.byte_class
->byval_arg
;
3722 case MONO_TYPE_CHAR
:
3723 return &mono_defaults
.uint16_class
->byval_arg
;
3725 return &mono_defaults
.int_class
->byval_arg
;
3726 case MONO_TYPE_VALUETYPE
:
3727 if (t
->data
.klass
->enumtype
) {
3728 t
= mono_class_enum_basetype (t
->data
.klass
);
3738 * mono_marshal_get_runtime_invoke_sig:
3740 * Return a common signature used for sharing runtime invoke wrappers.
3742 static MonoMethodSignature
*
3743 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
3745 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
3748 res
->generic_param_count
= 0;
3749 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
3750 for (i
= 0; i
< res
->param_count
; ++i
)
3751 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
3757 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
3759 /* Can't share wrappers which return a vtype since it needs to be boxed */
3760 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
))
3763 return mono_metadata_signature_equal (sig1
, sig2
);
3771 * Emit the call to the wrapper method from a runtime invoke wrapper.
3774 emit_invoke_call (MonoMethodBuilder
*mb
, MonoMethod
*method
,
3775 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
3777 gboolean virtual_
, gboolean need_direct_wrapper
)
3779 static MonoString
*string_dummy
= NULL
;
3781 int *tmp_nullable_locals
;
3782 gboolean void_ret
= FALSE
;
3783 gboolean string_ctor
= method
&& method
->string_ctor
;
3785 /* to make it work with our special string constructors */
3786 if (!string_dummy
) {
3787 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy
, MONO_ROOT_SOURCE_MARSHAL
, "dummy marshal string");
3788 string_dummy
= mono_string_new_wrapper ("dummy");
3792 g_assert (sig
->hasthis
);
3793 g_assert (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
);
3798 if (mono_gc_is_moving ()) {
3799 mono_mb_emit_ptr (mb
, &string_dummy
);
3800 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3802 mono_mb_emit_ptr (mb
, string_dummy
);
3805 mono_mb_emit_ldarg (mb
, 0);
3809 tmp_nullable_locals
= g_new0 (int, sig
->param_count
);
3811 for (i
= 0; i
< sig
->param_count
; i
++) {
3812 MonoType
*t
= sig
->params
[i
];
3815 mono_mb_emit_ldarg (mb
, 1);
3817 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
3818 mono_mb_emit_byte (mb
, CEE_ADD
);
3822 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3823 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
3824 * So to make this work we unbox it to a local variablee and push a reference to that.
3826 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
3827 tmp_nullable_locals
[i
] = mono_mb_add_local (mb
, &mono_class_from_mono_type (t
)->byval_arg
);
3829 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type (t
));
3830 mono_mb_emit_stloc (mb
, tmp_nullable_locals
[i
]);
3831 mono_mb_emit_ldloc_addr (mb
, tmp_nullable_locals
[i
]);
3836 /*FIXME 'this doesn't handle generic enums. Shouldn't we?*/
3837 type
= sig
->params
[i
]->type
;
3841 case MONO_TYPE_BOOLEAN
:
3845 case MONO_TYPE_CHAR
:
3854 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3855 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
3857 case MONO_TYPE_STRING
:
3858 case MONO_TYPE_CLASS
:
3859 case MONO_TYPE_ARRAY
:
3861 case MONO_TYPE_SZARRAY
:
3862 case MONO_TYPE_OBJECT
:
3863 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
3865 case MONO_TYPE_GENERICINST
:
3866 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
3867 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
3872 case MONO_TYPE_VALUETYPE
:
3873 if (type
== MONO_TYPE_VALUETYPE
&& t
->data
.klass
->enumtype
) {
3874 type
= mono_class_enum_basetype (t
->data
.klass
)->type
;
3877 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3878 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->params
[i
]))) {
3879 /* Need to convert a boxed vtype to an mp to a Nullable struct */
3880 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (sig
->params
[i
]));
3881 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
3883 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
3887 g_assert_not_reached ();
3892 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
3893 } else if (need_direct_wrapper
) {
3894 mono_mb_emit_op (mb
, CEE_CALL
, method
);
3896 mono_mb_emit_ldarg (mb
, 3);
3897 mono_mb_emit_calli (mb
, callsig
);
3900 if (sig
->ret
->byref
) {
3902 g_assert_not_reached ();
3905 switch (sig
->ret
->type
) {
3906 case MONO_TYPE_VOID
:
3910 case MONO_TYPE_BOOLEAN
:
3911 case MONO_TYPE_CHAR
:
3924 case MONO_TYPE_VALUETYPE
:
3925 case MONO_TYPE_TYPEDBYREF
:
3926 case MONO_TYPE_GENERICINST
:
3927 /* box value types */
3928 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
3930 case MONO_TYPE_STRING
:
3931 case MONO_TYPE_CLASS
:
3932 case MONO_TYPE_ARRAY
:
3933 case MONO_TYPE_SZARRAY
:
3934 case MONO_TYPE_OBJECT
:
3938 /* The result is an IntPtr */
3939 mono_mb_emit_op (mb
, CEE_BOX
, mono_defaults
.int_class
);
3942 g_assert_not_reached ();
3946 mono_mb_emit_stloc (mb
, loc_res
);
3948 /* Convert back nullable-byref arguments */
3949 for (i
= 0; i
< sig
->param_count
; i
++) {
3950 MonoType
*t
= sig
->params
[i
];
3953 * Box the result and put it back into the array, the caller will have
3954 * to obtain it from there.
3956 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
3957 mono_mb_emit_ldarg (mb
, 1);
3958 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
3959 mono_mb_emit_byte (mb
, CEE_ADD
);
3961 mono_mb_emit_ldloc (mb
, tmp_nullable_locals
[i
]);
3962 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
3964 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3968 g_free (tmp_nullable_locals
);
3972 emit_runtime_invoke_body (MonoMethodBuilder
*mb
, MonoImage
*image
, MonoMethod
*method
,
3973 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
3974 gboolean virtual_
, gboolean need_direct_wrapper
)
3977 MonoExceptionClause
*clause
;
3978 int loc_res
, loc_exc
;
3980 /* The wrapper looks like this:
3986 * } catch (Exception e) {
3994 /* allocate local 0 (object) tmp */
3995 loc_res
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3996 /* allocate local 1 (object) exc */
3997 loc_exc
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3999 /* *exc is assumed to be initialized to NULL by the caller */
4001 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4002 labels
[0] = mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4007 labels
[1] = mono_mb_get_label (mb
);
4008 emit_thread_force_interrupt_checkpoint (mb
);
4009 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
4011 labels
[2] = mono_mb_emit_branch (mb
, CEE_LEAVE
);
4013 /* Add a try clause around the call */
4014 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
4015 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4016 clause
->data
.catch_class
= mono_defaults
.exception_class
;
4017 clause
->try_offset
= labels
[1];
4018 clause
->try_len
= mono_mb_get_label (mb
) - labels
[1];
4020 clause
->handler_offset
= mono_mb_get_label (mb
);
4023 mono_mb_emit_stloc (mb
, loc_exc
);
4024 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4025 mono_mb_emit_ldloc (mb
, loc_exc
);
4026 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4028 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4030 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4032 mono_mb_set_clauses (mb
, 1, clause
);
4034 mono_mb_patch_branch (mb
, labels
[2]);
4035 mono_mb_emit_ldloc (mb
, loc_res
);
4036 mono_mb_emit_byte (mb
, CEE_RET
);
4041 mono_mb_patch_branch (mb
, labels
[0]);
4042 emit_thread_force_interrupt_checkpoint (mb
);
4043 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
4045 mono_mb_emit_ldloc (mb
, 0);
4046 mono_mb_emit_byte (mb
, CEE_RET
);
4051 * generates IL code for the runtime invoke function
4052 * MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)
4054 * we also catch exceptions if exc != null
4055 * If VIRTUAL is TRUE, then METHOD is invoked virtually on THIS. This is useful since
4056 * it means that the compiled code for METHOD does not have to be looked up
4057 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
4058 * its METHOD argument.
4061 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
4063 MonoMethodSignature
*sig
, *csig
, *callsig
;
4064 MonoMethodBuilder
*mb
;
4065 GHashTable
*cache
= NULL
;
4066 MonoClass
*target_klass
;
4067 MonoMethod
*res
= NULL
;
4068 static MonoMethodSignature
*cctor_signature
= NULL
;
4069 static MonoMethodSignature
*finalize_signature
= NULL
;
4071 const char *param_names
[16];
4072 gboolean need_direct_wrapper
= FALSE
;
4077 if (!cctor_signature
) {
4078 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4079 cctor_signature
->ret
= &mono_defaults
.void_class
->byval_arg
;
4081 if (!finalize_signature
) {
4082 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4083 finalize_signature
->ret
= &mono_defaults
.void_class
->byval_arg
;
4084 finalize_signature
->hasthis
= 1;
4088 need_direct_wrapper
= TRUE
;
4091 * Use a separate cache indexed by methods to speed things up and to avoid the
4092 * boundless mempool growth caused by the signature_dup stuff below.
4095 cache
= get_cache (&method
->klass
->image
->runtime_invoke_vcall_cache
, mono_aligned_addr_hash
, NULL
);
4097 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->runtime_invoke_direct_cache
, mono_aligned_addr_hash
, NULL
);
4099 res
= mono_marshal_find_in_cache (cache
, method
);
4103 if (method
->klass
->rank
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
4104 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
4106 * Array Get/Set/Address methods. The JIT implements them using inline code
4107 * so we need to create an invoke wrapper which calls the method directly.
4109 need_direct_wrapper
= TRUE
;
4112 if (method
->string_ctor
) {
4113 callsig
= lookup_string_ctor_signature (mono_method_signature (method
));
4115 callsig
= add_string_ctor_signature (method
);
4116 /* Can't share this as we push a string as this */
4117 need_direct_wrapper
= TRUE
;
4119 if (method_is_dynamic (method
))
4120 callsig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
4122 callsig
= mono_method_signature (method
);
4125 sig
= mono_method_signature (method
);
4127 target_klass
= get_wrapper_target_class (method
->klass
->image
);
4129 /* Try to share wrappers for non-corlib methods with simple signatures */
4130 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
4131 callsig
= cctor_signature
;
4132 target_klass
= mono_defaults
.object_class
;
4133 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
4134 callsig
= finalize_signature
;
4135 target_klass
= mono_defaults
.object_class
;
4138 if (need_direct_wrapper
) {
4139 /* Already searched at the start */
4141 MonoMethodSignature
*tmp_sig
;
4143 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
4144 GHashTable
**cache_table
= NULL
;
4146 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
)
4147 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_vtype_cache
;
4149 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_cache
;
4151 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
4152 (GCompareFunc
)runtime_invoke_signature_equal
);
4154 /* from mono_marshal_find_in_cache */
4155 mono_marshal_lock ();
4156 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4157 mono_marshal_unlock ();
4164 /* Make a copy of the signature from the image mempool */
4166 callsig
= mono_metadata_signature_dup_full (target_klass
->image
, callsig
);
4170 csig
= mono_metadata_signature_alloc (target_klass
->image
, 4);
4172 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4173 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
)
4174 csig
->params
[0] = get_runtime_invoke_type (&method
->klass
->this_arg
, FALSE
);
4176 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4177 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4178 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4179 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4182 /* This is called from runtime code so it has to be cdecl */
4183 csig
->call_convention
= MONO_CALL_C
;
4186 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : "runtime_invoke");
4187 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4191 param_names
[0] = "this";
4192 param_names
[1] = "params";
4193 param_names
[2] = "exc";
4194 param_names
[3] = "method";
4195 mono_mb_set_param_names (mb
, param_names
);
4197 emit_runtime_invoke_body (mb
, target_klass
->image
, method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
4200 if (need_direct_wrapper
) {
4202 mb
->skip_visibility
= 1;
4204 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
4205 info
->d
.runtime_invoke
.method
= method
;
4206 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
4208 /* taken from mono_mb_create_and_cache */
4209 mono_marshal_lock ();
4210 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4211 mono_marshal_unlock ();
4213 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
4214 info
->d
.runtime_invoke
.sig
= callsig
;
4216 /* Somebody may have created it before us */
4219 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
4221 mono_marshal_lock ();
4222 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4224 GHashTable
*direct_cache
;
4226 g_hash_table_insert (cache
, callsig
, res
);
4227 /* Can't insert it into wrapper_hash since the key is a signature */
4228 direct_cache
= mono_method_get_wrapper_cache (method
)->runtime_invoke_direct_cache
;
4230 g_hash_table_insert (direct_cache
, method
, res
);
4232 mono_free_method (newm
);
4234 mono_marshal_unlock ();
4237 /* end mono_mb_create_and_cache */
4246 * mono_marshal_get_runtime_invoke_dynamic:
4248 * Return a method which can be used to invoke managed methods from native code
4250 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
4251 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
4252 * ARGS should point to an architecture specific structure containing
4253 * the arguments and space for the return value.
4254 * The other arguments are the same as for runtime_invoke (), except that
4255 * ARGS should contain the this argument too.
4256 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
4257 * is only one copy of it, which is useful in full-aot.
4260 mono_marshal_get_runtime_invoke_dynamic (void)
4262 static MonoMethod
*method
;
4263 MonoMethodSignature
*csig
;
4264 MonoExceptionClause
*clause
;
4265 MonoMethodBuilder
*mb
;
4273 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
4275 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
4276 csig
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
4277 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4278 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4279 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4281 name
= g_strdup ("runtime_invoke_dynamic");
4282 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4286 /* allocate local 0 (object) tmp */
4287 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4288 /* allocate local 1 (object) exc */
4289 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4291 /* cond set *exc to null */
4292 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4293 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
4294 mono_mb_emit_byte (mb
, 3);
4295 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4296 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4297 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4299 emit_thread_force_interrupt_checkpoint (mb
);
4301 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
4302 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4303 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4304 mono_mb_emit_byte (mb
, CEE_MONO_DYN_CALL
);
4306 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4308 clause
= (MonoExceptionClause
*)mono_image_alloc0 (mono_defaults
.corlib
, sizeof (MonoExceptionClause
));
4309 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
4310 clause
->try_len
= mono_mb_get_label (mb
);
4313 clause
->data
.filter_offset
= mono_mb_get_label (mb
);
4315 mono_mb_emit_byte (mb
, CEE_POP
);
4316 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4317 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
4318 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4319 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
4320 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4321 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
4323 clause
->handler_offset
= mono_mb_get_label (mb
);
4326 /* store exception */
4327 mono_mb_emit_stloc (mb
, 1);
4329 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4330 mono_mb_emit_ldloc (mb
, 1);
4331 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4333 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4334 mono_mb_emit_stloc (mb
, 0);
4336 /* Check for the abort exception */
4337 mono_mb_emit_ldloc (mb
, 1);
4338 mono_mb_emit_op (mb
, CEE_ISINST
, mono_defaults
.threadabortexception_class
);
4339 posna
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
4341 /* Delay the abort exception */
4342 mono_mb_emit_icall (mb
, ves_icall_System_Threading_Thread_ResetAbort
);
4344 mono_mb_patch_short_branch (mb
, posna
);
4345 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4347 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4349 mono_mb_set_clauses (mb
, 1, clause
);
4352 mono_mb_patch_branch (mb
, pos
);
4353 //mono_mb_emit_ldloc (mb, 0);
4354 mono_mb_emit_byte (mb
, CEE_RET
);
4355 #endif /* DISABLE_JIT */
4357 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
4359 mono_marshal_lock ();
4360 /* double-checked locking */
4362 method
= mono_mb_create (mb
, csig
, 16, info
);
4364 mono_marshal_unlock ();
4372 * mono_marshal_get_runtime_invoke_for_sig:
4374 * Return a runtime invoke wrapper for a given signature.
4377 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
4379 MonoMethodSignature
*csig
, *callsig
;
4380 MonoMethodBuilder
*mb
;
4382 GHashTable
*cache
= NULL
;
4383 GHashTable
**cache_table
= NULL
;
4384 MonoMethod
*res
= NULL
;
4386 const char *param_names
[16];
4389 /* A simplified version of mono_marshal_get_runtime_invoke */
4391 image
= mono_defaults
.corlib
;
4393 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
4395 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
4397 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
4398 (GCompareFunc
)runtime_invoke_signature_equal
);
4400 /* from mono_marshal_find_in_cache */
4401 mono_marshal_lock ();
4402 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4403 mono_marshal_unlock ();
4410 /* Make a copy of the signature from the image mempool */
4411 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
4413 csig
= mono_metadata_signature_alloc (image
, 4);
4414 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4415 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4416 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4417 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4418 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4421 /* This is called from runtime code so it has to be cdecl */
4422 csig
->call_convention
= MONO_CALL_C
;
4425 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
4426 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4430 param_names
[0] = "this";
4431 param_names
[1] = "params";
4432 param_names
[2] = "exc";
4433 param_names
[3] = "method";
4434 mono_mb_set_param_names (mb
, param_names
);
4436 emit_runtime_invoke_body (mb
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
4439 /* taken from mono_mb_create_and_cache */
4440 mono_marshal_lock ();
4441 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4442 mono_marshal_unlock ();
4444 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
4445 info
->d
.runtime_invoke
.sig
= callsig
;
4447 /* Somebody may have created it before us */
4450 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
4452 mono_marshal_lock ();
4453 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4456 g_hash_table_insert (cache
, callsig
, res
);
4458 mono_free_method (newm
);
4460 mono_marshal_unlock ();
4463 /* end mono_mb_create_and_cache */
4472 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4474 char *msg
= g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
4475 klass
->name_space
, klass
->name
);
4477 mono_mb_emit_exception_marshal_directive (mb
, msg
);
4482 * generates IL code for the icall wrapper (the generated method
4483 * calls the unmanaged code in func)
4486 mono_marshal_get_icall_wrapper (MonoMethodSignature
*sig
, const char *name
, gconstpointer func
, gboolean check_exceptions
)
4488 MonoMethodSignature
*csig
, *csig2
;
4489 MonoMethodBuilder
*mb
;
4494 GHashTable
*cache
= get_cache (&mono_defaults
.object_class
->image
->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4495 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
4498 g_assert (sig
->pinvoke
);
4500 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
4502 mb
->method
->save_lmf
= 1;
4504 /* Add an explicit this argument */
4506 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
4508 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4512 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
4514 for (i
= 0; i
< sig
->param_count
; i
++)
4515 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
4517 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4518 mono_mb_emit_op (mb
, CEE_MONO_JIT_ICALL_ADDR
, (gpointer
)func
);
4519 mono_mb_emit_calli (mb
, csig2
);
4520 if (check_exceptions
)
4521 emit_thread_interrupt_checkpoint (mb
);
4522 mono_mb_emit_byte (mb
, CEE_RET
);
4525 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4527 if (csig
->call_convention
== MONO_CALL_VARARG
)
4528 csig
->call_convention
= 0;
4530 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
4531 info
->d
.icall
.func
= (gpointer
)func
;
4532 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
4539 emit_marshal_custom (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4540 MonoMarshalSpec
*spec
,
4541 int conv_arg
, MonoType
**conv_arg_type
,
4542 MarshalAction action
)
4545 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
4546 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
4552 static MonoClass
*ICustomMarshaler
= NULL
;
4553 static MonoMethod
*cleanup_native
, *cleanup_managed
;
4554 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
4555 MonoMethod
*get_instance
= NULL
;
4556 MonoMethodBuilder
*mb
= m
->mb
;
4557 char *exception_msg
= NULL
;
4561 if (!ICustomMarshaler
) {
4562 MonoClass
*klass
= mono_class_try_get_icustom_marshaler_class ();
4564 exception_msg
= g_strdup ("Current profile doesn't support ICustomMarshaler");
4565 goto handle_exception
;
4568 cleanup_native
= mono_class_get_method_from_name (klass
, "CleanUpNativeData", 1);
4569 g_assert (cleanup_native
);
4570 cleanup_managed
= mono_class_get_method_from_name (klass
, "CleanUpManagedData", 1);
4571 g_assert (cleanup_managed
);
4572 marshal_managed_to_native
= mono_class_get_method_from_name (klass
, "MarshalManagedToNative", 1);
4573 g_assert (marshal_managed_to_native
);
4574 marshal_native_to_managed
= mono_class_get_method_from_name (klass
, "MarshalNativeToManaged", 1);
4575 g_assert (marshal_native_to_managed
);
4577 mono_memory_barrier ();
4578 ICustomMarshaler
= klass
;
4581 if (spec
->data
.custom_data
.image
)
4582 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, spec
->data
.custom_data
.image
, &error
);
4584 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, m
->image
, &error
);
4585 g_assert (mtype
!= NULL
);
4586 mono_error_assert_ok (&error
);
4587 mklass
= mono_class_from_mono_type (mtype
);
4588 g_assert (mklass
!= NULL
);
4590 if (!mono_class_is_assignable_from (ICustomMarshaler
, mklass
))
4591 exception_msg
= g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass
->name
);
4593 get_instance
= mono_class_get_method_from_name_flags (mklass
, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC
);
4595 MonoMethodSignature
*get_sig
= mono_method_signature (get_instance
);
4596 if ((get_sig
->ret
->type
!= MONO_TYPE_CLASS
) ||
4597 (mono_class_from_mono_type (get_sig
->ret
) != ICustomMarshaler
) ||
4598 (get_sig
->params
[0]->type
!= MONO_TYPE_STRING
))
4599 get_instance
= NULL
;
4603 exception_msg
= g_strdup_printf ("Custom marshaler '%s' does not implement a static GetInstance method that takes a single string parameter and returns an ICustomMarshaler.", mklass
->name
);
4606 /* Throw exception and emit compensation code if neccesary */
4607 if (exception_msg
) {
4609 case MARSHAL_ACTION_CONV_IN
:
4610 case MARSHAL_ACTION_CONV_RESULT
:
4611 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4612 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
4613 mono_mb_emit_byte (mb
, CEE_POP
);
4615 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
4616 g_free (exception_msg
);
4619 case MARSHAL_ACTION_PUSH
:
4620 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4628 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
4629 /* FIXME: MS.NET throws an exception if GetInstance returns null */
4632 case MARSHAL_ACTION_CONV_IN
:
4634 case MONO_TYPE_CLASS
:
4635 case MONO_TYPE_OBJECT
:
4636 case MONO_TYPE_STRING
:
4637 case MONO_TYPE_ARRAY
:
4638 case MONO_TYPE_SZARRAY
:
4639 case MONO_TYPE_VALUETYPE
:
4643 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
4644 g_assert_not_reached ();
4648 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
4650 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4651 mono_mb_emit_stloc (mb
, conv_arg
);
4653 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4656 /* Minic MS.NET behavior */
4657 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
4660 /* Check for null */
4661 mono_mb_emit_ldarg (mb
, argnum
);
4663 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4664 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4666 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4668 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4670 mono_mb_emit_ldarg (mb
, argnum
);
4672 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4674 if (t
->type
== MONO_TYPE_VALUETYPE
) {
4676 * Since we can't determine the type of the argument, we
4677 * will assume the unmanaged function takes a pointer.
4679 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
4681 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
4684 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4685 mono_mb_emit_stloc (mb
, conv_arg
);
4687 mono_mb_patch_branch (mb
, pos2
);
4690 case MARSHAL_ACTION_CONV_OUT
:
4691 /* Check for null */
4692 mono_mb_emit_ldloc (mb
, conv_arg
);
4693 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4696 mono_mb_emit_ldarg (mb
, argnum
);
4698 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4700 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4702 mono_mb_emit_ldloc (mb
, conv_arg
);
4703 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4704 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4705 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
4706 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4708 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4710 mono_mb_emit_ldloc (mb
, conv_arg
);
4711 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4713 /* We have nowhere to store the result */
4714 mono_mb_emit_byte (mb
, CEE_POP
);
4717 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4719 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4721 mono_mb_emit_ldloc (mb
, conv_arg
);
4723 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4725 mono_mb_patch_branch (mb
, pos2
);
4728 case MARSHAL_ACTION_PUSH
:
4730 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4732 mono_mb_emit_ldloc (mb
, conv_arg
);
4735 case MARSHAL_ACTION_CONV_RESULT
:
4736 loc1
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
4738 mono_mb_emit_stloc (mb
, 3);
4740 mono_mb_emit_ldloc (mb
, 3);
4741 mono_mb_emit_stloc (mb
, loc1
);
4743 /* Check for null */
4744 mono_mb_emit_ldloc (mb
, 3);
4745 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4747 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4749 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4750 mono_mb_emit_byte (mb
, CEE_DUP
);
4752 mono_mb_emit_ldloc (mb
, 3);
4753 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4754 mono_mb_emit_stloc (mb
, 3);
4756 mono_mb_emit_ldloc (mb
, loc1
);
4757 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4759 mono_mb_patch_branch (mb
, pos2
);
4762 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4763 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4765 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4766 mono_mb_emit_stloc (mb
, conv_arg
);
4768 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4771 /* Check for null */
4772 mono_mb_emit_ldarg (mb
, argnum
);
4774 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4775 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4777 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4778 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4780 mono_mb_emit_ldarg (mb
, argnum
);
4782 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4784 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4785 mono_mb_emit_stloc (mb
, conv_arg
);
4787 mono_mb_patch_branch (mb
, pos2
);
4790 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4791 g_assert (!t
->byref
);
4793 loc1
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4795 mono_mb_emit_stloc (mb
, 3);
4797 mono_mb_emit_ldloc (mb
, 3);
4798 mono_mb_emit_stloc (mb
, loc1
);
4800 /* Check for null */
4801 mono_mb_emit_ldloc (mb
, 3);
4802 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4804 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4805 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4806 mono_mb_emit_byte (mb
, CEE_DUP
);
4808 mono_mb_emit_ldloc (mb
, 3);
4809 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4810 mono_mb_emit_stloc (mb
, 3);
4812 mono_mb_emit_ldloc (mb
, loc1
);
4813 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4815 mono_mb_patch_branch (mb
, pos2
);
4818 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4820 /* Check for null */
4821 mono_mb_emit_ldloc (mb
, conv_arg
);
4822 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4825 mono_mb_emit_ldarg (mb
, argnum
);
4827 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4829 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4831 mono_mb_emit_ldloc (mb
, conv_arg
);
4832 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4833 mono_mb_emit_byte (mb
, CEE_STIND_I
);
4836 /* Call CleanUpManagedData */
4837 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4839 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4841 mono_mb_emit_ldloc (mb
, conv_arg
);
4842 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4844 mono_mb_patch_branch (mb
, pos2
);
4848 g_assert_not_reached ();
4856 emit_marshal_asany (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4857 MonoMarshalSpec
*spec
,
4858 int conv_arg
, MonoType
**conv_arg_type
,
4859 MarshalAction action
)
4862 MonoMethodBuilder
*mb
= m
->mb
;
4865 case MARSHAL_ACTION_CONV_IN
: {
4866 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4868 g_assert (t
->type
== MONO_TYPE_OBJECT
);
4869 g_assert (!t
->byref
);
4871 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
4872 mono_mb_emit_ldarg (mb
, argnum
);
4873 mono_mb_emit_icon (mb
, encoding
);
4874 mono_mb_emit_icon (mb
, t
->attrs
);
4875 mono_mb_emit_icall (mb
, mono_marshal_asany
);
4876 mono_mb_emit_stloc (mb
, conv_arg
);
4880 case MARSHAL_ACTION_PUSH
:
4881 mono_mb_emit_ldloc (mb
, conv_arg
);
4884 case MARSHAL_ACTION_CONV_OUT
: {
4885 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4887 mono_mb_emit_ldarg (mb
, argnum
);
4888 mono_mb_emit_ldloc (mb
, conv_arg
);
4889 mono_mb_emit_icon (mb
, encoding
);
4890 mono_mb_emit_icon (mb
, t
->attrs
);
4891 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
4896 g_assert_not_reached ();
4903 emit_marshal_vtype (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4904 MonoMarshalSpec
*spec
,
4905 int conv_arg
, MonoType
**conv_arg_type
,
4906 MarshalAction action
)
4909 MonoMethodBuilder
*mb
= m
->mb
;
4910 MonoClass
*klass
, *date_time_class
;
4913 klass
= mono_class_from_mono_type (t
);
4915 date_time_class
= mono_class_get_date_time_class ();
4918 case MARSHAL_ACTION_CONV_IN
:
4919 if (klass
== date_time_class
) {
4920 /* Convert it to an OLE DATE type */
4921 static MonoMethod
*to_oadate
;
4924 to_oadate
= mono_class_get_method_from_name (date_time_class
, "ToOADate", 0);
4925 g_assert (to_oadate
);
4927 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.double_class
->byval_arg
);
4930 mono_mb_emit_ldarg (mb
, argnum
);
4931 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4934 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4936 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.double_class
->byval_arg
;
4938 mono_mb_emit_ldarg_addr (mb
, argnum
);
4939 mono_mb_emit_managed_call (mb
, to_oadate
, NULL
);
4940 mono_mb_emit_stloc (mb
, conv_arg
);
4944 mono_mb_patch_branch (mb
, pos
);
4948 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
4949 klass
->blittable
|| klass
->enumtype
)
4952 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
4954 /* store the address of the source into local variable 0 */
4956 mono_mb_emit_ldarg (mb
, argnum
);
4958 mono_mb_emit_ldarg_addr (mb
, argnum
);
4960 mono_mb_emit_stloc (mb
, 0);
4962 /* allocate space for the native struct and
4963 * store the address into local variable 1 (dest) */
4964 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
4965 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4966 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
4967 mono_mb_emit_stloc (mb
, conv_arg
);
4970 mono_mb_emit_ldloc (mb
, 0);
4971 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4974 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4976 mono_mb_emit_ldloc (mb
, conv_arg
);
4977 mono_mb_emit_stloc (mb
, 1);
4979 /* emit valuetype conversion code */
4980 emit_struct_conv (mb
, klass
, FALSE
);
4984 mono_mb_patch_branch (mb
, pos
);
4987 case MARSHAL_ACTION_PUSH
:
4988 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
4990 g_assert (!t
->byref
);
4992 /* Have to change the signature since the vtype is passed byref */
4993 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.int_class
->byval_arg
;
4995 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
4996 klass
->blittable
|| klass
->enumtype
)
4997 mono_mb_emit_ldarg_addr (mb
, argnum
);
4999 mono_mb_emit_ldloc (mb
, conv_arg
);
5003 if (klass
== date_time_class
) {
5005 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5007 mono_mb_emit_ldloc (mb
, conv_arg
);
5011 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5012 klass
->blittable
|| klass
->enumtype
) {
5013 mono_mb_emit_ldarg (mb
, argnum
);
5016 mono_mb_emit_ldloc (mb
, conv_arg
);
5018 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5019 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
5023 case MARSHAL_ACTION_CONV_OUT
:
5024 if (klass
== date_time_class
) {
5025 /* Convert from an OLE DATE type */
5026 static MonoMethod
*from_oadate
;
5031 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5033 from_oadate
= mono_class_get_method_from_name (date_time_class
, "FromOADate", 1);
5034 g_assert (from_oadate
);
5036 mono_mb_emit_ldarg (mb
, argnum
);
5037 mono_mb_emit_ldloc (mb
, conv_arg
);
5038 mono_mb_emit_managed_call (mb
, from_oadate
, NULL
);
5039 mono_mb_emit_op (mb
, CEE_STOBJ
, date_time_class
);
5044 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5045 klass
->blittable
|| klass
->enumtype
)
5049 /* dst = argument */
5050 mono_mb_emit_ldarg (mb
, argnum
);
5051 mono_mb_emit_stloc (mb
, 1);
5053 mono_mb_emit_ldloc (mb
, 1);
5054 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5056 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5057 /* src = tmp_locals [i] */
5058 mono_mb_emit_ldloc (mb
, conv_arg
);
5059 mono_mb_emit_stloc (mb
, 0);
5061 /* emit valuetype conversion code */
5062 emit_struct_conv (mb
, klass
, TRUE
);
5066 emit_struct_free (mb
, klass
, conv_arg
);
5069 mono_mb_patch_branch (mb
, pos
);
5072 case MARSHAL_ACTION_CONV_RESULT
:
5073 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5075 mono_mb_emit_stloc (mb
, 3);
5079 /* load pointer to returned value type */
5080 g_assert (m
->vtaddr_var
);
5081 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
5082 /* store the address of the source into local variable 0 */
5083 mono_mb_emit_stloc (mb
, 0);
5085 mono_mb_emit_ldloc_addr (mb
, 3);
5086 mono_mb_emit_stloc (mb
, 1);
5088 /* emit valuetype conversion code */
5089 emit_struct_conv (mb
, klass
, TRUE
);
5092 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5093 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5094 klass
->blittable
|| klass
->enumtype
) {
5099 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
5101 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5105 mono_mb_emit_ldarg (mb
, argnum
);
5107 mono_mb_emit_ldarg_addr (mb
, argnum
);
5108 mono_mb_emit_stloc (mb
, 0);
5111 mono_mb_emit_ldloc (mb
, 0);
5112 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5115 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5116 mono_mb_emit_stloc (mb
, 1);
5118 /* emit valuetype conversion code */
5119 emit_struct_conv (mb
, klass
, TRUE
);
5122 mono_mb_patch_branch (mb
, pos
);
5125 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5126 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5127 klass
->blittable
|| klass
->enumtype
) {
5131 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5134 /* Check for null */
5135 mono_mb_emit_ldarg (mb
, argnum
);
5136 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5139 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5140 mono_mb_emit_stloc (mb
, 0);
5143 mono_mb_emit_ldarg (mb
, argnum
);
5144 mono_mb_emit_stloc (mb
, 1);
5146 /* emit valuetype conversion code */
5147 emit_struct_conv (mb
, klass
, FALSE
);
5149 mono_mb_patch_branch (mb
, pos2
);
5152 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5153 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5154 klass
->blittable
|| klass
->enumtype
) {
5155 mono_mb_emit_stloc (mb
, 3);
5160 /* load pointer to returned value type */
5161 g_assert (m
->vtaddr_var
);
5162 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
5164 /* store the address of the source into local variable 0 */
5165 mono_mb_emit_stloc (mb
, 0);
5166 /* allocate space for the native struct and
5167 * store the address into dst_ptr */
5168 m
->retobj_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5169 m
->retobj_class
= klass
;
5170 g_assert (m
->retobj_var
);
5171 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5172 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5173 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5174 mono_mb_emit_stloc (mb
, 1);
5175 mono_mb_emit_ldloc (mb
, 1);
5176 mono_mb_emit_stloc (mb
, m
->retobj_var
);
5178 /* emit valuetype conversion code */
5179 emit_struct_conv (mb
, klass
, FALSE
);
5183 g_assert_not_reached ();
5190 emit_marshal_string (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5191 MonoMarshalSpec
*spec
,
5192 int conv_arg
, MonoType
**conv_arg_type
,
5193 MarshalAction action
)
5197 case MARSHAL_ACTION_CONV_IN
:
5198 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5200 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5201 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5205 MonoMethodBuilder
*mb
= m
->mb
;
5206 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5207 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
5211 case MARSHAL_ACTION_CONV_IN
:
5212 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5213 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5216 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5219 mono_mb_emit_ldarg (mb
, argnum
);
5220 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5222 mono_mb_emit_ldarg (mb
, argnum
);
5225 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5226 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5227 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5229 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5231 mono_mb_emit_stloc (mb
, conv_arg
);
5235 case MARSHAL_ACTION_CONV_OUT
:
5236 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5237 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5238 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5239 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5243 if (encoding
== MONO_NATIVE_VBBYREFSTR
) {
5244 static MonoMethod
*m
;
5247 m
= mono_class_get_method_from_name_flags (mono_defaults
.string_class
, "get_Length", -1, 0);
5252 char *msg
= g_strdup_printf ("VBByRefStr marshalling requires a ref parameter.", encoding
);
5253 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5258 * Have to allocate a new string with the same length as the original, and
5259 * copy the contents of the buffer pointed to by CONV_ARG into it.
5261 g_assert (t
->byref
);
5262 mono_mb_emit_ldarg (mb
, argnum
);
5263 mono_mb_emit_ldloc (mb
, conv_arg
);
5264 mono_mb_emit_ldarg (mb
, argnum
);
5265 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5266 mono_mb_emit_managed_call (mb
, m
, NULL
);
5267 mono_mb_emit_icall (mb
, mono_string_new_len_wrapper
);
5268 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5269 } else if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5271 mono_mb_emit_ldarg (mb
, argnum
);
5272 mono_mb_emit_ldloc (mb
, conv_arg
);
5273 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
5274 mono_mb_emit_byte (mb
, stind_op
);
5279 mono_mb_emit_ldloc (mb
, conv_arg
);
5280 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5281 mono_mb_emit_icall (mb
, mono_free_bstr
);
5283 mono_mb_emit_icall (mb
, mono_marshal_free
);
5287 case MARSHAL_ACTION_PUSH
:
5288 if (t
->byref
&& encoding
!= MONO_NATIVE_VBBYREFSTR
)
5289 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5291 mono_mb_emit_ldloc (mb
, conv_arg
);
5294 case MARSHAL_ACTION_CONV_RESULT
:
5295 mono_mb_emit_stloc (mb
, 0);
5297 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5298 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5299 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5300 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5304 mono_mb_emit_ldloc (mb
, 0);
5305 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5306 mono_mb_emit_stloc (mb
, 3);
5308 /* free the string */
5309 mono_mb_emit_ldloc (mb
, 0);
5310 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5311 mono_mb_emit_icall (mb
, mono_free_bstr
);
5313 mono_mb_emit_icall (mb
, mono_marshal_free
);
5316 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5317 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
5319 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5322 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5326 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5327 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5328 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5329 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5333 mono_mb_emit_ldarg (mb
, argnum
);
5335 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5336 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5337 mono_mb_emit_stloc (mb
, conv_arg
);
5340 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5344 mono_mb_emit_ldarg (mb
, argnum
);
5345 mono_mb_emit_ldloc (mb
, conv_arg
);
5346 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
5347 mono_mb_emit_byte (mb
, stind_op
);
5352 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5353 if (conv_to_icall (conv
, NULL
) == mono_marshal_string_to_utf16
)
5354 /* We need to make a copy so the caller is able to free it */
5355 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
5357 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5358 mono_mb_emit_stloc (mb
, 3);
5362 g_assert_not_reached ();
5370 emit_marshal_safehandle (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5371 MonoMarshalSpec
*spec
, int conv_arg
,
5372 MonoType
**conv_arg_type
, MarshalAction action
)
5375 if (action
== MARSHAL_ACTION_CONV_IN
)
5376 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5378 MonoMethodBuilder
*mb
= m
->mb
;
5381 case MARSHAL_ACTION_CONV_IN
: {
5382 MonoType
*intptr_type
;
5383 int dar_release_slot
, pos
;
5385 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
5386 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
5387 *conv_arg_type
= intptr_type
;
5389 if (!sh_dangerous_add_ref
)
5390 init_safe_handle ();
5392 mono_mb_emit_ldarg (mb
, argnum
);
5393 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5394 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5396 mono_mb_patch_branch (mb
, pos
);
5399 * My tests in show that ref SafeHandles are not really
5400 * passed as ref objects. Instead a NULL is passed as the
5403 mono_mb_emit_icon (mb
, 0);
5404 mono_mb_emit_stloc (mb
, conv_arg
);
5408 /* Create local to hold the ref parameter to DangerousAddRef */
5409 dar_release_slot
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
5411 /* set release = false; */
5412 mono_mb_emit_icon (mb
, 0);
5413 mono_mb_emit_stloc (mb
, dar_release_slot
);
5415 /* safehandle.DangerousAddRef (ref release) */
5416 mono_mb_emit_ldarg (mb
, argnum
);
5417 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5418 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5420 /* Pull the handle field from SafeHandle */
5421 mono_mb_emit_ldarg (mb
, argnum
);
5422 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5423 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5424 mono_mb_emit_stloc (mb
, conv_arg
);
5429 case MARSHAL_ACTION_PUSH
:
5431 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5433 mono_mb_emit_ldloc (mb
, conv_arg
);
5436 case MARSHAL_ACTION_CONV_OUT
: {
5437 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5438 int dar_release_slot
= conv_arg
+ 1;
5441 if (!sh_dangerous_release
)
5442 init_safe_handle ();
5448 * My tests indicate that ref SafeHandles parameters are not actually
5449 * passed by ref, but instead a new Handle is created regardless of
5450 * whether a change happens in the unmanaged side.
5452 * Also, the Handle is created before calling into unmanaged code,
5453 * but we do not support that mechanism (getting to the original
5454 * handle) and it makes no difference where we create this
5456 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
5458 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5461 /* refval = new SafeHandleDerived ()*/
5462 mono_mb_emit_ldarg (mb
, argnum
);
5463 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5464 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5466 /* refval.handle = returned_handle */
5467 mono_mb_emit_ldarg (mb
, argnum
);
5468 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5469 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5470 mono_mb_emit_ldloc (mb
, conv_arg
);
5471 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5473 mono_mb_emit_ldloc (mb
, dar_release_slot
);
5474 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5475 mono_mb_emit_ldarg (mb
, argnum
);
5476 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5477 mono_mb_patch_branch (mb
, label_next
);
5482 case MARSHAL_ACTION_CONV_RESULT
: {
5483 MonoMethod
*ctor
= NULL
;
5484 int intptr_handle_slot
;
5486 if (t
->data
.klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
){
5487 mono_mb_emit_byte (mb
, CEE_POP
);
5488 mono_mb_emit_exception_marshal_directive (mb
, g_strdup ("Returned SafeHandles should not be abstract"));
5492 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
5494 mono_mb_emit_byte (mb
, CEE_POP
);
5495 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5498 /* Store the IntPtr results into a local */
5499 intptr_handle_slot
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5500 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
5502 /* Create return value */
5503 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5504 mono_mb_emit_stloc (mb
, 3);
5506 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5507 mono_mb_emit_ldloc (mb
, 3);
5508 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5509 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
5510 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5514 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5515 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5518 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5519 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5522 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5523 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5526 printf ("Unhandled case for MarshalAction: %d\n", action
);
5534 emit_marshal_handleref (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5535 MonoMarshalSpec
*spec
, int conv_arg
,
5536 MonoType
**conv_arg_type
, MarshalAction action
)
5539 if (action
== MARSHAL_ACTION_CONV_IN
)
5540 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5542 MonoMethodBuilder
*mb
= m
->mb
;
5545 case MARSHAL_ACTION_CONV_IN
: {
5546 MonoType
*intptr_type
;
5548 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
5549 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
5550 *conv_arg_type
= intptr_type
;
5553 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5554 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5557 mono_mb_emit_ldarg_addr (mb
, argnum
);
5558 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
5559 mono_mb_emit_byte (mb
, CEE_ADD
);
5560 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5561 mono_mb_emit_stloc (mb
, conv_arg
);
5565 case MARSHAL_ACTION_PUSH
:
5566 mono_mb_emit_ldloc (mb
, conv_arg
);
5569 case MARSHAL_ACTION_CONV_OUT
: {
5570 /* no resource release required */
5574 case MARSHAL_ACTION_CONV_RESULT
: {
5575 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5576 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5580 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5581 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5584 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5585 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5588 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5589 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5592 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
5600 emit_marshal_object (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5601 MonoMarshalSpec
*spec
,
5602 int conv_arg
, MonoType
**conv_arg_type
,
5603 MarshalAction action
)
5606 if (action
== MARSHAL_ACTION_CONV_IN
)
5607 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5609 MonoMethodBuilder
*mb
= m
->mb
;
5610 MonoClass
*klass
= mono_class_from_mono_type (t
);
5614 case MARSHAL_ACTION_CONV_IN
:
5615 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5616 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5618 m
->orig_conv_args
[argnum
] = 0;
5620 if (mono_class_from_mono_type (t
) == mono_defaults
.object_class
) {
5621 char *msg
= g_strdup_printf ("Marshalling of type object is not implemented");
5622 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5626 if (klass
->delegate
) {
5628 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5629 char *msg
= g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5630 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5632 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5633 mono_mb_emit_stloc (mb
, conv_arg
);
5635 mono_mb_emit_ldarg (mb
, argnum
);
5636 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5637 mono_mb_emit_stloc (mb
, conv_arg
);
5639 } else if (klass
== mono_defaults
.stringbuilder_class
) {
5640 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5641 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
5645 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5646 char *msg
= g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5647 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5653 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5656 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5657 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
5658 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5662 mono_mb_emit_ldarg (mb
, argnum
);
5664 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5666 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5667 mono_mb_emit_stloc (mb
, conv_arg
);
5668 } else if (klass
->blittable
) {
5669 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5670 mono_mb_emit_stloc (mb
, conv_arg
);
5672 mono_mb_emit_ldarg (mb
, argnum
);
5673 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5675 mono_mb_emit_ldarg (mb
, argnum
);
5676 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
5677 mono_mb_emit_stloc (mb
, conv_arg
);
5679 mono_mb_patch_branch (mb
, pos
);
5682 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5683 mono_mb_emit_stloc (mb
, conv_arg
);
5686 /* we dont need any conversions for out parameters */
5687 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5690 mono_mb_emit_ldarg (mb
, argnum
);
5691 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5694 mono_mb_emit_ldarg (mb
, argnum
);
5695 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5696 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5699 /* store the address of the source into local variable 0 */
5700 mono_mb_emit_stloc (mb
, 0);
5701 mono_mb_emit_ldloc (mb
, 0);
5702 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5704 /* allocate space for the native struct and store the address */
5705 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5706 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5707 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5708 mono_mb_emit_stloc (mb
, conv_arg
);
5711 /* Need to store the original buffer so we can free it later */
5712 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5713 mono_mb_emit_ldloc (mb
, conv_arg
);
5714 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
5717 /* set the src_ptr */
5718 mono_mb_emit_ldloc (mb
, 0);
5719 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
5720 mono_mb_emit_stloc (mb
, 0);
5723 mono_mb_emit_ldloc (mb
, conv_arg
);
5724 mono_mb_emit_stloc (mb
, 1);
5726 /* emit valuetype conversion code */
5727 emit_struct_conv (mb
, klass
, FALSE
);
5729 mono_mb_patch_branch (mb
, pos
);
5733 case MARSHAL_ACTION_CONV_OUT
:
5734 if (klass
== mono_defaults
.stringbuilder_class
) {
5736 MonoMarshalNative encoding
;
5737 MonoMarshalConv conv
;
5739 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5740 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
5742 g_assert (encoding
!= -1);
5745 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5749 mono_mb_emit_ldarg (mb
, argnum
);
5750 mono_mb_emit_ldloc (mb
, conv_arg
);
5753 case MONO_NATIVE_LPWSTR
:
5754 mono_mb_emit_icall (mb
, mono_string_utf16_to_builder2
);
5756 case MONO_NATIVE_LPSTR
:
5757 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5760 g_assert_not_reached ();
5763 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5765 mono_mb_emit_ldarg (mb
, argnum
);
5766 mono_mb_emit_ldloc (mb
, conv_arg
);
5768 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5772 mono_mb_emit_ldloc (mb
, conv_arg
);
5773 mono_mb_emit_icall (mb
, mono_marshal_free
);
5778 if (klass
->delegate
) {
5780 mono_mb_emit_ldarg (mb
, argnum
);
5781 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5782 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5783 mono_mb_emit_ldloc (mb
, conv_arg
);
5784 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5785 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5790 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5791 /* allocate a new object */
5792 mono_mb_emit_ldarg (mb
, argnum
);
5793 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5794 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5795 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5798 /* dst = *argument */
5799 mono_mb_emit_ldarg (mb
, argnum
);
5802 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5804 mono_mb_emit_stloc (mb
, 1);
5806 mono_mb_emit_ldloc (mb
, 1);
5807 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5809 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5810 mono_mb_emit_ldloc (mb
, 1);
5811 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
5812 mono_mb_emit_byte (mb
, CEE_ADD
);
5813 mono_mb_emit_stloc (mb
, 1);
5815 /* src = tmp_locals [i] */
5816 mono_mb_emit_ldloc (mb
, conv_arg
);
5817 mono_mb_emit_stloc (mb
, 0);
5819 /* emit valuetype conversion code */
5820 emit_struct_conv (mb
, klass
, TRUE
);
5822 /* Free the structure returned by the native code */
5823 emit_struct_free (mb
, klass
, conv_arg
);
5825 if (m
->orig_conv_args
[argnum
]) {
5827 * If the native function changed the pointer, then free
5828 * the original structure plus the new pointer.
5830 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
5831 mono_mb_emit_ldloc (mb
, conv_arg
);
5832 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5834 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5835 g_assert (m
->orig_conv_args
[argnum
]);
5837 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
5840 mono_mb_emit_ldloc (mb
, conv_arg
);
5841 mono_mb_emit_icall (mb
, mono_marshal_free
);
5843 mono_mb_patch_branch (mb
, pos2
);
5847 /* Free the original structure passed to native code */
5848 emit_struct_free (mb
, klass
, conv_arg
);
5850 mono_mb_patch_branch (mb
, pos
);
5853 case MARSHAL_ACTION_PUSH
:
5855 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5857 mono_mb_emit_ldloc (mb
, conv_arg
);
5860 case MARSHAL_ACTION_CONV_RESULT
:
5861 if (klass
->delegate
) {
5862 g_assert (!t
->byref
);
5863 mono_mb_emit_stloc (mb
, 0);
5864 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5865 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5866 mono_mb_emit_ldloc (mb
, 0);
5867 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5868 mono_mb_emit_stloc (mb
, 3);
5871 mono_mb_emit_stloc (mb
, 0);
5873 /* Make a copy since emit_conv modifies local 0 */
5874 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5875 mono_mb_emit_ldloc (mb
, 0);
5876 mono_mb_emit_stloc (mb
, loc
);
5878 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5879 mono_mb_emit_stloc (mb
, 3);
5881 mono_mb_emit_ldloc (mb
, 0);
5882 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5884 /* allocate result object */
5886 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5887 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5888 mono_mb_emit_stloc (mb
, 3);
5892 mono_mb_emit_ldloc (mb
, 3);
5893 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
5894 mono_mb_emit_stloc (mb
, 1);
5896 /* emit conversion code */
5897 emit_struct_conv (mb
, klass
, TRUE
);
5899 emit_struct_free (mb
, klass
, loc
);
5901 /* Free the pointer allocated by unmanaged code */
5902 mono_mb_emit_ldloc (mb
, loc
);
5903 mono_mb_emit_icall (mb
, mono_marshal_free
);
5904 mono_mb_patch_branch (mb
, pos
);
5908 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5909 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
5911 if (klass
->delegate
) {
5912 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5913 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5914 mono_mb_emit_ldarg (mb
, argnum
);
5916 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5917 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5918 mono_mb_emit_stloc (mb
, conv_arg
);
5922 if (klass
== mono_defaults
.stringbuilder_class
) {
5923 MonoMarshalNative encoding
;
5925 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5928 g_assert (encoding
== MONO_NATIVE_LPSTR
);
5930 g_assert (!t
->byref
);
5931 g_assert (encoding
!= -1);
5933 mono_mb_emit_ldarg (mb
, argnum
);
5934 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5935 mono_mb_emit_stloc (mb
, conv_arg
);
5939 /* The class can not have an automatic layout */
5940 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
5941 mono_mb_emit_auto_layout_exception (mb
, klass
);
5945 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
5946 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5947 mono_mb_emit_stloc (mb
, conv_arg
);
5952 mono_mb_emit_ldarg (mb
, argnum
);
5956 /* Check for NULL and raise an exception */
5957 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5959 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5961 mono_mb_patch_branch (mb
, pos2
);
5962 mono_mb_emit_ldarg (mb
, argnum
);
5963 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5966 mono_mb_emit_stloc (mb
, 0);
5968 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5969 mono_mb_emit_stloc (mb
, conv_arg
);
5971 mono_mb_emit_ldloc (mb
, 0);
5972 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5974 /* Create and set dst */
5975 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5976 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5977 mono_mb_emit_stloc (mb
, conv_arg
);
5978 mono_mb_emit_ldloc (mb
, conv_arg
);
5979 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
5980 mono_mb_emit_stloc (mb
, 1);
5982 /* emit valuetype conversion code */
5983 emit_struct_conv (mb
, klass
, TRUE
);
5985 mono_mb_patch_branch (mb
, pos
);
5988 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5989 if (klass
->delegate
) {
5992 mono_mb_emit_ldarg (mb
, argnum
);
5993 mono_mb_emit_ldloc (mb
, conv_arg
);
5994 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, &stind_op
));
5995 mono_mb_emit_byte (mb
, stind_op
);
6001 /* Check for null */
6002 mono_mb_emit_ldloc (mb
, conv_arg
);
6003 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6004 mono_mb_emit_ldarg (mb
, argnum
);
6005 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6006 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6007 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6009 mono_mb_patch_branch (mb
, pos
);
6012 mono_mb_emit_ldloc (mb
, conv_arg
);
6013 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6014 mono_mb_emit_stloc (mb
, 0);
6016 /* Allocate and set dest */
6017 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6018 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6019 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
6020 mono_mb_emit_stloc (mb
, 1);
6022 /* Update argument pointer */
6023 mono_mb_emit_ldarg (mb
, argnum
);
6024 mono_mb_emit_ldloc (mb
, 1);
6025 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6027 /* emit valuetype conversion code */
6028 emit_struct_conv (mb
, klass
, FALSE
);
6030 mono_mb_patch_branch (mb
, pos2
);
6031 } else if (klass
== mono_defaults
.stringbuilder_class
) {
6032 // FIXME: What to do here ?
6034 /* byval [Out] marshalling */
6036 /* FIXME: Handle null */
6039 mono_mb_emit_ldloc (mb
, conv_arg
);
6040 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6041 mono_mb_emit_stloc (mb
, 0);
6044 mono_mb_emit_ldarg (mb
, argnum
);
6045 mono_mb_emit_stloc (mb
, 1);
6047 /* emit valuetype conversion code */
6048 emit_struct_conv (mb
, klass
, FALSE
);
6052 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6053 if (klass
->delegate
) {
6054 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
6055 mono_mb_emit_stloc (mb
, 3);
6059 /* The class can not have an automatic layout */
6060 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
6061 mono_mb_emit_auto_layout_exception (mb
, klass
);
6065 mono_mb_emit_stloc (mb
, 0);
6066 /* Check for null */
6067 mono_mb_emit_ldloc (mb
, 0);
6068 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6069 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6070 mono_mb_emit_stloc (mb
, 3);
6071 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6073 mono_mb_patch_branch (mb
, pos
);
6076 mono_mb_emit_ldloc (mb
, 0);
6077 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6078 mono_mb_emit_stloc (mb
, 0);
6080 /* Allocate and set dest */
6081 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6082 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6083 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
6084 mono_mb_emit_byte (mb
, CEE_DUP
);
6085 mono_mb_emit_stloc (mb
, 1);
6086 mono_mb_emit_stloc (mb
, 3);
6088 emit_struct_conv (mb
, klass
, FALSE
);
6090 mono_mb_patch_branch (mb
, pos2
);
6094 g_assert_not_reached ();
6105 emit_marshal_variant (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6106 MonoMarshalSpec
*spec
,
6107 int conv_arg
, MonoType
**conv_arg_type
,
6108 MarshalAction action
)
6110 MonoMethodBuilder
*mb
= m
->mb
;
6111 static MonoMethod
*get_object_for_native_variant
= NULL
;
6112 static MonoMethod
*get_native_variant_for_object
= NULL
;
6114 if (!get_object_for_native_variant
)
6115 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
6116 g_assert (get_object_for_native_variant
);
6118 if (!get_native_variant_for_object
)
6119 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
6120 g_assert (get_native_variant_for_object
);
6123 case MARSHAL_ACTION_CONV_IN
: {
6124 conv_arg
= mono_mb_add_local (mb
, &mono_class_get_variant_class ()->byval_arg
);
6127 *conv_arg_type
= &mono_class_get_variant_class ()->this_arg
;
6129 *conv_arg_type
= &mono_class_get_variant_class ()->byval_arg
;
6131 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6134 mono_mb_emit_ldarg (mb
, argnum
);
6136 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
6137 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6138 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
6142 case MARSHAL_ACTION_CONV_OUT
: {
6143 static MonoMethod
*variant_clear
= NULL
;
6146 variant_clear
= mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
6147 g_assert (variant_clear
);
6150 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6151 mono_mb_emit_ldarg (mb
, argnum
);
6152 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6153 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
6154 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6157 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6158 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
6162 case MARSHAL_ACTION_PUSH
:
6164 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6166 mono_mb_emit_ldloc (mb
, conv_arg
);
6169 case MARSHAL_ACTION_CONV_RESULT
: {
6170 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6171 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6175 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
6176 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6179 *conv_arg_type
= &mono_class_get_variant_class ()->this_arg
;
6181 *conv_arg_type
= &mono_class_get_variant_class ()->byval_arg
;
6183 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6187 mono_mb_emit_ldarg (mb
, argnum
);
6189 mono_mb_emit_ldarg_addr (mb
, argnum
);
6190 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
6191 mono_mb_emit_stloc (mb
, conv_arg
);
6195 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
6196 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6197 mono_mb_emit_ldloc (mb
, conv_arg
);
6198 mono_mb_emit_ldarg (mb
, argnum
);
6199 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
6204 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
6205 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6206 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6211 g_assert_not_reached ();
6217 #endif /* DISABLE_COM */
6218 #endif /* DISABLE_JIT */
6221 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
6223 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
6224 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
6226 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
6228 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
6240 emit_marshal_array (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6241 MonoMarshalSpec
*spec
,
6242 int conv_arg
, MonoType
**conv_arg_type
,
6243 MarshalAction action
)
6247 case MARSHAL_ACTION_CONV_IN
:
6248 *conv_arg_type
= &mono_defaults
.object_class
->byval_arg
;
6250 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6251 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6255 MonoMethodBuilder
*mb
= m
->mb
;
6256 MonoClass
*klass
= mono_class_from_mono_type (t
);
6257 gboolean need_convert
, need_free
;
6258 MonoMarshalNative encoding
;
6260 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6263 case MARSHAL_ACTION_CONV_IN
:
6264 *conv_arg_type
= &mono_defaults
.object_class
->byval_arg
;
6265 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6267 if (klass
->element_class
->blittable
) {
6268 mono_mb_emit_ldarg (mb
, argnum
);
6270 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6271 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
, NULL
));
6272 mono_mb_emit_stloc (mb
, conv_arg
);
6275 guint32 label1
, label2
, label3
;
6276 int index_var
, src_var
, dest_ptr
, esize
;
6277 MonoMarshalConv conv
;
6278 gboolean is_string
= FALSE
;
6280 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6282 eklass
= klass
->element_class
;
6284 if (eklass
== mono_defaults
.string_class
) {
6286 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6288 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6290 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6293 conv
= MONO_MARSHAL_CONV_INVALID
;
6295 if (is_string
&& conv
== MONO_MARSHAL_CONV_INVALID
) {
6296 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
6297 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6301 src_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6302 mono_mb_emit_ldarg (mb
, argnum
);
6304 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6305 mono_mb_emit_stloc (mb
, src_var
);
6308 mono_mb_emit_ldloc (mb
, src_var
);
6309 mono_mb_emit_stloc (mb
, conv_arg
);
6310 mono_mb_emit_ldloc (mb
, src_var
);
6311 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6314 esize
= sizeof (gpointer
);
6315 else if (eklass
== mono_defaults
.char_class
) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
6316 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
6318 esize
= mono_class_native_size (eklass
, NULL
);
6320 /* allocate space for the native struct and store the address */
6321 mono_mb_emit_icon (mb
, esize
);
6322 mono_mb_emit_ldloc (mb
, src_var
);
6323 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6325 if (eklass
== mono_defaults
.string_class
) {
6326 /* Make the array bigger for the terminating null */
6327 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
6328 mono_mb_emit_byte (mb
, CEE_ADD
);
6330 mono_mb_emit_byte (mb
, CEE_MUL
);
6331 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6332 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
6333 mono_mb_emit_stloc (mb
, conv_arg
);
6335 mono_mb_emit_ldloc (mb
, conv_arg
);
6336 mono_mb_emit_stloc (mb
, dest_ptr
);
6338 /* Emit marshalling loop */
6339 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6340 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6341 mono_mb_emit_stloc (mb
, index_var
);
6342 label2
= mono_mb_get_label (mb
);
6343 mono_mb_emit_ldloc (mb
, index_var
);
6344 mono_mb_emit_ldloc (mb
, src_var
);
6345 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6346 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6348 /* Emit marshalling code */
6352 mono_mb_emit_ldloc (mb
, dest_ptr
);
6353 mono_mb_emit_ldloc (mb
, src_var
);
6354 mono_mb_emit_ldloc (mb
, index_var
);
6355 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6356 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
6357 mono_mb_emit_byte (mb
, stind_op
);
6359 /* set the src_ptr */
6360 mono_mb_emit_ldloc (mb
, src_var
);
6361 mono_mb_emit_ldloc (mb
, index_var
);
6362 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
6363 mono_mb_emit_stloc (mb
, 0);
6366 mono_mb_emit_ldloc (mb
, dest_ptr
);
6367 mono_mb_emit_stloc (mb
, 1);
6369 /* emit valuetype conversion code */
6370 emit_struct_conv_full (mb
, eklass
, FALSE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
6373 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6374 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
6376 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6378 mono_mb_patch_branch (mb
, label3
);
6380 if (eklass
== mono_defaults
.string_class
) {
6381 /* Null terminate */
6382 mono_mb_emit_ldloc (mb
, dest_ptr
);
6383 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6384 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6387 mono_mb_patch_branch (mb
, label1
);
6392 case MARSHAL_ACTION_CONV_OUT
:
6393 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
6394 need_convert
= ((klass
->element_class
== mono_defaults
.char_class
) && (encoding
== MONO_NATIVE_LPWSTR
)) || (klass
->element_class
== mono_defaults
.stringbuilder_class
) || (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
6395 need_free
= mono_marshal_need_free (&klass
->element_class
->byval_arg
,
6398 if ((t
->attrs
& PARAM_ATTRIBUTE_OUT
) && spec
&& spec
->native
== MONO_NATIVE_LPARRAY
&& spec
->data
.array_data
.param_num
!= -1) {
6399 int param_num
= spec
->data
.array_data
.param_num
;
6400 MonoType
*param_type
;
6402 param_type
= m
->sig
->params
[param_num
];
6404 if (param_type
->byref
&& param_type
->type
!= MONO_TYPE_I4
) {
6405 char *msg
= g_strdup ("Not implemented.");
6406 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6411 mono_mb_emit_ldarg (mb
, argnum
);
6413 /* Create the managed array */
6414 mono_mb_emit_ldarg (mb
, param_num
);
6415 if (m
->sig
->params
[param_num
]->byref
)
6416 // FIXME: Support other types
6417 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
6418 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
6419 mono_mb_emit_op (mb
, CEE_NEWARR
, klass
->element_class
);
6420 /* Store into argument */
6421 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6425 if (need_convert
|| need_free
) {
6426 /* FIXME: Optimize blittable case */
6428 guint32 label1
, label2
, label3
;
6429 int index_var
, src_ptr
, loc
, esize
;
6431 eklass
= klass
->element_class
;
6432 if ((eklass
== mono_defaults
.stringbuilder_class
) || (eklass
== mono_defaults
.string_class
))
6433 esize
= sizeof (gpointer
);
6434 else if (eklass
== mono_defaults
.char_class
)
6435 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
6437 esize
= mono_class_native_size (eklass
, NULL
);
6438 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6439 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6442 mono_mb_emit_ldarg (mb
, argnum
);
6444 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6445 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6447 mono_mb_emit_ldloc (mb
, conv_arg
);
6448 mono_mb_emit_stloc (mb
, src_ptr
);
6450 /* Emit marshalling loop */
6451 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6452 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6453 mono_mb_emit_stloc (mb
, index_var
);
6454 label2
= mono_mb_get_label (mb
);
6455 mono_mb_emit_ldloc (mb
, index_var
);
6456 mono_mb_emit_ldarg (mb
, argnum
);
6458 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6459 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6460 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6462 /* Emit marshalling code */
6464 if (eklass
== mono_defaults
.stringbuilder_class
) {
6465 gboolean need_free2
;
6466 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
6468 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6471 mono_mb_emit_ldarg (mb
, argnum
);
6473 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6474 mono_mb_emit_ldloc (mb
, index_var
);
6475 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6478 mono_mb_emit_ldloc (mb
, src_ptr
);
6479 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6481 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
6485 mono_mb_emit_ldloc (mb
, src_ptr
);
6486 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6488 mono_mb_emit_icall (mb
, mono_marshal_free
);
6491 else if (eklass
== mono_defaults
.string_class
) {
6494 mono_mb_emit_ldloc (mb
, src_ptr
);
6495 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6497 mono_mb_emit_icall (mb
, mono_marshal_free
);
6502 /* set the src_ptr */
6503 mono_mb_emit_ldloc (mb
, src_ptr
);
6504 mono_mb_emit_stloc (mb
, 0);
6507 mono_mb_emit_ldarg (mb
, argnum
);
6509 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6510 mono_mb_emit_ldloc (mb
, index_var
);
6511 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
6512 mono_mb_emit_stloc (mb
, 1);
6514 /* emit valuetype conversion code */
6515 emit_struct_conv_full (mb
, eklass
, TRUE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
6519 mono_mb_emit_ldloc (mb
, src_ptr
);
6520 mono_mb_emit_stloc (mb
, loc
);
6521 mono_mb_emit_ldloc (mb
, loc
);
6523 emit_struct_free (mb
, eklass
, loc
);
6527 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6528 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
6530 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6532 mono_mb_patch_branch (mb
, label1
);
6533 mono_mb_patch_branch (mb
, label3
);
6536 if (klass
->element_class
->blittable
) {
6537 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
6539 mono_mb_emit_ldarg (mb
, argnum
);
6541 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6542 mono_mb_emit_ldloc (mb
, conv_arg
);
6543 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY
, NULL
));
6548 case MARSHAL_ACTION_PUSH
:
6550 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6552 mono_mb_emit_ldloc (mb
, conv_arg
);
6555 case MARSHAL_ACTION_CONV_RESULT
:
6556 /* fixme: we need conversions here */
6557 mono_mb_emit_stloc (mb
, 3);
6560 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
6562 guint32 label1
, label2
, label3
;
6563 int index_var
, src_ptr
, esize
, param_num
, num_elem
;
6564 MonoMarshalConv conv
;
6565 gboolean is_string
= FALSE
;
6567 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6568 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6571 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
6572 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6576 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
6577 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6580 if (spec
->native
!= MONO_NATIVE_LPARRAY
) {
6581 char *msg
= g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
6582 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6586 /* FIXME: t is from the method which is wrapped, not the delegate type */
6587 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
6589 param_num
= spec
->data
.array_data
.param_num
;
6590 num_elem
= spec
->data
.array_data
.num_elem
;
6591 if (spec
->data
.array_data
.elem_mult
== 0)
6592 /* param_num is not specified */
6595 if (param_num
== -1) {
6596 if (num_elem
<= 0) {
6597 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
6598 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6603 /* FIXME: Optimize blittable case */
6605 eklass
= klass
->element_class
;
6606 if (eklass
== mono_defaults
.string_class
) {
6608 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
6610 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6612 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
6615 conv
= MONO_MARSHAL_CONV_INVALID
;
6617 mono_marshal_load_type_info (eklass
);
6620 esize
= sizeof (gpointer
);
6622 esize
= mono_class_native_size (eklass
, NULL
);
6623 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6625 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6626 mono_mb_emit_stloc (mb
, conv_arg
);
6628 /* Check param index */
6629 if (param_num
!= -1) {
6630 if (param_num
>= m
->sig
->param_count
) {
6631 char *msg
= g_strdup ("Array size control parameter index is out of range.");
6632 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6635 switch (m
->sig
->params
[param_num
]->type
) {
6648 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
6649 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6656 mono_mb_emit_ldarg (mb
, argnum
);
6657 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6659 mono_mb_emit_ldarg (mb
, argnum
);
6660 mono_mb_emit_stloc (mb
, src_ptr
);
6662 /* Create managed array */
6664 * The LPArray marshalling spec says that sometimes param_num starts
6665 * from 1, sometimes it starts from 0. But MS seems to allways start
6669 if (param_num
== -1) {
6670 mono_mb_emit_icon (mb
, num_elem
);
6672 mono_mb_emit_ldarg (mb
, param_num
);
6674 mono_mb_emit_icon (mb
, num_elem
);
6675 mono_mb_emit_byte (mb
, CEE_ADD
);
6677 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
6680 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
6681 mono_mb_emit_stloc (mb
, conv_arg
);
6683 if (eklass
->blittable
) {
6684 mono_mb_emit_ldloc (mb
, conv_arg
);
6685 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6686 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
6687 mono_mb_emit_byte (mb
, CEE_ADD
);
6688 mono_mb_emit_ldarg (mb
, argnum
);
6689 mono_mb_emit_ldloc (mb
, conv_arg
);
6690 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6691 mono_mb_emit_icon (mb
, esize
);
6692 mono_mb_emit_byte (mb
, CEE_MUL
);
6693 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6694 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6698 /* Emit marshalling loop */
6699 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6700 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6701 mono_mb_emit_stloc (mb
, index_var
);
6702 label2
= mono_mb_get_label (mb
);
6703 mono_mb_emit_ldloc (mb
, index_var
);
6704 mono_mb_emit_ldloc (mb
, conv_arg
);
6705 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6706 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6708 /* Emit marshalling code */
6710 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6712 mono_mb_emit_ldloc (mb
, conv_arg
);
6713 mono_mb_emit_ldloc (mb
, index_var
);
6715 mono_mb_emit_ldloc (mb
, src_ptr
);
6716 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6718 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
6719 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
6722 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
6723 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6727 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6728 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
6730 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6732 mono_mb_patch_branch (mb
, label1
);
6733 mono_mb_patch_branch (mb
, label3
);
6737 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
6739 guint32 label1
, label2
, label3
;
6740 int index_var
, dest_ptr
, esize
, param_num
, num_elem
;
6741 MonoMarshalConv conv
;
6742 gboolean is_string
= FALSE
;
6745 /* Already handled in CONV_IN */
6748 /* These are already checked in CONV_IN */
6749 g_assert (!t
->byref
);
6750 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
6751 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
6753 param_num
= spec
->data
.array_data
.param_num
;
6754 num_elem
= spec
->data
.array_data
.num_elem
;
6756 if (spec
->data
.array_data
.elem_mult
== 0)
6757 /* param_num is not specified */
6760 if (param_num
== -1) {
6761 if (num_elem
<= 0) {
6762 g_assert_not_reached ();
6766 /* FIXME: Optimize blittable case */
6768 eklass
= klass
->element_class
;
6769 if (eklass
== mono_defaults
.string_class
) {
6771 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6773 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6775 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6778 conv
= MONO_MARSHAL_CONV_INVALID
;
6780 mono_marshal_load_type_info (eklass
);
6783 esize
= sizeof (gpointer
);
6785 esize
= mono_class_native_size (eklass
, NULL
);
6787 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6790 mono_mb_emit_ldloc (mb
, conv_arg
);
6791 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6793 mono_mb_emit_ldarg (mb
, argnum
);
6794 mono_mb_emit_stloc (mb
, dest_ptr
);
6796 if (eklass
->blittable
) {
6798 mono_mb_emit_ldarg (mb
, argnum
);
6800 mono_mb_emit_ldloc (mb
, conv_arg
);
6801 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6802 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
6803 mono_mb_emit_byte (mb
, CEE_ADD
);
6805 mono_mb_emit_ldloc (mb
, conv_arg
);
6806 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6807 mono_mb_emit_icon (mb
, esize
);
6808 mono_mb_emit_byte (mb
, CEE_MUL
);
6809 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6810 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6814 /* Emit marshalling loop */
6815 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6816 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6817 mono_mb_emit_stloc (mb
, index_var
);
6818 label2
= mono_mb_get_label (mb
);
6819 mono_mb_emit_ldloc (mb
, index_var
);
6820 mono_mb_emit_ldloc (mb
, conv_arg
);
6821 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6822 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6824 /* Emit marshalling code */
6827 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6830 mono_mb_emit_ldloc (mb
, dest_ptr
);
6833 mono_mb_emit_ldloc (mb
, conv_arg
);
6834 mono_mb_emit_ldloc (mb
, index_var
);
6836 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6838 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
6839 mono_mb_emit_byte (mb
, stind_op
);
6842 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
6843 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6847 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6848 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
6850 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6852 mono_mb_patch_branch (mb
, label1
);
6853 mono_mb_patch_branch (mb
, label3
);
6857 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
6859 guint32 label1
, label2
, label3
;
6860 int index_var
, src
, dest
, esize
;
6861 MonoMarshalConv conv
= MONO_MARSHAL_CONV_INVALID
;
6862 gboolean is_string
= FALSE
;
6864 g_assert (!t
->byref
);
6866 eklass
= klass
->element_class
;
6868 mono_marshal_load_type_info (eklass
);
6870 if (eklass
== mono_defaults
.string_class
) {
6872 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6875 g_assert_not_reached ();
6879 esize
= sizeof (gpointer
);
6880 else if (eklass
== mono_defaults
.char_class
)
6881 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
6883 esize
= mono_class_native_size (eklass
, NULL
);
6885 src
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6886 dest
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6888 mono_mb_emit_stloc (mb
, src
);
6889 mono_mb_emit_ldloc (mb
, src
);
6890 mono_mb_emit_stloc (mb
, 3);
6892 /* Check for null */
6893 mono_mb_emit_ldloc (mb
, src
);
6894 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6896 /* Allocate native array */
6897 mono_mb_emit_icon (mb
, esize
);
6898 mono_mb_emit_ldloc (mb
, src
);
6899 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6901 if (eklass
== mono_defaults
.string_class
) {
6902 /* Make the array bigger for the terminating null */
6903 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
6904 mono_mb_emit_byte (mb
, CEE_ADD
);
6906 mono_mb_emit_byte (mb
, CEE_MUL
);
6907 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
6908 mono_mb_emit_stloc (mb
, dest
);
6909 mono_mb_emit_ldloc (mb
, dest
);
6910 mono_mb_emit_stloc (mb
, 3);
6912 /* Emit marshalling loop */
6913 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6914 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6915 mono_mb_emit_stloc (mb
, index_var
);
6916 label2
= mono_mb_get_label (mb
);
6917 mono_mb_emit_ldloc (mb
, index_var
);
6918 mono_mb_emit_ldloc (mb
, src
);
6919 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6920 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6922 /* Emit marshalling code */
6925 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6928 mono_mb_emit_ldloc (mb
, dest
);
6931 mono_mb_emit_ldloc (mb
, src
);
6932 mono_mb_emit_ldloc (mb
, index_var
);
6934 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6936 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
6937 mono_mb_emit_byte (mb
, stind_op
);
6940 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
6941 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6945 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6946 mono_mb_emit_add_to_local (mb
, dest
, esize
);
6948 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6950 mono_mb_patch_branch (mb
, label3
);
6951 mono_mb_patch_branch (mb
, label1
);
6955 g_assert_not_reached ();
6962 marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
6965 return &mono_defaults
.int32_class
->byval_arg
;
6967 switch (spec
->native
) {
6968 case MONO_NATIVE_I1
:
6969 case MONO_NATIVE_U1
:
6970 return &mono_defaults
.byte_class
->byval_arg
;
6971 case MONO_NATIVE_VARIANTBOOL
:
6972 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
6973 return &mono_defaults
.int16_class
->byval_arg
;
6974 case MONO_NATIVE_BOOLEAN
:
6975 return &mono_defaults
.int32_class
->byval_arg
;
6977 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
6978 return &mono_defaults
.int32_class
->byval_arg
;
6984 marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
6986 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
6988 switch (spec
->native
) {
6989 case MONO_NATIVE_I1
:
6990 case MONO_NATIVE_U1
:
6991 conv_arg_class
= mono_defaults
.byte_class
;
6992 if (ldop
) *ldop
= CEE_LDIND_I1
;
6994 case MONO_NATIVE_VARIANTBOOL
:
6995 conv_arg_class
= mono_defaults
.int16_class
;
6996 if (ldop
) *ldop
= CEE_LDIND_I2
;
6998 case MONO_NATIVE_BOOLEAN
:
7001 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
7004 return conv_arg_class
;
7008 emit_marshal_boolean (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7009 MonoMarshalSpec
*spec
,
7010 int conv_arg
, MonoType
**conv_arg_type
,
7011 MarshalAction action
)
7015 case MARSHAL_ACTION_CONV_IN
:
7017 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7019 *conv_arg_type
= marshal_boolean_conv_in_get_local_type (spec
, NULL
);
7022 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7023 MonoClass
* conv_arg_class
= marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
7025 *conv_arg_type
= &conv_arg_class
->this_arg
;
7027 *conv_arg_type
= &conv_arg_class
->byval_arg
;
7033 MonoMethodBuilder
*mb
= m
->mb
;
7036 case MARSHAL_ACTION_CONV_IN
: {
7037 MonoType
*local_type
;
7039 guint8 ldc_op
= CEE_LDC_I4_1
;
7041 local_type
= marshal_boolean_conv_in_get_local_type (spec
, &ldc_op
);
7043 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7045 *conv_arg_type
= local_type
;
7046 conv_arg
= mono_mb_add_local (mb
, local_type
);
7048 mono_mb_emit_ldarg (mb
, argnum
);
7050 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
7051 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7052 mono_mb_emit_byte (mb
, ldc_op
);
7053 mono_mb_emit_stloc (mb
, conv_arg
);
7054 mono_mb_patch_branch (mb
, label_false
);
7059 case MARSHAL_ACTION_CONV_OUT
:
7061 int label_false
, label_end
;
7065 mono_mb_emit_ldarg (mb
, argnum
);
7066 mono_mb_emit_ldloc (mb
, conv_arg
);
7068 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7069 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7071 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
7072 mono_mb_patch_branch (mb
, label_false
);
7073 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7074 mono_mb_patch_branch (mb
, label_end
);
7076 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
7080 case MARSHAL_ACTION_PUSH
:
7082 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7084 mono_mb_emit_ldloc (mb
, conv_arg
);
7086 mono_mb_emit_ldarg (mb
, argnum
);
7089 case MARSHAL_ACTION_CONV_RESULT
:
7090 /* maybe we need to make sure that it fits within 8 bits */
7091 mono_mb_emit_stloc (mb
, 3);
7094 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7095 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
7096 guint8 ldop
= CEE_LDIND_I4
;
7097 int label_null
, label_false
;
7099 conv_arg_class
= marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, &ldop
);
7100 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
7103 *conv_arg_type
= &conv_arg_class
->this_arg
;
7105 *conv_arg_type
= &conv_arg_class
->byval_arg
;
7108 mono_mb_emit_ldarg (mb
, argnum
);
7112 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7113 mono_mb_emit_ldarg (mb
, argnum
);
7114 mono_mb_emit_byte (mb
, ldop
);
7118 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7119 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7120 mono_mb_emit_stloc (mb
, conv_arg
);
7121 mono_mb_patch_branch (mb
, label_false
);
7124 mono_mb_patch_branch (mb
, label_null
);
7128 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7129 guint8 stop
= CEE_STIND_I4
;
7130 guint8 ldc_op
= CEE_LDC_I4_1
;
7131 int label_null
,label_false
, label_end
;;
7136 switch (spec
->native
) {
7137 case MONO_NATIVE_I1
:
7138 case MONO_NATIVE_U1
:
7139 stop
= CEE_STIND_I1
;
7141 case MONO_NATIVE_VARIANTBOOL
:
7142 stop
= CEE_STIND_I2
;
7143 ldc_op
= CEE_LDC_I4_M1
;
7151 mono_mb_emit_ldarg (mb
, argnum
);
7152 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7154 mono_mb_emit_ldarg (mb
, argnum
);
7155 mono_mb_emit_ldloc (mb
, conv_arg
);
7157 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7158 mono_mb_emit_byte (mb
, ldc_op
);
7159 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
7161 mono_mb_patch_branch (mb
, label_false
);
7162 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7163 mono_mb_patch_branch (mb
, label_end
);
7165 mono_mb_emit_byte (mb
, stop
);
7166 mono_mb_patch_branch (mb
, label_null
);
7171 g_assert_not_reached ();
7178 emit_marshal_ptr (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7179 MonoMarshalSpec
*spec
, int conv_arg
,
7180 MonoType
**conv_arg_type
, MarshalAction action
)
7183 MonoMethodBuilder
*mb
= m
->mb
;
7186 case MARSHAL_ACTION_CONV_IN
:
7187 /* MS seems to allow this in some cases, ie. bxc #158 */
7189 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
7190 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
7191 mono_mb_emit_exception_marshal_directive (m->mb, msg);
7196 case MARSHAL_ACTION_PUSH
:
7197 mono_mb_emit_ldarg (mb
, argnum
);
7200 case MARSHAL_ACTION_CONV_RESULT
:
7201 /* no conversions necessary */
7202 mono_mb_emit_stloc (mb
, 3);
7213 emit_marshal_char (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7214 MonoMarshalSpec
*spec
, int conv_arg
,
7215 MonoType
**conv_arg_type
, MarshalAction action
)
7218 MonoMethodBuilder
*mb
= m
->mb
;
7221 case MARSHAL_ACTION_PUSH
:
7222 /* fixme: dont know how to marshal that. We cant simply
7223 * convert it to a one byte UTF8 character, because an
7224 * unicode character may need more that one byte in UTF8 */
7225 mono_mb_emit_ldarg (mb
, argnum
);
7228 case MARSHAL_ACTION_CONV_RESULT
:
7229 /* fixme: we need conversions here */
7230 mono_mb_emit_stloc (mb
, 3);
7241 emit_marshal_scalar (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7242 MonoMarshalSpec
*spec
, int conv_arg
,
7243 MonoType
**conv_arg_type
, MarshalAction action
)
7246 MonoMethodBuilder
*mb
= m
->mb
;
7249 case MARSHAL_ACTION_PUSH
:
7250 mono_mb_emit_ldarg (mb
, argnum
);
7253 case MARSHAL_ACTION_CONV_RESULT
:
7254 /* no conversions necessary */
7255 mono_mb_emit_stloc (mb
, 3);
7266 emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7267 MonoMarshalSpec
*spec
, int conv_arg
,
7268 MonoType
**conv_arg_type
, MarshalAction action
)
7270 /* Ensure that we have marshalling info for this param */
7271 mono_marshal_load_type_info (mono_class_from_mono_type (t
));
7273 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
7274 return emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7276 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
7277 return emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7280 case MONO_TYPE_VALUETYPE
:
7281 if (t
->data
.klass
== mono_defaults
.handleref_class
)
7282 return emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7284 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7285 case MONO_TYPE_STRING
:
7286 return emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7287 case MONO_TYPE_CLASS
:
7288 case MONO_TYPE_OBJECT
:
7289 #if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
7290 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
7291 return emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7294 #if !defined(DISABLE_COM)
7295 if (spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
7296 spec
->native
== MONO_NATIVE_IDISPATCH
||
7297 spec
->native
== MONO_NATIVE_INTERFACE
))
7298 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7299 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
7300 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
7301 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
7302 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7305 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
7306 mono_class_is_subclass_of (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
7307 return emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7309 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7310 case MONO_TYPE_ARRAY
:
7311 case MONO_TYPE_SZARRAY
:
7312 return emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7313 case MONO_TYPE_BOOLEAN
:
7314 return emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7316 return emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7317 case MONO_TYPE_CHAR
:
7318 return emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7331 case MONO_TYPE_FNPTR
:
7332 return emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7333 case MONO_TYPE_GENERICINST
:
7334 if (mono_type_generic_inst_is_valuetype (t
))
7335 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7337 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7345 * mono_marshal_emit_native_wrapper:
7346 * @image: the image to use for looking up custom marshallers
7347 * @sig: The signature of the native function
7348 * @piinfo: Marshalling information
7349 * @mspecs: Marshalling information
7350 * @aot: whenever the created method will be compiled by the AOT compiler
7351 * @method: if non-NULL, the pinvoke method to call
7352 * @check_exceptions: Whenever to check for pending exceptions after the native call
7353 * @func_param: the function to call is passed as a boxed IntPtr as the first parameter
7355 * generates IL code for the pinvoke wrapper, the generated code calls @func.
7358 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
)
7360 EmitMarshalContext m
;
7361 MonoMethodSignature
*csig
;
7363 int i
, argnum
, *tmp_locals
;
7364 int type
, param_shift
= 0;
7365 int coop_gc_stack_dummy
, coop_gc_var
;
7367 memset (&m
, 0, sizeof (m
));
7372 /* we copy the signature, so that we can set pinvoke to 0 */
7374 /* The function address is passed as the first argument */
7375 g_assert (!sig
->hasthis
);
7378 csig
= mono_metadata_signature_dup_full (mb
->method
->klass
->image
, sig
);
7386 /* we allocate local for use with emit_struct_conv() */
7387 /* allocate local 0 (pointer) src_ptr */
7388 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7389 /* allocate local 1 (pointer) dst_ptr */
7390 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7391 /* allocate local 2 (boolean) delete_old */
7392 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
7394 /* delete_old = FALSE */
7395 mono_mb_emit_icon (mb
, 0);
7396 mono_mb_emit_stloc (mb
, 2);
7398 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
7399 /* allocate local 3 to store the return value */
7400 mono_mb_add_local (mb
, sig
->ret
);
7403 if (mono_threads_is_coop_enabled ()) {
7404 /* local 4, dummy local used to get a stack address for suspend funcs */
7405 coop_gc_stack_dummy
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7406 /* local 5, the local to be used when calling the suspend funcs */
7407 coop_gc_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7411 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
7413 * ret = method (...);
7415 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
7422 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
7423 m
.vtaddr_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7425 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
7426 /* Return type custom marshaling */
7428 * Since we can't determine the return type of the unmanaged function,
7429 * we assume it returns a pointer, and pass that pointer to
7430 * MarshalNativeToManaged.
7432 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
7435 /* we first do all conversions */
7436 tmp_locals
= (int *)alloca (sizeof (int) * sig
->param_count
);
7437 m
.orig_conv_args
= (int *)alloca (sizeof (int) * (sig
->param_count
+ 1));
7439 for (i
= 0; i
< sig
->param_count
; i
++) {
7440 tmp_locals
[i
] = emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
7443 // In coop mode need to register blocking state during native call
7444 if (mono_threads_is_coop_enabled ()) {
7445 // Perform an extra, early lookup of the function address, so any exceptions
7446 // potentially resulting from the lookup occur before entering blocking mode.
7447 if (!func_param
&& !MONO_CLASS_IS_IMPORT (mb
->method
->klass
) && aot
) {
7448 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7449 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
7450 mono_mb_emit_byte (mb
, CEE_POP
); // Result not needed yet
7453 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
7454 mono_mb_emit_icall (mb
, mono_threads_enter_gc_safe_region_unbalanced
);
7455 mono_mb_emit_stloc (mb
, coop_gc_var
);
7458 /* push all arguments */
7461 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7463 for (i
= 0; i
< sig
->param_count
; i
++) {
7464 emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
7467 /* call the native method */
7469 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7470 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_defaults
.int_class
);
7471 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7472 mono_mb_emit_calli (mb
, csig
);
7473 } else if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
7475 mono_mb_emit_cominterop_call (mb
, csig
, &piinfo
->method
);
7477 g_assert_not_reached ();
7481 /* Reuse the ICALL_ADDR opcode for pinvokes too */
7482 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7483 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
7484 mono_mb_emit_calli (mb
, csig
);
7486 mono_mb_emit_native_call (mb
, csig
, func
);
7490 /* Set LastError if needed */
7491 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
7494 static MonoMethodSignature
*get_last_error_sig
= NULL
;
7495 if (!get_last_error_sig
) {
7496 get_last_error_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
7497 get_last_error_sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
7498 get_last_error_sig
->pinvoke
= 1;
7502 * Have to call GetLastError () early and without a wrapper, since various runtime components could
7503 * clobber its value.
7505 mono_mb_emit_native_call (mb
, get_last_error_sig
, GetLastError
);
7506 mono_mb_emit_icall (mb
, mono_marshal_set_last_error_windows
);
7508 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7509 mono_mb_emit_byte (mb
, CEE_MONO_GET_LAST_ERROR
);
7510 mono_mb_emit_icall (mb
, mono_marshal_set_last_error_windows
);
7513 mono_mb_emit_icall (mb
, mono_marshal_set_last_error
);
7517 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
7518 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
7519 mono_class_init (klass
);
7520 if (!(((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) || klass
->blittable
)) {
7521 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
7522 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7523 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
7524 mono_mb_emit_stloc (mb
, m
.vtaddr_var
);
7528 /* Unblock before converting the result, since that can involve calls into the runtime */
7529 if (mono_threads_is_coop_enabled ()) {
7530 mono_mb_emit_ldloc (mb
, coop_gc_var
);
7531 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
7532 mono_mb_emit_icall (mb
, mono_threads_exit_gc_safe_region_unbalanced
);
7535 /* convert the result */
7536 if (!sig
->ret
->byref
) {
7537 MonoMarshalSpec
*spec
= mspecs
[0];
7538 type
= sig
->ret
->type
;
7540 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
7541 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
7545 case MONO_TYPE_VOID
:
7547 case MONO_TYPE_VALUETYPE
:
7548 klass
= sig
->ret
->data
.klass
;
7549 if (klass
->enumtype
) {
7550 type
= mono_class_enum_basetype (sig
->ret
->data
.klass
)->type
;
7553 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
7567 case MONO_TYPE_FNPTR
:
7568 case MONO_TYPE_STRING
:
7569 case MONO_TYPE_CLASS
:
7570 case MONO_TYPE_OBJECT
:
7571 case MONO_TYPE_BOOLEAN
:
7572 case MONO_TYPE_ARRAY
:
7573 case MONO_TYPE_SZARRAY
:
7574 case MONO_TYPE_CHAR
:
7576 case MONO_TYPE_GENERICINST
:
7577 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
7579 case MONO_TYPE_TYPEDBYREF
:
7581 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
7582 g_assert_not_reached ();
7586 mono_mb_emit_stloc (mb
, 3);
7590 * Need to call this after converting the result since MONO_VTADDR needs
7591 * to be adjacent to the call instruction.
7593 if (check_exceptions
)
7594 emit_thread_interrupt_checkpoint (mb
);
7596 /* we need to convert byref arguments back and free string arrays */
7597 for (i
= 0; i
< sig
->param_count
; i
++) {
7598 MonoType
*t
= sig
->params
[i
];
7599 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
7601 argnum
= i
+ param_shift
;
7603 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
7604 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
7609 case MONO_TYPE_STRING
:
7610 case MONO_TYPE_VALUETYPE
:
7611 case MONO_TYPE_CLASS
:
7612 case MONO_TYPE_OBJECT
:
7613 case MONO_TYPE_SZARRAY
:
7614 case MONO_TYPE_BOOLEAN
:
7615 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
7622 if (!MONO_TYPE_IS_VOID(sig
->ret
))
7623 mono_mb_emit_ldloc (mb
, 3);
7625 mono_mb_emit_byte (mb
, CEE_RET
);
7627 #endif /* DISABLE_JIT */
7630 * mono_marshal_get_native_wrapper:
7631 * @method: The MonoMethod to wrap.
7632 * @check_exceptions: Whenever to check for pending exceptions
7634 * generates IL code for the pinvoke wrapper (the generated method
7635 * calls the unmanaged code in piinfo->addr)
7638 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
7640 MonoMethodSignature
*sig
, *csig
;
7641 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
7642 MonoMethodBuilder
*mb
;
7643 MonoMarshalSpec
**mspecs
;
7646 gboolean pinvoke
= FALSE
;
7649 const char *exc_class
= "MissingMethodException";
7650 const char *exc_arg
= NULL
;
7653 g_assert (method
!= NULL
);
7654 g_assert (mono_method_signature (method
)->pinvoke
);
7656 GHashTable
**cache_ptr
;
7659 if (check_exceptions
)
7660 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
7662 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
7664 if (check_exceptions
)
7665 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
7667 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
7670 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
7672 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
7675 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
7676 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
7680 return mono_cominterop_get_native_wrapper (method
);
7682 g_assert_not_reached ();
7686 sig
= mono_method_signature (method
);
7688 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
7689 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
7692 if (!piinfo
->addr
) {
7694 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
7695 exc_arg
= "Method contains unsupported native code";
7697 mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
7699 piinfo
->addr
= mono_lookup_internal_call (method
);
7703 /* hack - redirect certain string constructors to CreateString */
7704 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
7705 g_assert (!pinvoke
);
7706 g_assert (method
->string_ctor
);
7707 g_assert (sig
->hasthis
);
7709 /* CreateString returns a value */
7710 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7711 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
7715 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
7716 if (!strcmp ("CreateString", res
->name
) &&
7717 mono_metadata_signature_equal (csig
, mono_method_signature (res
))) {
7720 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
7721 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
7723 /* create a wrapper to preserve .ctor in stack trace */
7724 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
7727 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7728 for (i
= 1; i
<= csig
->param_count
; i
++)
7729 mono_mb_emit_ldarg (mb
, i
);
7730 mono_mb_emit_managed_call (mb
, res
, NULL
);
7731 mono_mb_emit_byte (mb
, CEE_RET
);
7734 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
7735 info
->d
.string_ctor
.method
= method
;
7737 /* use native_wrapper_cache because internal calls are looked up there */
7738 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
7739 csig
->param_count
+ 1, info
, NULL
);
7746 /* exception will be thrown */
7747 piinfo
->addr
= NULL
;
7748 g_warning ("cannot find CreateString for .ctor");
7751 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
7753 mb
->method
->save_lmf
= 1;
7756 * In AOT mode and embedding scenarios, it is possible that the icall is not
7757 * registered in the runtime doing the AOT compilation.
7759 if (!piinfo
->addr
&& !aot
) {
7761 mono_mb_emit_exception (mb
, exc_class
, exc_arg
);
7763 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
7764 info
->d
.managed_to_native
.method
= method
;
7766 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7768 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
7769 csig
->param_count
+ 16, info
, NULL
);
7775 /* internal calls: we simply push all arguments and call the method (no conversions) */
7776 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
7778 csig
= mono_metadata_signature_dup_add_this (method
->klass
->image
, sig
, method
->klass
);
7780 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7782 //printf ("%s\n", mono_method_full_name (method, 1));
7784 /* hack - string constructors returns a value */
7785 if (method
->string_ctor
)
7786 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
7790 MonoClass
*handle_stack_mark_class
;
7791 MonoClass
*error_class
;
7792 int thread_info_var
= -1, stack_mark_var
= -1, error_var
= -1;
7793 MonoMethodSignature
*call_sig
= csig
;
7794 gboolean uses_handles
= FALSE
;
7795 (void) mono_lookup_internal_call_full (method
, &uses_handles
);
7798 /* If it uses handles and MonoError, it had better check exceptions */
7799 g_assert (!uses_handles
|| check_exceptions
);
7802 MonoMethodSignature
*ret
;
7804 /* Add a MonoError argument */
7805 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
7806 ret
= mono_metadata_signature_alloc (method
->klass
->image
, csig
->param_count
+ 1);
7808 ret
->param_count
= csig
->param_count
+ 1;
7809 ret
->ret
= csig
->ret
;
7810 for (int i
= 0; i
< csig
->param_count
; ++i
) {
7811 // FIXME: TODO implement handle wrapping for out and inout params.
7812 g_assert (!mono_signature_param_is_out (csig
, i
));
7813 ret
->params
[i
] = csig
->params
[i
];
7815 ret
->params
[csig
->param_count
] = &mono_get_intptr_class ()->byval_arg
;
7820 handle_stack_mark_class
= mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
7821 error_class
= mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
7823 thread_info_var
= mono_mb_add_local (mb
, &mono_get_intptr_class ()->byval_arg
);
7824 stack_mark_var
= mono_mb_add_local (mb
, &handle_stack_mark_class
->byval_arg
);
7825 error_var
= mono_mb_add_local (mb
, &error_class
->byval_arg
);
7827 // FIXME: Change csig so it passes a handle not an objref
7834 * Add a null check since public icalls can be called with 'call' which
7835 * does no such check.
7837 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7838 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
7839 mono_mb_emit_exception (mb
, "NullReferenceException", NULL
);
7840 mono_mb_patch_branch (mb
, pos
);
7844 mono_mb_emit_ldloc_addr (mb
, stack_mark_var
);
7845 mono_mb_emit_ldloc_addr (mb
, error_var
);
7846 mono_mb_emit_icall (mb
, mono_icall_start
);
7847 mono_mb_emit_stloc (mb
, thread_info_var
);
7850 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7851 mono_mb_emit_icall (mb
, mono_handle_new
);
7853 for (i
= 0; i
< sig
->param_count
; i
++) {
7854 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
7855 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
7856 mono_mb_emit_icall (mb
, mono_handle_new
);
7859 mono_mb_emit_ldloc_addr (mb
, error_var
);
7862 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7863 for (i
= 0; i
< sig
->param_count
; i
++)
7864 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
7868 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7869 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
7870 mono_mb_emit_calli (mb
, call_sig
);
7872 g_assert (piinfo
->addr
);
7873 mono_mb_emit_native_call (mb
, call_sig
, piinfo
->addr
);
7877 if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
7878 // if (ret != NULL_HANDLE) {
7879 // ret = MONO_HANDLE_RAW(ret)
7881 mono_mb_emit_byte (mb
, CEE_DUP
);
7882 int pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7883 mono_mb_emit_ldflda (mb
, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject
));
7884 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7885 mono_mb_patch_branch (mb
, pos
);
7887 mono_mb_emit_ldloc (mb
, thread_info_var
);
7888 mono_mb_emit_ldloc_addr (mb
, stack_mark_var
);
7889 mono_mb_emit_ldloc_addr (mb
, error_var
);
7890 mono_mb_emit_icall (mb
, mono_icall_end
);
7893 if (check_exceptions
)
7894 emit_thread_interrupt_checkpoint (mb
);
7895 mono_mb_emit_byte (mb
, CEE_RET
);
7897 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
7898 info
->d
.managed_to_native
.method
= method
;
7900 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, csig
);
7902 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
7911 g_assert (piinfo
->addr
);
7914 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
7915 mono_method_get_marshal_info (method
, mspecs
);
7917 mono_marshal_emit_native_wrapper (mb
->method
->klass
->image
, mb
, sig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
);
7919 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
7920 info
->d
.managed_to_native
.method
= method
;
7922 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7924 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
7929 for (i
= sig
->param_count
; i
>= 0; i
--)
7931 mono_metadata_free_marshal_spec (mspecs
[i
]);
7935 /* mono_method_print_code (res); */
7941 * mono_marshal_get_native_func_wrapper:
7942 * @image: The image to use for memory allocation and for looking up custom marshallers.
7943 * @sig: The signature of the function
7944 * @func: The native function to wrap
7946 * Returns a wrapper method around native functions, similar to the pinvoke
7950 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
7951 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
7953 MonoMethodSignature
*csig
;
7955 SignaturePointerPair key
, *new_key
;
7956 MonoMethodBuilder
*mb
;
7965 // Generic types are not safe to place in MonoImage caches.
7966 g_assert (!sig
->is_inflated
);
7968 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
7969 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
7972 name
= g_strdup_printf ("wrapper_native_%p", func
);
7973 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
7974 mb
->method
->save_lmf
= 1;
7977 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
);
7980 csig
= mono_metadata_signature_dup_full (image
, sig
);
7983 new_key
= g_new (SignaturePointerPair
,1);
7984 new_key
->sig
= csig
;
7985 new_key
->pointer
= func
;
7987 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
7993 mono_marshal_set_wrapper_info (res
, NULL
);
7999 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
8003 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
8005 MonoMethodSignature
*sig
, *csig
;
8006 MonoMethodBuilder
*mb
;
8011 MonoMethodPInvoke mpiinfo
;
8012 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
8013 MonoMarshalSpec
**mspecs
;
8014 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
8015 MonoImage
*image
= invoke
->klass
->image
;
8018 // FIXME: include UnmanagedFunctionPointerAttribute info
8021 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
8023 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
8025 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
8028 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
8029 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
8031 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
8032 mono_method_get_marshal_info (invoke
, mspecs
);
8033 /* Freed below so don't alloc from mempool */
8034 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
8037 name
= g_strdup_printf ("wrapper_aot_native");
8038 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8039 mb
->method
->save_lmf
= 1;
8042 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
);
8045 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
8046 info
->d
.managed_to_native
.method
= invoke
;
8048 g_assert (!sig
->hasthis
);
8049 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
8051 res
= mono_mb_create_and_cache_full (cache
, invoke
,
8052 mb
, csig
, csig
->param_count
+ 16,
8056 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
8058 mono_metadata_free_marshal_spec (mspecs
[i
]);
8066 * mono_marshal_emit_managed_wrapper:
8068 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
8069 * the delegate which wraps the managed method to be called. For closed delegates,
8070 * it could have fewer parameters than the method it wraps.
8071 * THIS_LOC is the memory location where the target of the delegate is stored.
8074 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
8077 MonoMethodSignature
*sig
, *csig
;
8083 /* we first do all conversions */
8084 for (i
= 0; i
< sig
->param_count
; i
++) {
8085 MonoType
*t
= sig
->params
[i
];
8088 case MONO_TYPE_OBJECT
:
8089 case MONO_TYPE_CLASS
:
8090 case MONO_TYPE_VALUETYPE
:
8091 case MONO_TYPE_ARRAY
:
8092 case MONO_TYPE_SZARRAY
:
8093 case MONO_TYPE_STRING
:
8094 case MONO_TYPE_BOOLEAN
:
8095 emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
8099 if (!sig
->ret
->byref
) {
8100 switch (sig
->ret
->type
) {
8101 case MONO_TYPE_STRING
:
8102 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8109 MonoMethodSignature
*sig
, *csig
;
8110 MonoExceptionClause
*clauses
, *clause_finally
, *clause_catch
;
8111 int i
, *tmp_locals
, ex_local
, e_local
, attach_cookie_local
, attach_dummy_local
;
8112 int leave_try_pos
, leave_catch_pos
, ex_m1_pos
;
8113 gboolean closed
= FALSE
;
8118 /* allocate local 0 (pointer) src_ptr */
8119 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8120 /* allocate local 1 (pointer) dst_ptr */
8121 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8122 /* allocate local 2 (boolean) delete_old */
8123 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
8125 if (!sig
->hasthis
&& sig
->param_count
!= invoke_sig
->param_count
) {
8126 /* Closed delegate */
8127 g_assert (sig
->param_count
== invoke_sig
->param_count
+ 1);
8129 /* Use a new signature without the first argument */
8130 sig
= mono_metadata_signature_dup (sig
);
8131 memmove (&sig
->params
[0], &sig
->params
[1], (sig
->param_count
- 1) * sizeof (MonoType
*));
8132 sig
->param_count
--;
8135 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
8136 /* allocate local 3 to store the return value */
8137 mono_mb_add_local (mb
, sig
->ret
);
8140 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
8141 m
->vtaddr_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8143 ex_local
= mono_mb_add_local (mb
, &mono_defaults
.uint32_class
->byval_arg
);
8144 e_local
= mono_mb_add_local (mb
, &mono_defaults
.exception_class
->byval_arg
);
8146 attach_cookie_local
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8147 attach_dummy_local
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8152 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
8153 * mono_threads_attach_coop ();
8157 * ret = method (...);
8158 * } catch (Exception e) {
8159 * ex = mono_gchandle_new (e, false);
8161 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
8162 * mono_threads_detach_coop ();
8165 * mono_marshal_ftnptr_eh_callback (ex);
8171 clauses
= g_new0 (MonoExceptionClause
, 2);
8173 clause_catch
= &clauses
[0];
8174 clause_catch
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
8175 clause_catch
->data
.catch_class
= mono_defaults
.exception_class
;
8177 clause_finally
= &clauses
[1];
8178 clause_finally
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
8180 mono_mb_emit_icon (mb
, 0);
8181 mono_mb_emit_stloc (mb
, 2);
8183 mono_mb_emit_icon (mb
, -1);
8184 mono_mb_emit_byte (mb
, CEE_CONV_U4
);
8185 mono_mb_emit_stloc (mb
, ex_local
);
8188 clause_catch
->try_offset
= clause_finally
->try_offset
= mono_mb_get_label (mb
);
8190 if (!mono_threads_is_coop_enabled ()) {
8191 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8192 mono_mb_emit_byte (mb
, CEE_MONO_JIT_ATTACH
);
8194 /* mono_threads_attach_coop (); */
8195 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8196 mono_mb_emit_byte (mb
, CEE_MONO_LDDOMAIN
);
8197 mono_mb_emit_ldloc_addr (mb
, attach_dummy_local
);
8198 mono_mb_emit_icall (mb
, mono_threads_attach_coop
);
8199 mono_mb_emit_stloc (mb
, attach_cookie_local
);
8202 /* <interrupt check> */
8203 emit_thread_interrupt_checkpoint (mb
);
8205 /* we first do all conversions */
8206 tmp_locals
= (int *)alloca (sizeof (int) * sig
->param_count
);
8207 for (i
= 0; i
< sig
->param_count
; i
++) {
8208 MonoType
*t
= sig
->params
[i
];
8211 case MONO_TYPE_OBJECT
:
8212 case MONO_TYPE_CLASS
:
8213 case MONO_TYPE_VALUETYPE
:
8214 case MONO_TYPE_ARRAY
:
8215 case MONO_TYPE_SZARRAY
:
8216 case MONO_TYPE_STRING
:
8217 case MONO_TYPE_BOOLEAN
:
8218 tmp_locals
[i
] = emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
8228 if (target_handle
) {
8229 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
8230 mono_mb_emit_icall (mb
, mono_gchandle_get_target
);
8233 g_assert_not_reached ();
8235 } else if (closed
) {
8236 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
8237 mono_mb_emit_icall (mb
, mono_gchandle_get_target
);
8240 for (i
= 0; i
< sig
->param_count
; i
++) {
8241 MonoType
*t
= sig
->params
[i
];
8243 if (tmp_locals
[i
]) {
8245 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
8247 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
8250 mono_mb_emit_ldarg (mb
, i
);
8253 /* ret = method (...) */
8254 mono_mb_emit_managed_call (mb
, method
, NULL
);
8256 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
8257 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
8258 mono_class_init (klass
);
8259 if (!(((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) || klass
->blittable
)) {
8260 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
8261 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8262 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
8263 mono_mb_emit_stloc (mb
, m
->vtaddr_var
);
8267 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
8268 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8269 } else if (!sig
->ret
->byref
) {
8270 switch (sig
->ret
->type
) {
8271 case MONO_TYPE_VOID
:
8273 case MONO_TYPE_BOOLEAN
:
8276 case MONO_TYPE_CHAR
:
8288 case MONO_TYPE_OBJECT
:
8289 mono_mb_emit_stloc (mb
, 3);
8291 case MONO_TYPE_STRING
:
8292 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8293 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8295 case MONO_TYPE_VALUETYPE
:
8296 case MONO_TYPE_CLASS
:
8297 case MONO_TYPE_SZARRAY
:
8298 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8301 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
8302 g_assert_not_reached ();
8305 mono_mb_emit_stloc (mb
, 3);
8308 /* Convert byref arguments back */
8309 for (i
= 0; i
< sig
->param_count
; i
++) {
8310 MonoType
*t
= sig
->params
[i
];
8311 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
8313 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
8314 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8316 else if (t
->byref
) {
8318 case MONO_TYPE_CLASS
:
8319 case MONO_TYPE_VALUETYPE
:
8320 case MONO_TYPE_OBJECT
:
8321 case MONO_TYPE_STRING
:
8322 case MONO_TYPE_BOOLEAN
:
8323 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8329 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
8330 /* The [Out] information is encoded in the delegate signature */
8332 case MONO_TYPE_SZARRAY
:
8333 case MONO_TYPE_CLASS
:
8334 case MONO_TYPE_VALUETYPE
:
8335 emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8338 g_assert_not_reached ();
8343 leave_try_pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
8347 /* catch (Exception e) { */
8348 clause_catch
->try_len
= mono_mb_get_label (mb
) - clause_catch
->try_offset
;
8349 clause_catch
->handler_offset
= mono_mb_get_label (mb
);
8351 mono_mb_emit_stloc (mb
, e_local
);
8353 /* ex = mono_gchandle_new (e, false); */
8354 mono_mb_emit_ldloc (mb
, e_local
);
8355 mono_mb_emit_icon (mb
, 0);
8356 mono_mb_emit_icall (mb
, mono_gchandle_new
);
8357 mono_mb_emit_stloc (mb
, ex_local
);
8359 leave_catch_pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
8362 clause_catch
->handler_len
= mono_mb_get_pos (mb
) - clause_catch
->handler_offset
;
8365 clause_finally
->try_len
= mono_mb_get_label (mb
) - clause_finally
->try_offset
;
8366 clause_finally
->handler_offset
= mono_mb_get_label (mb
);
8368 if (!mono_threads_is_coop_enabled ()) {
8369 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8370 mono_mb_emit_byte (mb
, CEE_MONO_JIT_DETACH
);
8372 /* mono_threads_detach_coop (); */
8373 mono_mb_emit_ldloc (mb
, attach_cookie_local
);
8374 mono_mb_emit_ldloc_addr (mb
, attach_dummy_local
);
8375 mono_mb_emit_icall (mb
, mono_threads_detach_coop
);
8379 mono_mb_emit_ldloc (mb
, ex_local
);
8380 mono_mb_emit_icon (mb
, -1);
8381 mono_mb_emit_byte (mb
, CEE_CONV_U4
);
8382 ex_m1_pos
= mono_mb_emit_branch (mb
, CEE_BEQ
);
8384 /* mono_marshal_ftnptr_eh_callback (ex) */
8385 mono_mb_emit_ldloc (mb
, ex_local
);
8386 mono_mb_emit_icall (mb
, mono_marshal_ftnptr_eh_callback
);
8389 mono_mb_patch_branch (mb
, ex_m1_pos
);
8391 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
8393 /* } [endfinally] */
8394 clause_finally
->handler_len
= mono_mb_get_pos (mb
) - clause_finally
->handler_offset
;
8396 mono_mb_patch_branch (mb
, leave_try_pos
);
8397 mono_mb_patch_branch (mb
, leave_catch_pos
);
8400 if (m
->retobj_var
) {
8401 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
8402 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8403 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
8406 if (!MONO_TYPE_IS_VOID(sig
->ret
))
8407 mono_mb_emit_ldloc (mb
, 3);
8408 mono_mb_emit_byte (mb
, CEE_RET
);
8411 mono_mb_set_clauses (mb
, 2, clauses
);
8419 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
)
8421 MonoMethodSignature
*sig
;
8426 * Under windows, delegates passed to native code must use the STDCALL
8427 * calling convention.
8429 csig
->call_convention
= MONO_CALL_STDCALL
;
8432 sig
= mono_method_signature (method
);
8434 /* Change default calling convention if needed */
8435 /* Why is this a modopt ? */
8436 if (sig
->ret
&& sig
->ret
->num_mods
) {
8437 for (i
= 0; i
< sig
->ret
->num_mods
; ++i
) {
8439 MonoClass
*cmod_class
= mono_class_get_checked (method
->klass
->image
, sig
->ret
->modifiers
[i
].token
, &error
);
8440 g_assert (mono_error_ok (&error
));
8441 if ((cmod_class
->image
== mono_defaults
.corlib
) && !strcmp (cmod_class
->name_space
, "System.Runtime.CompilerServices")) {
8442 if (!strcmp (cmod_class
->name
, "CallConvCdecl"))
8443 csig
->call_convention
= MONO_CALL_C
;
8444 else if (!strcmp (cmod_class
->name
, "CallConvStdcall"))
8445 csig
->call_convention
= MONO_CALL_STDCALL
;
8446 else if (!strcmp (cmod_class
->name
, "CallConvFastcall"))
8447 csig
->call_convention
= MONO_CALL_FASTCALL
;
8448 else if (!strcmp (cmod_class
->name
, "CallConvThiscall"))
8449 csig
->call_convention
= MONO_CALL_THISCALL
;
8456 * generates IL code to call managed methods from unmanaged code
8457 * If target_handle==0, the wrapper info will be a WrapperInfo structure.
8460 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
)
8463 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
8464 MonoMethodBuilder
*mb
;
8465 MonoMethod
*res
, *invoke
;
8466 MonoMarshalSpec
**mspecs
;
8467 MonoMethodPInvoke piinfo
;
8470 EmitMarshalContext m
;
8472 g_assert (method
!= NULL
);
8473 g_assert (!(method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
8476 * FIXME: Should cache the method+delegate type pair, since the same method
8477 * could be called with different delegates, thus different marshalling
8480 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
8482 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
8485 invoke
= mono_get_delegate_invoke (delegate_klass
);
8486 invoke_sig
= mono_method_signature (invoke
);
8488 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
8489 mono_method_get_marshal_info (invoke
, mspecs
);
8491 sig
= mono_method_signature (method
);
8493 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8495 /*the target gchandle must be the first entry after size and the wrapper itself.*/
8496 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
8498 /* we copy the signature, so that we can modify it */
8500 /* Need to free this later */
8501 csig
= mono_metadata_signature_dup (invoke_sig
);
8503 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, invoke_sig
);
8507 memset (&m
, 0, sizeof (m
));
8513 m
.image
= method
->klass
->image
;
8515 mono_marshal_set_callconv_from_modopt (invoke
, csig
);
8517 /* The attribute is only available in Net 2.0 */
8518 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
8519 MonoCustomAttrInfo
*cinfo
;
8520 MonoCustomAttrEntry
*attr
;
8523 * The pinvoke attributes are stored in a real custom attribute. Obtain the
8524 * contents of the attribute without constructing it, as that might not be
8525 * possible when running in cross-compiling mode.
8527 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, &error
);
8528 mono_error_assert_ok (&error
);
8531 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
8532 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
8533 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
8534 attr
= &cinfo
->attrs
[i
];
8540 MonoArray
*typed_args
, *named_args
;
8541 CattrNamedArg
*arginfo
;
8545 MonoBoolean set_last_error
= 0;
8548 mono_reflection_create_custom_attr_data_args (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
, &error
);
8549 g_assert (mono_error_ok (&error
));
8550 g_assert (mono_array_length (typed_args
) == 1);
8553 o
= mono_array_get (typed_args
, MonoObject
*, 0);
8554 call_conv
= *(gint32
*)mono_object_unbox (o
);
8557 for (i
= 0; i
< mono_array_length (named_args
); ++i
) {
8558 CattrNamedArg
*narg
= &arginfo
[i
];
8560 o
= mono_array_get (named_args
, MonoObject
*, i
);
8562 g_assert (narg
->field
);
8563 if (!strcmp (narg
->field
->name
, "CharSet")) {
8564 charset
= *(gint32
*)mono_object_unbox (o
);
8565 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
8566 set_last_error
= *(MonoBoolean
*)mono_object_unbox (o
);
8567 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
8568 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox (o);
8569 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
8570 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox (o);
8572 g_assert_not_reached ();
8578 memset (&piinfo
, 0, sizeof (piinfo
));
8580 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
8582 csig
->call_convention
= call_conv
- 1;
8585 if (cinfo
&& !cinfo
->cached
)
8586 mono_custom_attrs_free (cinfo
);
8589 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
8591 if (!target_handle
) {
8594 // FIXME: Associate it with the method+delegate_klass pair
8595 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
8596 info
->d
.native_to_managed
.method
= method
;
8597 info
->d
.native_to_managed
.klass
= delegate_klass
;
8599 res
= mono_mb_create_and_cache_full (cache
, method
,
8600 mb
, csig
, sig
->param_count
+ 16,
8606 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
8610 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
8612 mono_metadata_free_marshal_spec (mspecs
[i
]);
8615 /* mono_method_print_code (res); */
8621 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
8625 MonoMethodSignature
*sig
;
8626 MonoMethodBuilder
*mb
;
8631 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, &error
);
8633 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (&error
));
8636 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
8637 MonoMethodSignature
*csig
;
8638 MonoMarshalSpec
**mspecs
;
8639 EmitMarshalContext m
;
8641 sig
= mono_method_signature (method
);
8642 g_assert (!sig
->hasthis
);
8644 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
8645 mono_method_get_marshal_info (method
, mspecs
);
8647 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8648 csig
= mono_metadata_signature_dup_full (image
, sig
);
8652 memset (&m
, 0, sizeof (m
));
8660 mono_marshal_set_callconv_from_modopt (method
, csig
);
8662 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
8664 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
8669 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
8672 for (i
= sig
->param_count
; i
>= 0; i
--)
8674 mono_metadata_free_marshal_spec (mspecs
[i
]);
8677 gpointer compiled_ptr
= mono_compile_method_checked (method
, &error
);
8678 mono_error_assert_ok (&error
);
8679 return compiled_ptr
;
8682 sig
= mono_method_signature (method
);
8683 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
8685 param_count
= sig
->param_count
+ sig
->hasthis
;
8687 for (i
= 0; i
< param_count
; i
++)
8688 mono_mb_emit_ldarg (mb
, i
);
8690 if (type
& VTFIXUP_TYPE_CALL_MOST_DERIVED
)
8691 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
8693 mono_mb_emit_op (mb
, CEE_CALL
, method
);
8694 mono_mb_emit_byte (mb
, CEE_RET
);
8699 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
8702 gpointer compiled_ptr
= mono_compile_method_checked (method
, &error
);
8703 mono_error_assert_ok (&error
);
8704 return compiled_ptr
;
8710 * The code directly following this is the cache hit, value positive branch
8712 * This function takes a new method builder with 0 locals and adds two locals
8713 * to create multiple out-branches and the fall through state of having the object
8714 * on the stack after a cache miss
8717 generate_check_cache (int obj_arg_position
, int class_arg_position
, int cache_arg_position
, // In-parameters
8718 int *null_obj
, int *cache_hit_neg
, int *cache_hit_pos
, // Out-parameters
8719 MonoMethodBuilder
*mb
)
8723 /* allocate local 0 (pointer) obj_vtable */
8724 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8725 /* allocate local 1 (pointer) cached_vtable */
8726 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8729 mono_mb_emit_ldarg (mb
, obj_arg_position
);
8730 *null_obj
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8732 /*obj_vtable = obj->vtable;*/
8733 mono_mb_emit_ldarg (mb
, obj_arg_position
);
8734 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
8735 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
8736 mono_mb_emit_stloc (mb
, 0);
8738 /* cached_vtable = *cache*/
8739 mono_mb_emit_ldarg (mb
, cache_arg_position
);
8740 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
8741 mono_mb_emit_stloc (mb
, 1);
8743 mono_mb_emit_ldloc (mb
, 1);
8744 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
8745 mono_mb_emit_i4 (mb
, ~0x1);
8746 mono_mb_emit_byte (mb
, CEE_CONV_I
);
8747 mono_mb_emit_byte (mb
, CEE_AND
);
8748 mono_mb_emit_ldloc (mb
, 0);
8749 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
8750 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
8752 /*return (cached_vtable & 0x1) ? NULL : obj;*/
8753 mono_mb_emit_ldloc (mb
, 1);
8754 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
8755 mono_mb_emit_byte (mb
, CEE_CONV_U
);
8756 mono_mb_emit_byte (mb
, CEE_AND
);
8757 *cache_hit_neg
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
8758 *cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BR
);
8761 mono_mb_patch_branch (mb
, cache_miss_pos
);
8764 mono_mb_emit_ldarg (mb
, obj_arg_position
);
8765 mono_mb_emit_ldarg (mb
, class_arg_position
);
8766 mono_mb_emit_ldarg (mb
, cache_arg_position
);
8767 mono_mb_emit_icall (mb
, mono_marshal_isinst_with_cache
);
8770 #endif /* DISABLE_JIT */
8773 * This does the equivalent of mono_object_castclass_with_cache.
8776 mono_marshal_get_castclass_with_cache (void)
8778 static MonoMethod
*cached
;
8780 MonoMethodBuilder
*mb
;
8781 MonoMethodSignature
*sig
;
8782 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
, invalid_cast_pos
;
8785 const int obj_arg_position
= 0;
8786 const int class_arg_position
= 1;
8787 const int cache_arg_position
= 2;
8792 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
8793 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
8794 sig
->params
[obj_arg_position
] = &mono_defaults
.object_class
->byval_arg
;
8795 sig
->params
[class_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
8796 sig
->params
[cache_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
8797 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
8801 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
8802 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
8803 invalid_cast_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8806 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
8807 mono_mb_emit_ldarg (mb
, obj_arg_position
);
8808 mono_mb_emit_byte (mb
, CEE_RET
);
8811 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
8812 mono_mb_patch_branch (mb
, invalid_cast_pos
);
8813 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
8816 mono_mb_patch_branch (mb
, return_null_pos
);
8817 mono_mb_emit_byte (mb
, CEE_LDNULL
);
8818 mono_mb_emit_byte (mb
, CEE_RET
);
8819 #endif /* DISABLE_JIT */
8821 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
8822 res
= mono_mb_create (mb
, sig
, 8, info
);
8825 if (InterlockedCompareExchangePointer ((volatile gpointer
*)&cached
, res
, NULL
)) {
8826 mono_free_method (res
);
8827 mono_metadata_free_method_signature (sig
);
8834 /* this is an icall */
8836 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
8839 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, &error
);
8840 if (mono_error_set_pending_exception (&error
))
8843 #ifndef DISABLE_REMOTING
8844 if (obj
->vtable
->klass
== mono_defaults
.transparent_proxy_class
)
8848 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
8850 cache_update
= cache_update
| 0x1;
8852 *cache
= cache_update
;
8858 * This does the equivalent of mono_object_isinst_with_cache.
8861 mono_marshal_get_isinst_with_cache (void)
8863 static MonoMethod
*cached
;
8865 MonoMethodBuilder
*mb
;
8866 MonoMethodSignature
*sig
;
8867 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
;
8870 const int obj_arg_position
= 0;
8871 const int class_arg_position
= 1;
8872 const int cache_arg_position
= 2;
8877 mb
= mono_mb_new (mono_defaults
.object_class
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
8878 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
8880 sig
->params
[obj_arg_position
] = &mono_defaults
.object_class
->byval_arg
;
8882 sig
->params
[class_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
8884 sig
->params
[cache_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
8885 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
8889 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
8890 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
8891 // Return the object gotten via the slow path.
8892 mono_mb_emit_byte (mb
, CEE_RET
);
8895 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
8896 mono_mb_patch_branch (mb
, return_null_pos
);
8897 mono_mb_emit_byte (mb
, CEE_LDNULL
);
8898 mono_mb_emit_byte (mb
, CEE_RET
);
8901 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
8902 mono_mb_emit_ldarg (mb
, obj_arg_position
);
8903 mono_mb_emit_byte (mb
, CEE_RET
);
8906 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
8907 res
= mono_mb_create (mb
, sig
, 8, info
);
8910 if (InterlockedCompareExchangePointer ((volatile gpointer
*)&cached
, res
, NULL
)) {
8911 mono_free_method (res
);
8912 mono_metadata_free_method_signature (sig
);
8920 * mono_marshal_get_isinst:
8921 * @klass: the type of the field
8923 * This method generates a function which can be used to check if an object is
8924 * an instance of the given type, icluding the case where the object is a proxy.
8925 * The generated function has the following signature:
8926 * MonoObject* __isinst_wrapper_ (MonoObject *obj)
8929 mono_marshal_get_isinst (MonoClass
*klass
)
8931 static MonoMethodSignature
*isint_sig
= NULL
;
8935 int pos_was_ok
, pos_end
;
8936 #ifndef DISABLE_REMOTING
8937 int pos_end2
, pos_failed
;
8940 MonoMethodBuilder
*mb
;
8942 cache
= get_cache (&klass
->image
->isinst_cache
, mono_aligned_addr_hash
, NULL
);
8943 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
8947 isint_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
8948 isint_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
8949 isint_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
8950 isint_sig
->pinvoke
= 0;
8953 name
= g_strdup_printf ("__isinst_wrapper_%s", klass
->name
);
8954 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_ISINST
);
8957 mb
->method
->save_lmf
= 1;
8960 /* check if the object is a proxy that needs special cast */
8961 mono_mb_emit_ldarg (mb
, 0);
8962 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8963 mono_mb_emit_op (mb
, CEE_MONO_CISINST
, klass
);
8965 /* The result of MONO_CISINST can be:
8966 0) the type check succeeded
8967 1) the type check did not succeed
8968 2) a CanCastTo call is needed */
8969 #ifndef DISABLE_REMOTING
8970 mono_mb_emit_byte (mb
, CEE_DUP
);
8971 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8973 mono_mb_emit_byte (mb
, CEE_LDC_I4_2
);
8974 pos_failed
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
8976 /* get the real proxy from the transparent proxy*/
8978 mono_mb_emit_ldarg (mb
, 0);
8979 mono_mb_emit_managed_call (mb
, mono_marshal_get_proxy_cancast (klass
), NULL
);
8980 pos_end
= mono_mb_emit_branch (mb
, CEE_BR
);
8984 mono_mb_patch_branch (mb
, pos_failed
);
8985 mono_mb_emit_byte (mb
, CEE_LDNULL
);
8986 pos_end2
= mono_mb_emit_branch (mb
, CEE_BR
);
8990 mono_mb_patch_branch (mb
, pos_was_ok
);
8991 mono_mb_emit_byte (mb
, CEE_POP
);
8992 mono_mb_emit_ldarg (mb
, 0);
8996 mono_mb_patch_branch (mb
, pos_end
);
8997 mono_mb_patch_branch (mb
, pos_end2
);
8998 mono_mb_emit_byte (mb
, CEE_RET
);
9000 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9004 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9005 pos_end
= mono_mb_emit_branch (mb
, CEE_BR
);
9009 mono_mb_patch_branch (mb
, pos_was_ok
);
9010 mono_mb_emit_ldarg (mb
, 0);
9014 mono_mb_patch_branch (mb
, pos_end
);
9015 mono_mb_emit_byte (mb
, CEE_RET
);
9016 #endif /* DISABLE_REMOTING */
9017 #endif /* DISABLE_JIT */
9019 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
9020 info
->d
.proxy
.klass
= klass
;
9021 res
= mono_mb_create_and_cache_full (cache
, klass
, mb
, isint_sig
, isint_sig
->param_count
+ 16, info
, NULL
);
9028 * mono_marshal_get_castclass:
9029 * @klass: the type of the field
9031 * This method generates a function which can be used to cast an object to
9032 * an instance of the given type, icluding the case where the object is a proxy.
9033 * The generated function has the following signature:
9034 * MonoObject* __castclass_wrapper_ (MonoObject *obj)
9037 mono_marshal_get_castclass (MonoClass
*klass
)
9039 static MonoMethodSignature
*castclass_sig
= NULL
;
9042 #ifndef DISABLE_REMOTING
9043 int pos_was_ok
, pos_was_ok2
;
9046 MonoMethodBuilder
*mb
;
9049 cache
= get_cache (&klass
->image
->castclass_cache
, mono_aligned_addr_hash
, NULL
);
9050 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9053 if (!castclass_sig
) {
9054 castclass_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9055 castclass_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9056 castclass_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9057 castclass_sig
->pinvoke
= 0;
9060 name
= g_strdup_printf ("__castclass_wrapper_%s", klass
->name
);
9061 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_CASTCLASS
);
9064 mb
->method
->save_lmf
= 1;
9067 /* check if the object is a proxy that needs special cast */
9068 mono_mb_emit_ldarg (mb
, 0);
9069 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
9070 mono_mb_emit_op (mb
, CEE_MONO_CCASTCLASS
, klass
);
9072 /* The result of MONO_CCASTCLASS can be:
9073 0) the cast is valid
9074 1) cast of unknown proxy type
9075 or an exception if the cast is is invalid
9077 #ifndef DISABLE_REMOTING
9078 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9080 /* get the real proxy from the transparent proxy*/
9082 mono_mb_emit_ldarg (mb
, 0);
9083 mono_mb_emit_managed_call (mb
, mono_marshal_get_proxy_cancast (klass
), NULL
);
9084 pos_was_ok2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
9087 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
9090 mono_mb_patch_branch (mb
, pos_was_ok
);
9091 mono_mb_patch_branch (mb
, pos_was_ok2
);
9093 /* MONO_CCASTCLASS leaves an int in the stack with the result, pop it. */
9094 mono_mb_emit_byte (mb
, CEE_POP
);
9095 #endif /* DISABLE_REMOTING */
9097 mono_mb_emit_ldarg (mb
, 0);
9100 mono_mb_emit_byte (mb
, CEE_RET
);
9101 #endif /* DISABLE_JIT */
9103 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
9105 res
= mono_mb_create_and_cache_full (cache
, klass
, mb
, castclass_sig
, castclass_sig
->param_count
+ 16,
9113 * mono_marshal_get_struct_to_ptr:
9116 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
9119 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
9121 MonoMethodBuilder
*mb
;
9122 static MonoMethod
*stoptr
= NULL
;
9126 g_assert (klass
!= NULL
);
9128 mono_marshal_load_type_info (klass
);
9130 if (klass
->marshal_info
->str_to_ptr
)
9131 return klass
->marshal_info
->str_to_ptr
;
9134 stoptr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "StructureToPtr", 3);
9137 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_UNKNOWN
);
9140 if (klass
->blittable
) {
9141 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9142 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9143 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9144 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9145 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9146 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9149 /* allocate local 0 (pointer) src_ptr */
9150 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9151 /* allocate local 1 (pointer) dst_ptr */
9152 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9153 /* allocate local 2 (boolean) delete_old */
9154 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
9155 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
9156 mono_mb_emit_stloc (mb
, 2);
9158 /* initialize src_ptr to point to the start of object data */
9159 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9160 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9161 mono_mb_emit_stloc (mb
, 0);
9163 /* initialize dst_ptr */
9164 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9165 mono_mb_emit_stloc (mb
, 1);
9167 emit_struct_conv (mb
, klass
, FALSE
);
9170 mono_mb_emit_byte (mb
, CEE_RET
);
9172 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
9173 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
9176 mono_marshal_lock ();
9177 if (!klass
->marshal_info
->str_to_ptr
)
9178 klass
->marshal_info
->str_to_ptr
= res
;
9180 res
= klass
->marshal_info
->str_to_ptr
;
9181 mono_marshal_unlock ();
9186 * mono_marshal_get_ptr_to_struct:
9189 * generates IL code for PtrToStructure (IntPtr src, object structure)
9192 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
9194 MonoMethodBuilder
*mb
;
9195 static MonoMethodSignature
*ptostr
= NULL
;
9199 g_assert (klass
!= NULL
);
9201 mono_marshal_load_type_info (klass
);
9203 if (klass
->marshal_info
->ptr_to_str
)
9204 return klass
->marshal_info
->ptr_to_str
;
9207 MonoMethodSignature
*sig
;
9209 /* Create the signature corresponding to
9210 static void PtrToStructure (IntPtr ptr, object structure);
9211 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9212 sig
= mono_create_icall_signature ("void ptr object");
9213 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
9215 mono_memory_barrier ();
9219 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_UNKNOWN
);
9222 if (klass
->blittable
) {
9223 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9224 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9225 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9226 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9227 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9228 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9231 /* allocate local 0 (pointer) src_ptr */
9232 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9233 /* allocate local 1 (pointer) dst_ptr */
9234 mono_mb_add_local (mb
, &klass
->this_arg
);
9236 /* initialize src_ptr to point to the start of object data */
9237 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9238 mono_mb_emit_stloc (mb
, 0);
9240 /* initialize dst_ptr */
9241 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9242 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
9243 mono_mb_emit_stloc (mb
, 1);
9245 emit_struct_conv (mb
, klass
, TRUE
);
9248 mono_mb_emit_byte (mb
, CEE_RET
);
9250 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
9251 res
= mono_mb_create (mb
, ptostr
, 0, info
);
9254 mono_marshal_lock ();
9255 if (!klass
->marshal_info
->ptr_to_str
)
9256 klass
->marshal_info
->ptr_to_str
= res
;
9258 res
= klass
->marshal_info
->ptr_to_str
;
9259 mono_marshal_unlock ();
9264 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
9265 * This is used to avoid infinite recursion since it is hard to determine where to
9266 * replace a method with its synchronized wrapper, and where not.
9267 * The runtime should execute METHOD instead of the wrapper.
9270 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
9272 MonoMethodBuilder
*mb
;
9274 MonoMethodSignature
*sig
;
9276 MonoGenericContext
*ctx
= NULL
;
9277 MonoGenericContainer
*container
= NULL
;
9279 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
9280 ctx
= &((MonoMethodInflated
*)method
)->context
;
9281 method
= ((MonoMethodInflated
*)method
)->declaring
;
9282 container
= mono_method_get_generic_container (method
);
9284 container
= method
->klass
->generic_container
;
9285 g_assert (container
);
9288 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNKNOWN
);
9290 mono_mb_emit_exception_full (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
9291 mono_mb_emit_byte (mb
, CEE_RET
);
9293 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
9295 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
9296 info
->d
.synchronized_inner
.method
= method
;
9297 res
= mono_mb_create (mb
, sig
, 0, info
);
9301 res
= mono_class_inflate_generic_method_checked (res
, ctx
, &error
);
9302 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
9308 * generates IL code for the synchronized wrapper: the generated method
9309 * calls METHOD while locking 'this' or the parent type.
9312 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
9314 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
9315 MonoMethodSignature
*sig
;
9316 MonoExceptionClause
*clause
;
9317 MonoMethodBuilder
*mb
;
9321 int i
, pos
, pos2
, this_local
, taken_local
, ret_local
= 0;
9322 MonoGenericContext
*ctx
= NULL
;
9323 MonoMethod
*orig_method
= NULL
;
9324 MonoGenericContainer
*container
= NULL
;
9328 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
9331 /* FIXME: Support generic methods too */
9332 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
9333 orig_method
= method
;
9334 ctx
= &((MonoMethodInflated
*)method
)->context
;
9335 method
= ((MonoMethodInflated
*)method
)->declaring
;
9336 container
= mono_method_get_generic_container (method
);
9338 container
= method
->klass
->generic_container
;
9339 g_assert (container
);
9346 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
9347 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
9351 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
9352 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9356 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
9359 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
9361 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
9362 info
->d
.synchronized
.method
= method
;
9365 mb
->skip_visibility
= 1;
9367 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9368 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
9371 if (method
->klass
->valuetype
&& !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
9372 mono_class_set_failure (method
->klass
, MONO_EXCEPTION_TYPE_LOAD
, NULL
);
9374 /* This will throw the type load exception when the wrapper is compiled */
9375 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9376 mono_mb_emit_op (mb
, CEE_ISINST
, method
->klass
);
9377 mono_mb_emit_byte (mb
, CEE_POP
);
9379 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9380 mono_mb_emit_ldloc (mb
, ret_local
);
9381 mono_mb_emit_byte (mb
, CEE_RET
);
9384 res
= mono_mb_create_and_cache_full (cache
, method
,
9385 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9393 this_local
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
9394 taken_local
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
9396 clause
= (MonoExceptionClause
*)mono_image_alloc0 (method
->klass
->image
, sizeof (MonoExceptionClause
));
9397 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
9400 mono_marshal_lock ();
9402 if (!enter_method
) {
9403 MonoMethodDesc
*desc
;
9405 desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
9406 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9407 g_assert (enter_method
);
9408 mono_method_desc_free (desc
);
9410 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
9411 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9412 g_assert (exit_method
);
9413 mono_method_desc_free (desc
);
9415 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
9416 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
9417 g_assert (gettypefromhandle_method
);
9418 mono_method_desc_free (desc
);
9421 mono_marshal_unlock ();
9424 /* Push this or the type object */
9425 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
9426 /* We have special handling for this in the JIT */
9427 int index
= mono_mb_add_data (mb
, method
->klass
);
9428 mono_mb_add_data (mb
, mono_defaults
.typehandle_class
);
9429 mono_mb_emit_byte (mb
, CEE_LDTOKEN
);
9430 mono_mb_emit_i4 (mb
, index
);
9432 mono_mb_emit_managed_call (mb
, gettypefromhandle_method
, NULL
);
9435 mono_mb_emit_ldarg (mb
, 0);
9436 mono_mb_emit_stloc (mb
, this_local
);
9438 /* Call Monitor::Enter() */
9439 mono_mb_emit_ldloc (mb
, this_local
);
9440 mono_mb_emit_ldloc_addr (mb
, taken_local
);
9441 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
9443 clause
->try_offset
= mono_mb_get_label (mb
);
9445 /* Call the method */
9447 mono_mb_emit_ldarg (mb
, 0);
9448 for (i
= 0; i
< sig
->param_count
; i
++)
9449 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
9453 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, &error
), NULL
);
9454 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
9456 mono_mb_emit_managed_call (mb
, method
, NULL
);
9459 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9460 mono_mb_emit_stloc (mb
, ret_local
);
9462 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
9464 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
9465 clause
->handler_offset
= mono_mb_get_label (mb
);
9467 /* Call Monitor::Exit() if needed */
9468 mono_mb_emit_ldloc (mb
, taken_local
);
9469 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9470 mono_mb_emit_ldloc (mb
, this_local
);
9471 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
9472 mono_mb_patch_branch (mb
, pos2
);
9473 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
9475 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
9477 mono_mb_patch_branch (mb
, pos
);
9478 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9479 mono_mb_emit_ldloc (mb
, ret_local
);
9480 mono_mb_emit_byte (mb
, CEE_RET
);
9482 mono_mb_set_clauses (mb
, 1, clause
);
9487 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9488 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
9490 res
= mono_mb_create_and_cache_full (cache
, method
,
9491 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9500 * the returned method calls 'method' unboxing the this argument
9503 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
9505 MonoMethodSignature
*sig
= mono_method_signature (method
);
9507 MonoMethodBuilder
*mb
;
9512 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
9514 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9517 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
9519 g_assert (sig
->hasthis
);
9522 mono_mb_emit_ldarg (mb
, 0);
9523 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
9524 mono_mb_emit_byte (mb
, CEE_ADD
);
9525 for (i
= 0; i
< sig
->param_count
; ++i
)
9526 mono_mb_emit_ldarg (mb
, i
+ 1);
9527 mono_mb_emit_managed_call (mb
, method
, NULL
);
9528 mono_mb_emit_byte (mb
, CEE_RET
);
9531 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
9532 info
->d
.unbox
.method
= method
;
9534 res
= mono_mb_create_and_cache_full (cache
, method
,
9535 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9538 /* mono_method_print_code (res); */
9544 STELEMREF_OBJECT
, /*no check at all*/
9545 STELEMREF_SEALED_CLASS
, /*check vtable->klass->element_type */
9546 STELEMREF_CLASS
, /*only the klass->parents check*/
9547 STELEMREF_INTERFACE
, /*interfaces without variant generic arguments. */
9548 STELEMREF_COMPLEX
, /*arrays, MBR or types with variant generic args - go straight to icalls*/
9549 STELEMREF_KIND_COUNT
9552 static const char *strelemref_wrapper_name
[] = {
9553 "object", "sealed_class", "class", "interface", "complex"
9557 is_monomorphic_array (MonoClass
*klass
)
9559 MonoClass
*element_class
;
9560 if (klass
->rank
!= 1)
9563 element_class
= klass
->element_class
;
9564 return (element_class
->flags
& TYPE_ATTRIBUTE_SEALED
) || element_class
->valuetype
;
9568 get_virtual_stelemref_kind (MonoClass
*element_class
)
9570 if (element_class
== mono_defaults
.object_class
)
9571 return STELEMREF_OBJECT
;
9572 if (is_monomorphic_array (element_class
))
9573 return STELEMREF_SEALED_CLASS
;
9574 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
9575 if (MONO_CLASS_IS_INTERFACE (element_class
) && !mono_class_has_variant_generic_params (element_class
))
9576 #ifdef COMPRESSED_INTERFACE_BITMAP
9577 return STELEMREF_COMPLEX
;
9579 return STELEMREF_INTERFACE
;
9581 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
9582 if (mono_class_is_marshalbyref (element_class
) || element_class
->rank
|| mono_class_has_variant_generic_params (element_class
))
9583 return STELEMREF_COMPLEX
;
9584 if (element_class
->flags
& TYPE_ATTRIBUTE_SEALED
)
9585 return STELEMREF_SEALED_CLASS
;
9586 return STELEMREF_CLASS
;
9592 load_array_element_address (MonoMethodBuilder
*mb
)
9594 mono_mb_emit_ldarg (mb
, 0);
9595 mono_mb_emit_ldarg (mb
, 1);
9596 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
9600 load_array_class (MonoMethodBuilder
*mb
, int aklass
)
9602 mono_mb_emit_ldarg (mb
, 0);
9603 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
9604 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9605 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
9606 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9607 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, element_class
));
9608 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9609 mono_mb_emit_stloc (mb
, aklass
);
9613 load_value_class (MonoMethodBuilder
*mb
, int vklass
)
9615 mono_mb_emit_ldarg (mb
, 2);
9616 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
9617 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9618 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
9619 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9620 mono_mb_emit_stloc (mb
, vklass
);
9626 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
9628 char *name
= mono_type_get_full_name (array
->vtable
->klass
->element_class
);
9629 printf ("slow vstore of %s\n", name
);
9636 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
9637 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
9638 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
9639 * - Add a case for arrays of arrays.
9642 get_virtual_stelemref_wrapper (int kind
)
9644 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
9645 static MonoMethodSignature
*signature
;
9646 MonoMethodBuilder
*mb
;
9649 const char *param_names
[16];
9650 guint32 b1
, b2
, b3
, b4
;
9651 int aklass
, vklass
, vtable
, uiid
;
9652 int array_slot_addr
;
9655 if (cached_methods
[kind
])
9656 return cached_methods
[kind
];
9658 name
= g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name
[kind
]);
9659 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
9663 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
9665 /* void this::stelemref (size_t idx, void* value) */
9666 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9667 sig
->hasthis
= TRUE
;
9668 sig
->params
[0] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9669 sig
->params
[1] = &mono_defaults
.object_class
->byval_arg
;
9674 param_names
[0] = "index";
9675 param_names
[1] = "value";
9676 mono_mb_set_param_names (mb
, param_names
);
9678 /*For now simply call plain old stelemref*/
9680 case STELEMREF_OBJECT
:
9681 /* ldelema (implicit bound check) */
9682 load_array_element_address (mb
);
9684 mono_mb_emit_ldarg (mb
, 2);
9685 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9686 mono_mb_emit_byte (mb
, CEE_RET
);
9689 case STELEMREF_COMPLEX
:
9691 <ldelema (bound check)>
9694 if (!mono_object_isinst (value, aklass))
9698 *array_slot_addr = value;
9701 throw new ArrayTypeMismatchException ();
9704 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9705 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9709 /*Use this to debug/record stores that are going thru the slow path*/
9710 MonoMethodSignature
*csig
;
9711 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
9712 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9713 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9714 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9715 csig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
9716 mono_mb_emit_ldarg (mb
, 0);
9717 mono_mb_emit_ldarg (mb
, 1);
9718 mono_mb_emit_ldarg (mb
, 2);
9719 mono_mb_emit_native_call (mb
, csig
, record_slot_vstore
);
9723 /* ldelema (implicit bound check) */
9724 load_array_element_address (mb
);
9725 mono_mb_emit_stloc (mb
, array_slot_addr
);
9727 /* if (!value) goto do_store */
9728 mono_mb_emit_ldarg (mb
, 2);
9729 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9731 /* aklass = array->vtable->klass->element_class */
9732 load_array_class (mb
, aklass
);
9734 /*if (mono_object_isinst (value, aklass)) */
9735 mono_mb_emit_ldarg (mb
, 2);
9736 mono_mb_emit_ldloc (mb
, aklass
);
9737 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
9738 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9741 mono_mb_patch_branch (mb
, b1
);
9742 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9743 mono_mb_emit_ldarg (mb
, 2);
9744 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9745 mono_mb_emit_byte (mb
, CEE_RET
);
9748 mono_mb_patch_branch (mb
, b2
);
9750 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9753 case STELEMREF_SEALED_CLASS
:
9755 <ldelema (bound check)>
9759 aklass = array->vtable->klass->element_class;
9760 vklass = value->vtable->klass;
9762 if (vklass != aklass)
9766 *array_slot_addr = value;
9769 throw new ArrayTypeMismatchException ();
9771 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9772 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9773 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9776 /* ldelema (implicit bound check) */
9777 load_array_element_address (mb
);
9778 mono_mb_emit_stloc (mb
, array_slot_addr
);
9780 /* if (!value) goto do_store */
9781 mono_mb_emit_ldarg (mb
, 2);
9782 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9784 /* aklass = array->vtable->klass->element_class */
9785 load_array_class (mb
, aklass
);
9787 /* vklass = value->vtable->klass */
9788 load_value_class (mb
, vklass
);
9790 /*if (vklass != aklass) goto do_exception; */
9791 mono_mb_emit_ldloc (mb
, aklass
);
9792 mono_mb_emit_ldloc (mb
, vklass
);
9793 b2
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9796 mono_mb_patch_branch (mb
, b1
);
9797 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9798 mono_mb_emit_ldarg (mb
, 2);
9799 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9800 mono_mb_emit_byte (mb
, CEE_RET
);
9803 mono_mb_patch_branch (mb
, b2
);
9804 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9807 case STELEMREF_CLASS
:
9810 <ldelema (bound check)>
9814 aklass = array->vtable->klass->element_class;
9815 vklass = value->vtable->klass;
9817 if (vklass->idepth < aklass->idepth)
9820 if (vklass->supertypes [aklass->idepth - 1] != aklass)
9824 *array_slot_addr = value;
9828 throw new ArrayTypeMismatchException ();
9830 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9831 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9832 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9834 /* ldelema (implicit bound check) */
9835 load_array_element_address (mb
);
9836 mono_mb_emit_stloc (mb
, array_slot_addr
);
9838 /* if (!value) goto do_store */
9839 mono_mb_emit_ldarg (mb
, 2);
9840 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9842 /* aklass = array->vtable->klass->element_class */
9843 load_array_class (mb
, aklass
);
9845 /* vklass = value->vtable->klass */
9846 load_value_class (mb
, vklass
);
9848 /*if (mono_object_isinst (value, aklass)) */
9849 mono_mb_emit_ldarg (mb
, 2);
9850 mono_mb_emit_ldloc (mb
, aklass
);
9851 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
9852 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9854 /* if (vklass->idepth < aklass->idepth) goto failue */
9855 mono_mb_emit_ldloc (mb
, vklass
);
9856 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
9857 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9859 mono_mb_emit_ldloc (mb
, aklass
);
9860 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
9861 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9863 b3
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
9865 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
9866 mono_mb_emit_ldloc (mb
, vklass
);
9867 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, supertypes
));
9868 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9870 mono_mb_emit_ldloc (mb
, aklass
);
9871 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
9872 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9873 mono_mb_emit_icon (mb
, 1);
9874 mono_mb_emit_byte (mb
, CEE_SUB
);
9875 mono_mb_emit_icon (mb
, sizeof (void*));
9876 mono_mb_emit_byte (mb
, CEE_MUL
);
9877 mono_mb_emit_byte (mb
, CEE_ADD
);
9878 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9880 mono_mb_emit_ldloc (mb
, aklass
);
9881 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9884 mono_mb_patch_branch (mb
, b1
);
9885 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9886 mono_mb_emit_ldarg (mb
, 2);
9887 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9888 mono_mb_emit_byte (mb
, CEE_RET
);
9891 mono_mb_patch_branch (mb
, b2
);
9892 mono_mb_patch_branch (mb
, b3
);
9893 mono_mb_patch_branch (mb
, b4
);
9895 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9898 case STELEMREF_INTERFACE
:
9905 klass = array->obj.vtable->klass->element_class;
9907 uiid = klass->interface_id;
9908 if (uiid > vt->max_interface_id)
9910 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
9913 mono_array_setref (array, index, value);
9916 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
9918 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9919 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9920 vtable
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9921 uiid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
9923 /* ldelema (implicit bound check) */
9924 load_array_element_address (mb
);
9925 mono_mb_emit_stloc (mb
, array_slot_addr
);
9927 /* if (!value) goto do_store */
9928 mono_mb_emit_ldarg (mb
, 2);
9929 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9931 /* klass = array->vtable->klass->element_class */
9932 load_array_class (mb
, aklass
);
9934 /* vt = value->vtable */
9935 mono_mb_emit_ldarg (mb
, 2);
9936 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
9937 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9938 mono_mb_emit_stloc (mb
, vtable
);
9940 /* uiid = klass->interface_id; */
9941 mono_mb_emit_ldloc (mb
, aklass
);
9942 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, interface_id
));
9943 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9944 mono_mb_emit_stloc (mb
, uiid
);
9946 /*if (uiid > vt->max_interface_id)*/
9947 mono_mb_emit_ldloc (mb
, uiid
);
9948 mono_mb_emit_ldloc (mb
, vtable
);
9949 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
9950 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9951 b2
= mono_mb_emit_branch (mb
, CEE_BGT_UN
);
9953 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
9955 /*vt->interface_bitmap*/
9956 mono_mb_emit_ldloc (mb
, vtable
);
9957 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, interface_bitmap
));
9958 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9961 mono_mb_emit_ldloc (mb
, uiid
);
9962 mono_mb_emit_icon (mb
, 3);
9963 mono_mb_emit_byte (mb
, CEE_SHR_UN
);
9965 /*vt->interface_bitmap [(uiid) >> 3]*/
9966 mono_mb_emit_byte (mb
, CEE_ADD
); /*interface_bitmap is a guint8 array*/
9967 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
9969 /*(1 << ((uiid)&7)))*/
9970 mono_mb_emit_icon (mb
, 1);
9971 mono_mb_emit_ldloc (mb
, uiid
);
9972 mono_mb_emit_icon (mb
, 7);
9973 mono_mb_emit_byte (mb
, CEE_AND
);
9974 mono_mb_emit_byte (mb
, CEE_SHL
);
9976 /*bitwise and the whole thing*/
9977 mono_mb_emit_byte (mb
, CEE_AND
);
9978 b3
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9981 mono_mb_patch_branch (mb
, b1
);
9982 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9983 mono_mb_emit_ldarg (mb
, 2);
9984 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9985 mono_mb_emit_byte (mb
, CEE_RET
);
9988 mono_mb_patch_branch (mb
, b2
);
9989 mono_mb_patch_branch (mb
, b3
);
9990 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9994 mono_mb_emit_ldarg (mb
, 0);
9995 mono_mb_emit_ldarg (mb
, 1);
9996 mono_mb_emit_ldarg (mb
, 2);
9997 mono_mb_emit_managed_call (mb
, mono_marshal_get_stelemref (), NULL
);
9998 mono_mb_emit_byte (mb
, CEE_RET
);
10001 #endif /* DISABLE_JIT */
10002 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
10003 info
->d
.virtual_stelemref
.kind
= kind
;
10004 res
= mono_mb_create (mb
, signature
, 4, info
);
10005 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
10007 mono_marshal_lock ();
10008 if (!cached_methods
[kind
]) {
10009 cached_methods
[kind
] = res
;
10010 mono_marshal_unlock ();
10012 mono_marshal_unlock ();
10013 mono_free_method (res
);
10017 return cached_methods
[kind
];
10021 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
10025 g_assert (array_class
->rank
== 1);
10026 kind
= get_virtual_stelemref_kind (array_class
->element_class
);
10028 return get_virtual_stelemref_wrapper (kind
);
10032 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
10037 *nwrappers
= STELEMREF_KIND_COUNT
;
10038 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
10039 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
10040 res
[i
] = get_virtual_stelemref_wrapper (i
);
10045 mono_marshal_get_stelemref (void)
10047 static MonoMethod
* ret
= NULL
;
10048 MonoMethodSignature
*sig
;
10049 MonoMethodBuilder
*mb
;
10052 guint32 b1
, b2
, b3
, b4
;
10054 int aklass
, vklass
;
10055 int array_slot_addr
;
10060 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
10063 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
10065 /* void stelemref (void* array, int idx, void* value) */
10066 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10067 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
10068 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
10069 sig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
10071 #ifndef DISABLE_JIT
10072 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10073 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10074 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
10078 <ldelema (bound check)>
10082 aklass = array->vtable->klass->element_class;
10083 vklass = value->vtable->klass;
10085 if (vklass->idepth < aklass->idepth)
10088 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10092 *array_slot_addr = value;
10096 if (mono_object_isinst (value, aklass))
10099 throw new ArrayTypeMismatchException ();
10102 /* ldelema (implicit bound check) */
10103 mono_mb_emit_ldarg (mb
, 0);
10104 mono_mb_emit_ldarg (mb
, 1);
10105 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
10106 mono_mb_emit_stloc (mb
, array_slot_addr
);
10108 /* if (!value) goto do_store */
10109 mono_mb_emit_ldarg (mb
, 2);
10110 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
10112 /* aklass = array->vtable->klass->element_class */
10113 mono_mb_emit_ldarg (mb
, 0);
10114 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10115 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10116 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
10117 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10118 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, element_class
));
10119 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10120 mono_mb_emit_stloc (mb
, aklass
);
10122 /* vklass = value->vtable->klass */
10123 mono_mb_emit_ldarg (mb
, 2);
10124 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10125 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10126 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
10127 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10128 mono_mb_emit_stloc (mb
, vklass
);
10130 /* if (vklass->idepth < aklass->idepth) goto failue */
10131 mono_mb_emit_ldloc (mb
, vklass
);
10132 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
10133 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10135 mono_mb_emit_ldloc (mb
, aklass
);
10136 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
10137 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10139 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
10141 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10142 mono_mb_emit_ldloc (mb
, vklass
);
10143 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, supertypes
));
10144 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10146 mono_mb_emit_ldloc (mb
, aklass
);
10147 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
10148 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10149 mono_mb_emit_icon (mb
, 1);
10150 mono_mb_emit_byte (mb
, CEE_SUB
);
10151 mono_mb_emit_icon (mb
, sizeof (void*));
10152 mono_mb_emit_byte (mb
, CEE_MUL
);
10153 mono_mb_emit_byte (mb
, CEE_ADD
);
10154 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10156 mono_mb_emit_ldloc (mb
, aklass
);
10158 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
10160 copy_pos
= mono_mb_get_label (mb
);
10162 mono_mb_patch_branch (mb
, b1
);
10163 mono_mb_emit_ldloc (mb
, array_slot_addr
);
10164 mono_mb_emit_ldarg (mb
, 2);
10165 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
10167 mono_mb_emit_byte (mb
, CEE_RET
);
10170 mono_mb_patch_branch (mb
, b2
);
10171 mono_mb_patch_branch (mb
, b3
);
10173 mono_mb_emit_ldarg (mb
, 2);
10174 mono_mb_emit_ldloc (mb
, aklass
);
10175 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
10177 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
10178 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
10179 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
10181 mono_mb_emit_byte (mb
, CEE_RET
);
10183 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
10184 ret
= mono_mb_create (mb
, sig
, 4, info
);
10191 * mono_marshal_get_gsharedvt_in_wrapper:
10193 * This wrapper handles calls from normal code to gsharedvt code.
10196 mono_marshal_get_gsharedvt_in_wrapper (void)
10198 static MonoMethod
* ret
= NULL
;
10199 MonoMethodSignature
*sig
;
10200 MonoMethodBuilder
*mb
;
10206 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_UNKNOWN
);
10208 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
10209 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10211 #ifndef DISABLE_JIT
10213 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
10215 mono_mb_emit_byte (mb
, CEE_RET
);
10217 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
10218 ret
= mono_mb_create (mb
, sig
, 4, info
);
10225 * mono_marshal_get_gsharedvt_out_wrapper:
10227 * This wrapper handles calls from gsharedvt code to normal code.
10230 mono_marshal_get_gsharedvt_out_wrapper (void)
10232 static MonoMethod
* ret
= NULL
;
10233 MonoMethodSignature
*sig
;
10234 MonoMethodBuilder
*mb
;
10240 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_UNKNOWN
);
10242 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
10243 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10245 #ifndef DISABLE_JIT
10247 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
10249 mono_mb_emit_byte (mb
, CEE_RET
);
10251 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
10252 ret
= mono_mb_create (mb
, sig
, 4, info
);
10261 MonoMethod
*method
;
10264 /* LOCKING: vars accessed under the marshal lock */
10265 static ArrayElemAddr
*elem_addr_cache
= NULL
;
10266 static int elem_addr_cache_size
= 0;
10267 static int elem_addr_cache_next
= 0;
10270 * mono_marshal_get_array_address:
10271 * @rank: rank of the array type
10272 * @elem_size: size in bytes of an element of an array.
10274 * Returns a MonoMethod that implements the code to get the address
10275 * of an element in a multi-dimenasional array of @rank dimensions.
10276 * The returned method takes an array as the first argument and then
10277 * @rank indexes for the @rank dimensions.
10278 * If ELEM_SIZE is 0, read the array size from the array object.
10281 mono_marshal_get_array_address (int rank
, int elem_size
)
10284 MonoMethodBuilder
*mb
;
10285 MonoMethodSignature
*sig
;
10288 int i
, bounds
, ind
, realidx
;
10289 int branch_pos
, *branch_positions
;
10293 mono_marshal_lock ();
10294 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
10295 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
10296 ret
= elem_addr_cache
[i
].method
;
10300 mono_marshal_unlock ();
10304 branch_positions
= g_new0 (int, rank
);
10306 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
10308 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
10309 sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
10310 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
10311 for (i
= 0; i
< rank
; ++i
) {
10312 sig
->params
[i
+ 1] = &mono_defaults
.int32_class
->byval_arg
;
10315 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
10316 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
10319 #ifndef DISABLE_JIT
10320 bounds
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10321 ind
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10322 realidx
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10324 /* bounds = array->bounds; */
10325 mono_mb_emit_ldarg (mb
, 0);
10326 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
10327 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10328 mono_mb_emit_stloc (mb
, bounds
);
10330 /* ind is the overall element index, realidx is the partial index in a single dimension */
10331 /* ind = idx0 - bounds [0].lower_bound */
10332 mono_mb_emit_ldarg (mb
, 1);
10333 mono_mb_emit_ldloc (mb
, bounds
);
10334 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
10335 mono_mb_emit_byte (mb
, CEE_ADD
);
10336 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10337 mono_mb_emit_byte (mb
, CEE_SUB
);
10338 mono_mb_emit_stloc (mb
, ind
);
10339 /* if (ind >= bounds [0].length) goto exeception; */
10340 mono_mb_emit_ldloc (mb
, ind
);
10341 mono_mb_emit_ldloc (mb
, bounds
);
10342 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
10343 mono_mb_emit_byte (mb
, CEE_ADD
);
10344 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10345 /* note that we use unsigned comparison */
10346 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
10348 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
10349 * We could also decide to ignore the passed elem_size and get it
10350 * from the array object, to reduce the number of methods we generate:
10351 * the additional cost is 3 memory loads and a non-immediate mul.
10353 for (i
= 1; i
< rank
; ++i
) {
10354 /* realidx = idxi - bounds [i].lower_bound */
10355 mono_mb_emit_ldarg (mb
, 1 + i
);
10356 mono_mb_emit_ldloc (mb
, bounds
);
10357 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
10358 mono_mb_emit_byte (mb
, CEE_ADD
);
10359 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10360 mono_mb_emit_byte (mb
, CEE_SUB
);
10361 mono_mb_emit_stloc (mb
, realidx
);
10362 /* if (realidx >= bounds [i].length) goto exeception; */
10363 mono_mb_emit_ldloc (mb
, realidx
);
10364 mono_mb_emit_ldloc (mb
, bounds
);
10365 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
10366 mono_mb_emit_byte (mb
, CEE_ADD
);
10367 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10368 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
10369 /* ind = ind * bounds [i].length + realidx */
10370 mono_mb_emit_ldloc (mb
, ind
);
10371 mono_mb_emit_ldloc (mb
, bounds
);
10372 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
10373 mono_mb_emit_byte (mb
, CEE_ADD
);
10374 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10375 mono_mb_emit_byte (mb
, CEE_MUL
);
10376 mono_mb_emit_ldloc (mb
, realidx
);
10377 mono_mb_emit_byte (mb
, CEE_ADD
);
10378 mono_mb_emit_stloc (mb
, ind
);
10381 /* return array->vector + ind * element_size */
10382 mono_mb_emit_ldarg (mb
, 0);
10383 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
10384 mono_mb_emit_ldloc (mb
, ind
);
10386 mono_mb_emit_icon (mb
, elem_size
);
10388 /* Load arr->vtable->klass->sizes.element_class */
10389 mono_mb_emit_ldarg (mb
, 0);
10390 mono_mb_emit_byte (mb
, CEE_CONV_I
);
10391 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10392 mono_mb_emit_byte (mb
, CEE_ADD
);
10393 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10394 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
10395 mono_mb_emit_byte (mb
, CEE_ADD
);
10396 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10397 /* sizes is an union, so this reads sizes.element_size */
10398 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoClass
, sizes
));
10399 mono_mb_emit_byte (mb
, CEE_ADD
);
10400 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10402 mono_mb_emit_byte (mb
, CEE_MUL
);
10403 mono_mb_emit_byte (mb
, CEE_ADD
);
10404 mono_mb_emit_byte (mb
, CEE_RET
);
10406 /* patch the branches to get here and throw */
10407 for (i
= 1; i
< rank
; ++i
) {
10408 mono_mb_patch_branch (mb
, branch_positions
[i
]);
10410 mono_mb_patch_branch (mb
, branch_pos
);
10411 /* throw exception */
10412 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
10414 g_free (branch_positions
);
10415 #endif /* DISABLE_JIT */
10417 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
10418 info
->d
.element_addr
.rank
= rank
;
10419 info
->d
.element_addr
.elem_size
= elem_size
;
10420 ret
= mono_mb_create (mb
, sig
, 4, info
);
10423 /* cache the result */
10425 mono_marshal_lock ();
10426 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
10427 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
10428 /* FIXME: free ret */
10429 ret
= elem_addr_cache
[i
].method
;
10435 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
10436 int new_size
= elem_addr_cache_size
+ 4;
10437 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
10438 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
10439 g_free (elem_addr_cache
);
10440 elem_addr_cache
= new_array
;
10441 elem_addr_cache_size
= new_size
;
10443 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
10444 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
10445 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
10446 elem_addr_cache_next
++;
10448 mono_marshal_unlock ();
10453 * mono_marshal_get_array_accessor_wrapper:
10455 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
10458 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
10460 MonoMethodSignature
*sig
;
10461 MonoMethodBuilder
*mb
;
10465 MonoGenericContext
*ctx
= NULL
;
10466 MonoMethod
*orig_method
= NULL
;
10467 MonoGenericContainer
*container
= NULL
;
10471 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
10472 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
10473 * FIXME: Use generic methods.
10480 g_assert_not_reached ();
10482 cache
= get_cache (&method
->klass
->image
->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
10483 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
10487 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
10490 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNKNOWN
);
10492 #ifndef DISABLE_JIT
10493 /* Call the method */
10495 mono_mb_emit_ldarg (mb
, 0);
10496 for (i
= 0; i
< sig
->param_count
; i
++)
10497 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
10501 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, &error
), NULL
);
10502 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
10504 mono_mb_emit_managed_call (mb
, method
, NULL
);
10506 mono_mb_emit_byte (mb
, CEE_RET
);
10509 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
10510 info
->d
.array_accessor
.method
= method
;
10514 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
10515 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
10517 res
= mono_mb_create_and_cache_full (cache
, method
,
10518 mb
, sig
, sig
->param_count
+ 16,
10527 mono_marshal_alloc (gulong size
, MonoError
*error
)
10531 mono_error_init (error
);
10534 res
= CoTaskMemAlloc (size
);
10536 res
= g_try_malloc ((gulong
)size
);
10538 mono_error_set_out_of_memory (error
, "Could not allocate %lu bytes", size
);
10543 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
10545 ves_icall_marshal_alloc (gulong size
)
10548 void *ret
= mono_marshal_alloc (size
, &error
);
10549 if (!mono_error_ok (&error
)) {
10550 mono_error_set_pending_exception (&error
);
10558 mono_marshal_free (gpointer ptr
)
10561 CoTaskMemFree (ptr
);
10568 mono_marshal_free_array (gpointer
*ptr
, int size
)
10575 for (i
= 0; i
< size
; i
++)
10581 mono_marshal_string_to_utf16 (MonoString
*s
)
10583 return s
? mono_string_chars (s
) : NULL
;
10586 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
10588 mono_marshal_string_to_utf16_copy (MonoString
*s
)
10594 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((mono_string_length (s
) * 2) + 2, &error
);
10595 if (!mono_error_ok (&error
)) {
10596 mono_error_set_pending_exception (&error
);
10599 memcpy (res
, mono_string_chars (s
), mono_string_length (s
) * 2);
10600 res
[mono_string_length (s
)] = 0;
10606 * mono_marshal_set_last_error:
10608 * This function is invoked to set the last error value from a P/Invoke call
10609 * which has SetLastError set.
10612 mono_marshal_set_last_error (void)
10615 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
10617 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
10622 mono_marshal_set_last_error_windows (int error
)
10625 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
10630 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray
*src
, gint32 start_index
,
10631 gpointer dest
, gint32 length
)
10636 MONO_CHECK_ARG_NULL (src
,);
10637 MONO_CHECK_ARG_NULL (dest
,);
10639 if (src
->obj
.vtable
->klass
->rank
!= 1) {
10640 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10643 if (start_index
< 0) {
10644 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10648 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10651 if (start_index
+ length
> mono_array_length (src
)) {
10652 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10656 element_size
= mono_array_element_size (src
->obj
.vtable
->klass
);
10658 /* no references should be involved */
10659 source_addr
= mono_array_addr_with_size_fast (src
, element_size
, start_index
);
10661 memcpy (dest
, source_addr
, length
* element_size
);
10665 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src
, gint32 start_index
,
10666 MonoArray
*dest
, gint32 length
)
10671 MONO_CHECK_ARG_NULL (src
,);
10672 MONO_CHECK_ARG_NULL (dest
,);
10674 if (dest
->obj
.vtable
->klass
->rank
!= 1) {
10675 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10678 if (start_index
< 0) {
10679 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10683 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10686 if (start_index
+ length
> mono_array_length (dest
)) {
10687 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10690 element_size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
10692 /* no references should be involved */
10693 dest_addr
= mono_array_addr_with_size_fast (dest
, element_size
, start_index
);
10695 memcpy (dest_addr
, src
, length
* element_size
);
10699 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr
)
10704 return mono_string_new (mono_domain_get (), ptr
);
10708 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr
, gint32 len
)
10711 MonoString
*result
= NULL
;
10712 mono_error_init (&error
);
10714 mono_error_set_argument_null (&error
, "ptr", "");
10716 result
= mono_string_new_len_checked (mono_domain_get (), ptr
, len
, &error
);
10717 mono_error_set_pending_exception (&error
);
10722 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16
*ptr
)
10725 MonoString
*res
= NULL
;
10726 MonoDomain
*domain
= mono_domain_get ();
10736 res
= mono_string_new_utf16_checked (domain
, ptr
, len
, &error
);
10737 if (!mono_error_ok (&error
)) {
10738 mono_error_set_pending_exception (&error
);
10745 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16
*ptr
, gint32 len
)
10748 MonoString
*res
= NULL
;
10749 MonoDomain
*domain
= mono_domain_get ();
10751 mono_error_init (&error
);
10755 mono_error_set_argument_null (&error
, "ptr", "");
10757 res
= mono_string_new_utf16_checked (domain
, ptr
, len
, &error
);
10760 if (!mono_error_ok (&error
))
10761 mono_error_set_pending_exception (&error
);
10766 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10768 return (GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
)));
10772 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType
*rtype
)
10778 MONO_CHECK_ARG_NULL (rtype
, 0);
10780 type
= rtype
->type
;
10781 klass
= mono_class_from_mono_type (type
);
10782 if (!mono_class_init (klass
)) {
10783 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
10787 layout
= (klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
);
10789 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
10790 return sizeof (gpointer
);
10791 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
10793 MonoException
*exc
;
10795 msg
= g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass
->name
);
10796 exc
= mono_get_exception_argument ("t", msg
);
10798 mono_set_pending_exception (exc
);
10802 return mono_class_native_size (klass
, NULL
);
10806 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject
*obj
, gpointer dst
, MonoBoolean delete_old
)
10809 MonoMethod
*method
;
10812 MONO_CHECK_ARG_NULL (obj
,);
10813 MONO_CHECK_ARG_NULL (dst
,);
10815 method
= mono_marshal_get_struct_to_ptr (obj
->vtable
->klass
);
10819 pa
[2] = &delete_old
;
10821 mono_runtime_invoke_checked (method
, NULL
, pa
, &error
);
10822 if (!mono_error_ok (&error
))
10823 mono_error_set_pending_exception (&error
);
10827 ptr_to_structure (gpointer src
, MonoObject
*dst
, MonoError
*error
)
10829 MonoMethod
*method
;
10832 mono_error_init (error
);
10834 method
= mono_marshal_get_ptr_to_struct (dst
->vtable
->klass
);
10839 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
10843 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src
, MonoObject
*dst
)
10848 MONO_CHECK_ARG_NULL (src
,);
10849 MONO_CHECK_ARG_NULL (dst
,);
10851 t
= mono_type_get_underlying_type (mono_class_get_type (dst
->vtable
->klass
));
10853 if (t
->type
== MONO_TYPE_VALUETYPE
) {
10854 MonoException
*exc
;
10857 tmp
= g_strdup_printf ("Destination is a boxed value type.");
10858 exc
= mono_get_exception_argument ("dst", tmp
);
10861 mono_set_pending_exception (exc
);
10865 ptr_to_structure (src
, dst
, &error
);
10866 if (!mono_error_ok (&error
))
10867 mono_error_set_pending_exception (&error
);
10871 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src
, MonoReflectionType
*type
)
10875 MonoDomain
*domain
= mono_domain_get ();
10880 MONO_CHECK_ARG_NULL (type
, NULL
);
10882 klass
= mono_class_from_mono_type (type
->type
);
10883 if (!mono_class_init (klass
)) {
10884 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
10888 res
= mono_object_new_checked (domain
, klass
, &error
);
10889 if (!mono_error_ok (&error
)) {
10890 mono_error_set_pending_exception (&error
);
10894 ptr_to_structure (src
, res
, &error
);
10895 if (!mono_error_ok (&error
)) {
10896 mono_error_set_pending_exception (&error
);
10904 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType
*type
, MonoString
*field_name
)
10907 MonoMarshalType
*info
;
10910 int match_index
= -1;
10912 MONO_CHECK_ARG_NULL (type
, 0);
10913 MONO_CHECK_ARG_NULL (field_name
, 0);
10915 fname
= mono_string_to_utf8_checked (field_name
, &error
);
10916 if (mono_error_set_pending_exception (&error
))
10918 klass
= mono_class_from_mono_type (type
->type
);
10919 if (!mono_class_init (klass
)) {
10920 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
10924 while (klass
&& match_index
== -1) {
10925 MonoClassField
* field
;
10927 gpointer iter
= NULL
;
10928 while ((field
= mono_class_get_fields (klass
, &iter
))) {
10929 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10931 if (!strcmp (fname
, mono_field_get_name (field
))) {
10938 if (match_index
== -1)
10939 klass
= klass
->parent
;
10944 if(match_index
== -1) {
10945 MonoException
* exc
;
10948 /* Get back original class instance */
10949 klass
= mono_class_from_mono_type (type
->type
);
10951 tmp
= g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass
->name
);
10952 exc
= mono_get_exception_argument ("fieldName", tmp
);
10955 mono_set_pending_exception ((MonoException
*)exc
);
10959 info
= mono_marshal_load_type_info (klass
);
10960 return info
->fields
[match_index
].offset
;
10964 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString
*string
)
10970 tres
= mono_string_to_utf8_checked (string
, &error
);
10971 if (mono_error_set_pending_exception (&error
))
10977 * mono_string_to_utf8_checked() returns a memory area at least as large as the size of the
10978 * MonoString, even if it contains NULL characters. The copy we allocate here has to be equally
10981 len
= MAX (strlen (tres
) + 1, string
->length
);
10982 ret
= ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len
);
10983 memcpy (ret
, tres
, len
);
10988 char *ret
= mono_string_to_utf8_checked (string
, &error
);
10989 mono_error_set_pending_exception (&error
);
10995 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString
*string
)
10997 if (string
== NULL
)
11000 #ifdef TARGET_WIN32
11001 gunichar2
*res
= ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal
11002 ((mono_string_length (string
) + 1) * 2);
11004 gunichar2
*res
= (gunichar2
*)g_malloc ((mono_string_length (string
) + 1) * 2);
11006 memcpy (res
, mono_string_chars (string
), mono_string_length (string
) * 2);
11007 res
[mono_string_length (string
)] = 0;
11013 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
11015 MonoMarshalType
*info
;
11018 info
= mono_marshal_load_type_info (klass
);
11020 for (i
= 0; i
< info
->num_fields
; i
++) {
11021 MonoMarshalConv conv
;
11022 MonoType
*ftype
= info
->fields
[i
].field
->type
;
11025 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11028 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
11029 klass
->unicode
, &conv
);
11031 cpos
= ptr
+ info
->fields
[i
].offset
;
11034 case MONO_MARSHAL_CONV_NONE
:
11035 if (MONO_TYPE_ISSTRUCT (ftype
)) {
11036 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
11040 case MONO_MARSHAL_CONV_STR_LPWSTR
:
11041 /* We assume this field points inside a MonoString */
11043 case MONO_MARSHAL_CONV_STR_LPTSTR
:
11044 #ifdef TARGET_WIN32
11045 /* We assume this field points inside a MonoString
11049 case MONO_MARSHAL_CONV_STR_LPSTR
:
11050 case MONO_MARSHAL_CONV_STR_BSTR
:
11051 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
11052 case MONO_MARSHAL_CONV_STR_TBSTR
:
11053 mono_marshal_free (*(gpointer
*)cpos
);
11063 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionType
*type
)
11067 MONO_CHECK_ARG_NULL (src
,);
11068 MONO_CHECK_ARG_NULL (type
,);
11070 klass
= mono_class_from_mono_type (type
->type
);
11071 if (!mono_class_init (klass
)) {
11072 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
11076 mono_struct_delete_old (klass
, (char *)src
);
11080 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size
)
11083 size_t s
= (size_t)size
;
11086 /* This returns a valid pointer for size 0 on MS.NET */
11090 res
= GlobalAlloc (GMEM_FIXED
, s
);
11092 res
= g_try_malloc (s
);
11095 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11103 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gpointer size
)
11106 size_t s
= (size_t)size
;
11109 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11114 res
= GlobalReAlloc (ptr
, s
, GMEM_MOVEABLE
);
11116 res
= g_try_realloc (ptr
, s
);
11119 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11127 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
11137 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
)
11142 res
= CoTaskMemAlloc (size
);
11144 if ((gulong
)size
== 0)
11145 /* This returns a valid pointer for size 0 on MS.NET */
11148 res
= g_try_malloc ((gulong
)size
);
11151 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11158 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
11161 CoTaskMemFree (ptr
);
11168 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
)
11173 res
= CoTaskMemRealloc (ptr
, size
);
11175 res
= g_try_realloc (ptr
, (gulong
)size
);
11178 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11185 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray
*arrayobj
, int index
)
11187 return mono_array_addr_with_size_fast (arrayobj
, mono_array_element_size (arrayobj
->obj
.vtable
->klass
), index
);
11191 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionType
*type
)
11193 MonoClass
*klass
= mono_type_get_class (type
->type
);
11194 if (!mono_class_init (klass
)) {
11195 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
11199 return mono_ftnptr_to_delegate (klass
, ftn
);
11203 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate
*delegate
)
11205 return mono_delegate_to_ftnptr (delegate
);
11209 * mono_marshal_is_loading_type_info:
11211 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
11215 mono_marshal_is_loading_type_info (MonoClass
*klass
)
11217 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
11219 return g_slist_find (loads_list
, klass
) != NULL
;
11223 * mono_marshal_load_type_info:
11225 * Initialize klass->marshal_info using information from metadata. This function can
11226 * recursively call itself, and the caller is responsible to avoid that by calling
11227 * mono_marshal_is_loading_type_info () beforehand.
11229 * LOCKING: Acquires the loader lock.
11232 mono_marshal_load_type_info (MonoClass
* klass
)
11235 guint32 native_size
= 0, min_align
= 1, packing
;
11236 MonoMarshalType
*info
;
11237 MonoClassField
* field
;
11240 GSList
*loads_list
;
11242 g_assert (klass
!= NULL
);
11244 if (klass
->marshal_info
)
11245 return klass
->marshal_info
;
11247 if (!klass
->inited
)
11248 mono_class_init (klass
);
11250 if (klass
->marshal_info
)
11251 return klass
->marshal_info
;
11254 * This function can recursively call itself, so we keep the list of classes which are
11255 * under initialization in a TLS list.
11257 g_assert (!mono_marshal_is_loading_type_info (klass
));
11258 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
11259 loads_list
= g_slist_prepend (loads_list
, klass
);
11260 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
11263 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11264 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11266 if (mono_field_is_deleted (field
))
11271 layout
= klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
;
11273 /* The mempool is protected by the loader lock */
11274 info
= (MonoMarshalType
*)mono_image_alloc0 (klass
->image
, MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
11275 info
->num_fields
= count
;
11277 /* Try to find a size for this type in metadata */
11278 mono_metadata_packing_from_typedef (klass
->image
, klass
->type_token
, NULL
, &native_size
);
11280 if (klass
->parent
) {
11281 int parent_size
= mono_class_native_size (klass
->parent
, NULL
);
11283 /* Add parent size to real size */
11284 native_size
+= parent_size
;
11285 info
->native_size
= parent_size
;
11288 packing
= klass
->packing_size
? klass
->packing_size
: 8;
11291 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11295 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11298 if (mono_field_is_deleted (field
))
11300 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
11301 mono_metadata_field_info_with_mempool (klass
->image
, mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
11302 NULL
, NULL
, &info
->fields
[j
].mspec
);
11304 info
->fields
[j
].field
= field
;
11306 if ((mono_class_num_fields (klass
) == 1) && (klass
->instance_size
== sizeof (MonoObject
)) &&
11307 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
11308 /* This field is a hack inserted by MCS to empty structures */
11313 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
11314 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
11315 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
11316 &align
, TRUE
, klass
->unicode
);
11317 align
= klass
->packing_size
? MIN (klass
->packing_size
, align
): align
;
11318 min_align
= MAX (align
, min_align
);
11319 info
->fields
[j
].offset
= info
->native_size
;
11320 info
->fields
[j
].offset
+= align
- 1;
11321 info
->fields
[j
].offset
&= ~(align
- 1);
11322 info
->native_size
= info
->fields
[j
].offset
+ size
;
11324 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
11325 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
11326 &align
, TRUE
, klass
->unicode
);
11327 min_align
= MAX (align
, min_align
);
11328 info
->fields
[j
].offset
= field
->offset
- sizeof (MonoObject
);
11329 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
11335 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
11336 info
->native_size
= MAX (native_size
, info
->native_size
);
11338 * If the provided Size is equal or larger than the calculated size, and there
11339 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
11341 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
11342 if (native_size
&& native_size
== info
->native_size
&& klass
->packing_size
== 0)
11345 min_align
= MIN (min_align
, packing
);
11349 if (info
->native_size
& (min_align
- 1)) {
11350 info
->native_size
+= min_align
- 1;
11351 info
->native_size
&= ~(min_align
- 1);
11354 info
->min_align
= min_align
;
11356 /* Update the class's blittable info, if the layouts don't match */
11357 if (info
->native_size
!= mono_class_value_size (klass
, NULL
))
11358 klass
->blittable
= FALSE
;
11360 /* If this is an array type, ensure that we have element info */
11361 if (klass
->rank
&& !mono_marshal_is_loading_type_info (klass
->element_class
)) {
11362 mono_marshal_load_type_info (klass
->element_class
);
11365 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
11366 loads_list
= g_slist_remove (loads_list
, klass
);
11367 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
11369 mono_marshal_lock ();
11370 if (!klass
->marshal_info
) {
11371 /*We do double-checking locking on marshal_info */
11372 mono_memory_barrier ();
11373 klass
->marshal_info
= info
;
11375 mono_marshal_unlock ();
11377 return klass
->marshal_info
;
11381 * mono_class_native_size:
11384 * Returns: the native size of an object instance (when marshaled
11385 * to unmanaged code)
11388 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
11390 if (!klass
->marshal_info
) {
11391 if (mono_marshal_is_loading_type_info (klass
)) {
11396 mono_marshal_load_type_info (klass
);
11401 *align
= klass
->marshal_info
->min_align
;
11403 return klass
->marshal_info
->native_size
;
11407 * mono_type_native_stack_size:
11408 * @t: the type to return the size it uses on the stack
11410 * Returns: the number of bytes required to hold an instance of this
11411 * type on the native stack
11414 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
11418 g_assert (t
!= NULL
);
11424 *align
= sizeof (gpointer
);
11425 return sizeof (gpointer
);
11429 case MONO_TYPE_BOOLEAN
:
11430 case MONO_TYPE_CHAR
:
11441 case MONO_TYPE_STRING
:
11442 case MONO_TYPE_OBJECT
:
11443 case MONO_TYPE_CLASS
:
11444 case MONO_TYPE_SZARRAY
:
11445 case MONO_TYPE_PTR
:
11446 case MONO_TYPE_FNPTR
:
11447 case MONO_TYPE_ARRAY
:
11448 *align
= sizeof (gpointer
);
11449 return sizeof (gpointer
);
11454 *align
= MONO_ABI_ALIGNOF (double);
11458 *align
= MONO_ABI_ALIGNOF (gint64
);
11460 case MONO_TYPE_GENERICINST
:
11461 if (!mono_type_generic_inst_is_valuetype (t
)) {
11462 *align
= sizeof (gpointer
);
11463 return sizeof (gpointer
);
11466 case MONO_TYPE_TYPEDBYREF
:
11467 case MONO_TYPE_VALUETYPE
: {
11469 MonoClass
*klass
= mono_class_from_mono_type (t
);
11471 if (klass
->enumtype
)
11472 return mono_type_native_stack_size (mono_class_enum_basetype (klass
), align
);
11474 size
= mono_class_native_size (klass
, align
);
11475 *align
= *align
+ 3;
11485 g_error ("type 0x%02x unknown", t
->type
);
11491 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
11492 gboolean as_field
, gboolean unicode
)
11494 MonoMarshalNative native_type
= mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
11497 switch (native_type
) {
11498 case MONO_NATIVE_BOOLEAN
:
11501 case MONO_NATIVE_I1
:
11502 case MONO_NATIVE_U1
:
11505 case MONO_NATIVE_I2
:
11506 case MONO_NATIVE_U2
:
11507 case MONO_NATIVE_VARIANTBOOL
:
11510 case MONO_NATIVE_I4
:
11511 case MONO_NATIVE_U4
:
11512 case MONO_NATIVE_ERROR
:
11515 case MONO_NATIVE_I8
:
11516 case MONO_NATIVE_U8
:
11517 *align
= MONO_ABI_ALIGNOF (gint64
);
11519 case MONO_NATIVE_R4
:
11522 case MONO_NATIVE_R8
:
11523 *align
= MONO_ABI_ALIGNOF (double);
11525 case MONO_NATIVE_INT
:
11526 case MONO_NATIVE_UINT
:
11527 case MONO_NATIVE_LPSTR
:
11528 case MONO_NATIVE_LPWSTR
:
11529 case MONO_NATIVE_LPTSTR
:
11530 case MONO_NATIVE_BSTR
:
11531 case MONO_NATIVE_ANSIBSTR
:
11532 case MONO_NATIVE_TBSTR
:
11533 case MONO_NATIVE_LPARRAY
:
11534 case MONO_NATIVE_SAFEARRAY
:
11535 case MONO_NATIVE_IUNKNOWN
:
11536 case MONO_NATIVE_IDISPATCH
:
11537 case MONO_NATIVE_INTERFACE
:
11538 case MONO_NATIVE_ASANY
:
11539 case MONO_NATIVE_FUNC
:
11540 case MONO_NATIVE_LPSTRUCT
:
11541 *align
= MONO_ABI_ALIGNOF (gpointer
);
11542 return sizeof (gpointer
);
11543 case MONO_NATIVE_STRUCT
:
11544 klass
= mono_class_from_mono_type (type
);
11545 if (klass
== mono_defaults
.object_class
&&
11546 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
11550 return mono_class_native_size (klass
, align
);
11551 case MONO_NATIVE_BYVALTSTR
: {
11552 int esize
= unicode
? 2: 1;
11555 return mspec
->data
.array_data
.num_elem
* esize
;
11557 case MONO_NATIVE_BYVALARRAY
: {
11558 // FIXME: Have to consider ArraySubType
11560 klass
= mono_class_from_mono_type (type
);
11561 if (klass
->element_class
== mono_defaults
.char_class
) {
11562 esize
= unicode
? 2 : 1;
11565 esize
= mono_class_native_size (klass
->element_class
, align
);
11568 return mspec
->data
.array_data
.num_elem
* esize
;
11570 case MONO_NATIVE_CUSTOM
:
11571 *align
= sizeof (gpointer
);
11572 return sizeof (gpointer
);
11574 case MONO_NATIVE_CURRENCY
:
11575 case MONO_NATIVE_VBBYREFSTR
:
11577 g_error ("native type %02x not implemented", native_type
);
11580 g_assert_not_reached ();
11584 /* This is a JIT icall, it sets the pending exception and return NULL on error */
11586 mono_marshal_asany (MonoObject
*o
, MonoMarshalNative string_encoding
, int param_attrs
)
11595 t
= &o
->vtable
->klass
->byval_arg
;
11599 case MONO_TYPE_PTR
:
11602 case MONO_TYPE_BOOLEAN
:
11605 case MONO_TYPE_CHAR
:
11610 return mono_object_unbox (o
);
11612 case MONO_TYPE_STRING
:
11613 switch (string_encoding
) {
11614 case MONO_NATIVE_LPWSTR
:
11615 return mono_marshal_string_to_utf16_copy ((MonoString
*)o
);
11617 case MONO_NATIVE_LPSTR
:
11618 return mono_string_to_lpstr ((MonoString
*)o
);
11621 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11622 g_assert_not_reached ();
11625 case MONO_TYPE_CLASS
:
11626 case MONO_TYPE_VALUETYPE
: {
11627 MonoMethod
*method
;
11630 MonoBoolean delete_old
= FALSE
;
11632 klass
= t
->data
.klass
;
11634 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
)
11637 if (klass
->valuetype
&& (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
11638 klass
->blittable
|| klass
->enumtype
))
11639 return mono_object_unbox (o
);
11641 res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), &error
);
11642 if (!mono_error_ok (&error
)) {
11643 mono_error_set_pending_exception (&error
);
11647 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11648 method
= mono_marshal_get_struct_to_ptr (o
->vtable
->klass
);
11652 pa
[2] = &delete_old
;
11654 mono_runtime_invoke_checked (method
, NULL
, pa
, &error
);
11655 if (!mono_error_ok (&error
)) {
11656 mono_error_set_pending_exception (&error
);
11666 mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
11670 /* This is a JIT icall, it sets the pending exception */
11672 mono_marshal_free_asany (MonoObject
*o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
)
11681 t
= &o
->vtable
->klass
->byval_arg
;
11683 case MONO_TYPE_STRING
:
11684 switch (string_encoding
) {
11685 case MONO_NATIVE_LPWSTR
:
11686 case MONO_NATIVE_LPSTR
:
11687 mono_marshal_free (ptr
);
11690 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11691 g_assert_not_reached ();
11694 case MONO_TYPE_CLASS
:
11695 case MONO_TYPE_VALUETYPE
: {
11696 klass
= t
->data
.klass
;
11698 if (klass
->valuetype
&& (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
11699 klass
->blittable
|| klass
->enumtype
))
11702 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
11703 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (o
->vtable
->klass
);
11709 mono_runtime_invoke_checked (method
, NULL
, pa
, &error
);
11710 if (!mono_error_ok (&error
)) {
11711 mono_error_set_pending_exception (&error
);
11716 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11717 mono_struct_delete_old (klass
, (char *)ptr
);
11720 mono_marshal_free (ptr
);
11729 mono_marshal_get_generic_array_helper (MonoClass
*klass
, MonoClass
*iface
, gchar
*name
, MonoMethod
*method
)
11731 MonoMethodSignature
*sig
, *csig
;
11732 MonoMethodBuilder
*mb
;
11737 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
11738 mb
->method
->slot
= -1;
11740 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
11741 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
11743 sig
= mono_method_signature (method
);
11744 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
11745 csig
->generic_param_count
= 0;
11747 #ifndef DISABLE_JIT
11748 mono_mb_emit_ldarg (mb
, 0);
11749 for (i
= 0; i
< csig
->param_count
; i
++)
11750 mono_mb_emit_ldarg (mb
, i
+ 1);
11751 mono_mb_emit_managed_call (mb
, method
, NULL
);
11752 mono_mb_emit_byte (mb
, CEE_RET
);
11754 /* We can corlib internal methods */
11755 mb
->skip_visibility
= TRUE
;
11757 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
11758 info
->d
.generic_array_helper
.method
= method
;
11759 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
11767 * The mono_win32_compat_* functions are implementations of inline
11768 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11769 * although not exported by kernel32.
11771 * We map the appropiate kernel32 entries to these functions using
11772 * dllmaps declared in the global etc/mono/config.
11776 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
11778 if (!dest
|| !source
)
11781 memcpy (dest
, source
, length
);
11785 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
11787 memset (dest
, fill
, length
);
11791 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
11793 if (!dest
|| !source
)
11796 memmove (dest
, source
, length
);
11800 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
11802 memset (dest
, 0, length
);
11806 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
11811 for (i
= 0; i
< len
; ++i
)
11815 g_assert (i
< len
);
11818 while (byte
&& !(byte
& 1))
11820 g_assert (byte
== 1);
11823 *bitmask
= buf
[i
];
11827 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
11829 MonoMethodBuilder
*mb
;
11830 MonoMethodSignature
*sig
, *csig
;
11831 MonoExceptionClause
*clause
;
11836 int i
, param_count
, sig_size
, pos_leave
;
11840 // FIXME: we need to store the exception into a MonoHandle
11841 g_assert (!mono_threads_is_coop_enabled ());
11843 klass
= method
->klass
;
11844 image
= method
->klass
->image
;
11846 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
11848 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
11851 sig
= mono_method_signature (method
);
11852 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
11854 /* add "this" and exception param */
11855 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
11857 /* dup & extend signature */
11858 csig
= mono_metadata_signature_alloc (image
, param_count
);
11859 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
11860 memcpy (csig
, sig
, sig_size
);
11861 csig
->param_count
= param_count
;
11864 csig
->call_convention
= MONO_CALL_DEFAULT
;
11866 if (sig
->hasthis
) {
11868 csig
->params
[0] = &klass
->byval_arg
;
11869 /* move params up by one */
11870 for (i
= 0; i
< sig
->param_count
; i
++)
11871 csig
->params
[i
+ 1] = sig
->params
[i
];
11874 /* setup exception param as byref+[out] */
11875 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
,
11876 &mono_defaults
.exception_class
->byval_arg
);
11877 csig
->params
[param_count
- 1]->byref
= 1;
11878 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
11880 /* convert struct return to object */
11881 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
11882 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
11884 #ifndef DISABLE_JIT
11885 /* local 0 (temp for exception object) */
11886 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
11888 /* local 1 (temp for result) */
11889 if (!MONO_TYPE_IS_VOID (sig
->ret
))
11890 mono_mb_add_local (mb
, sig
->ret
);
11892 /* clear exception arg */
11893 mono_mb_emit_ldarg (mb
, param_count
- 1);
11894 mono_mb_emit_byte (mb
, CEE_LDNULL
);
11895 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
11898 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
11899 clause
->try_offset
= mono_mb_get_label (mb
);
11901 /* push method's args */
11902 for (i
= 0; i
< param_count
- 1; i
++) {
11906 mono_mb_emit_ldarg (mb
, i
);
11908 /* get the byval type of the param */
11909 klass
= mono_class_from_mono_type (csig
->params
[i
]);
11910 type
= &klass
->byval_arg
;
11912 /* unbox struct args */
11913 if (MONO_TYPE_ISSTRUCT (type
)) {
11914 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
11916 /* byref args & and the "this" arg must remain a ptr.
11917 Otherwise make a copy of the value type */
11918 if (!(csig
->params
[i
]->byref
|| (i
== 0 && sig
->hasthis
)))
11919 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
11921 csig
->params
[i
] = &mono_defaults
.object_class
->byval_arg
;
11926 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
11927 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
11929 mono_mb_emit_op (mb
, CEE_CALL
, method
);
11931 /* save result at local 1 */
11932 if (!MONO_TYPE_IS_VOID (sig
->ret
))
11933 mono_mb_emit_stloc (mb
, 1);
11935 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
11938 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
11939 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
11940 clause
->data
.catch_class
= mono_defaults
.object_class
;
11942 clause
->handler_offset
= mono_mb_get_label (mb
);
11944 /* store exception at local 0 */
11945 mono_mb_emit_stloc (mb
, 0);
11946 mono_mb_emit_ldarg (mb
, param_count
- 1);
11947 mono_mb_emit_ldloc (mb
, 0);
11948 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
11949 mono_mb_emit_branch (mb
, CEE_LEAVE
);
11951 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
11953 mono_mb_set_clauses (mb
, 1, clause
);
11955 mono_mb_patch_branch (mb
, pos_leave
);
11958 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
11959 mono_mb_emit_ldloc (mb
, 1);
11961 /* box the return value */
11962 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
11963 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
11966 mono_mb_emit_byte (mb
, CEE_RET
);
11969 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
11976 * mono_marshal_free_dynamic_wrappers:
11978 * Free wrappers of the dynamic method METHOD.
11981 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
11983 MonoImage
*image
= method
->klass
->image
;
11985 g_assert (method_is_dynamic (method
));
11987 /* This could be called during shutdown */
11988 if (marshal_mutex_initialized
)
11989 mono_marshal_lock ();
11991 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
11992 * they could be shared with other methods ?
11994 if (image
->wrapper_caches
.runtime_invoke_direct_cache
)
11995 g_hash_table_remove (image
->wrapper_caches
.runtime_invoke_direct_cache
, method
);
11996 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
11997 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
11998 // FIXME: Need to clear the caches in other images as well
11999 if (image
->delegate_bound_static_invoke_cache
)
12000 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature (method
));
12002 if (marshal_mutex_initialized
)
12003 mono_marshal_unlock ();
12007 mono_marshal_ftnptr_eh_callback (guint32 gchandle
)
12009 g_assert (ftnptr_eh_callback
);
12010 ftnptr_eh_callback (gchandle
);
12014 ftnptr_eh_callback_default (guint32 gchandle
)
12016 MonoException
*exc
;
12017 gpointer stackdata
;
12019 mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata
);
12021 exc
= (MonoException
*) mono_gchandle_get_target (gchandle
);
12023 mono_gchandle_free (gchandle
);
12025 mono_raise_exception (exc
);
12029 * mono_install_ftnptr_eh_callback:
12031 * Install a callback that should be called when there is a managed exception
12032 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
12033 * managed exception to a native exception, to properly unwind the native
12034 * stack; this native exception will then be converted back to a managed
12035 * exception in their managed-to-native wrapper.
12038 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
12040 ftnptr_eh_callback
= callback
;
12043 static MonoThreadInfo
*
12044 mono_icall_start (HandleStackMark
*stackmark
, MonoError
*error
)
12046 MonoThreadInfo
*info
= mono_thread_info_current ();
12048 mono_stack_mark_init (info
, stackmark
);
12049 mono_error_init (error
);
12054 mono_icall_end (MonoThreadInfo
*info
, HandleStackMark
*stackmark
, MonoError
*error
)
12056 mono_stack_mark_pop (info
, stackmark
);
12057 mono_error_set_pending_exception (error
);