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/marshal-internals.h"
24 #include "metadata/method-builder.h"
25 #include "metadata/tabledefs.h"
26 #include "metadata/exception.h"
27 #include "metadata/appdomain.h"
28 #include "mono/metadata/abi-details.h"
29 #include "mono/metadata/debug-helpers.h"
30 #include "mono/metadata/threads.h"
31 #include "mono/metadata/monitor.h"
32 #include "mono/metadata/class-internals.h"
33 #include "mono/metadata/metadata-internals.h"
34 #include "mono/metadata/domain-internals.h"
35 #include "mono/metadata/gc-internals.h"
36 #include "mono/metadata/threads-types.h"
37 #include "mono/metadata/string-icalls.h"
38 #include "mono/metadata/attrdefs.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.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 /* #define DEBUG_RUNTIME_CODE */
57 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
61 #include "mono/cil/opcode.def"
67 * This mutex protects the various marshalling related caches in MonoImage
68 * and a few other data structures static to this file.
70 * The marshal lock is a non-recursive complex lock that sits below the domain lock in the
71 * runtime locking latice. Which means it can take simple locks suck as the image lock.
73 #define mono_marshal_lock() mono_locks_os_acquire (&marshal_mutex, MarshalLock)
74 #define mono_marshal_unlock() mono_locks_os_release (&marshal_mutex, MarshalLock)
75 static mono_mutex_t marshal_mutex
;
76 static gboolean marshal_mutex_initialized
;
78 static MonoNativeTlsKey last_error_tls_id
;
80 static MonoNativeTlsKey load_type_info_tls_id
;
82 static gboolean use_aot_wrappers
;
84 static int class_marshal_info_count
;
86 static void ftnptr_eh_callback_default (guint32 gchandle
);
88 static MonoFtnPtrEHCallback ftnptr_eh_callback
= ftnptr_eh_callback_default
;
91 delegate_hash_table_add (MonoDelegate
*d
);
94 delegate_hash_table_remove (MonoDelegate
*d
);
97 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
100 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
, int offset_of_first_child_field
, MonoMarshalNative string_encoding
);
103 mono_struct_delete_old (MonoClass
*klass
, char *ptr
);
106 mono_marshal_string_to_utf16 (MonoString
*s
);
109 mono_marshal_string_to_utf16_copy (MonoString
*s
);
113 mono_string_to_utf8str (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_GET_CLASS_WITH_CACHE (fixed_buffer_attribute
, "System.Runtime.CompilerServices", "FixedBufferAttribute");
221 static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
222 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler
, "System.Runtime.InteropServices", "ICustomMarshaler");
224 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
225 static MonoMethod
*sh_dangerous_add_ref
;
226 static MonoMethod
*sh_dangerous_release
;
231 sh_dangerous_add_ref
= mono_class_get_method_from_name (
232 mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
233 sh_dangerous_release
= mono_class_get_method_from_name (
234 mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
238 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean no_wrapper
)
240 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
242 mono_register_jit_icall (func
, name
, sig
, no_wrapper
);
246 register_icall_no_wrapper (gpointer func
, const char *name
, const char *sigstr
)
248 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
250 mono_register_jit_icall (func
, name
, sig
, TRUE
);
254 mono_signature_no_pinvoke (MonoMethod
*method
)
256 MonoMethodSignature
*sig
= mono_method_signature (method
);
258 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
259 sig
->pinvoke
= FALSE
;
266 mono_marshal_init_tls (void)
268 mono_native_tls_alloc (&last_error_tls_id
, NULL
);
269 mono_native_tls_alloc (&load_type_info_tls_id
, NULL
);
273 mono_object_isinst_icall (MonoObject
*obj
, MonoClass
*klass
)
276 MonoObject
*result
= mono_object_isinst_checked (obj
, klass
, &error
);
277 mono_error_set_pending_exception (&error
);
282 ves_icall_mono_string_from_utf16 (gunichar2
*data
)
285 MonoString
*result
= mono_string_from_utf16_checked (data
, &error
);
286 mono_error_set_pending_exception (&error
);
291 ves_icall_mono_string_to_utf8 (MonoString
*str
)
294 char *result
= mono_string_to_utf8_checked (str
, &error
);
295 mono_error_set_pending_exception (&error
);
300 mono_marshal_init (void)
302 static gboolean module_initialized
= FALSE
;
304 if (!module_initialized
) {
305 module_initialized
= TRUE
;
306 mono_os_mutex_init_recursive (&marshal_mutex
);
307 marshal_mutex_initialized
= TRUE
;
309 register_icall (ves_icall_System_Threading_Thread_ResetAbort
, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE
);
310 register_icall (mono_marshal_string_to_utf16
, "mono_marshal_string_to_utf16", "ptr obj", FALSE
);
311 register_icall (mono_marshal_string_to_utf16_copy
, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE
);
312 register_icall (mono_string_to_utf16
, "mono_string_to_utf16", "ptr obj", FALSE
);
313 register_icall (ves_icall_mono_string_from_utf16
, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE
);
314 register_icall (mono_string_from_byvalstr
, "mono_string_from_byvalstr", "obj ptr int", FALSE
);
315 register_icall (mono_string_from_byvalwstr
, "mono_string_from_byvalwstr", "obj ptr int", FALSE
);
316 register_icall (mono_string_new_wrapper
, "mono_string_new_wrapper", "obj ptr", FALSE
);
317 register_icall (mono_string_new_len_wrapper
, "mono_string_new_len_wrapper", "obj ptr int", FALSE
);
318 register_icall (ves_icall_mono_string_to_utf8
, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE
);
319 register_icall (mono_string_to_utf8str
, "mono_string_to_utf8str", "ptr obj", FALSE
);
320 register_icall (mono_string_to_ansibstr
, "mono_string_to_ansibstr", "ptr object", FALSE
);
321 register_icall (mono_string_builder_to_utf8
, "mono_string_builder_to_utf8", "ptr object", FALSE
);
322 register_icall (mono_string_builder_to_utf16
, "mono_string_builder_to_utf16", "ptr object", FALSE
);
323 register_icall (mono_array_to_savearray
, "mono_array_to_savearray", "ptr object", FALSE
);
324 register_icall (mono_array_to_lparray
, "mono_array_to_lparray", "ptr object", FALSE
);
325 register_icall (mono_free_lparray
, "mono_free_lparray", "void object ptr", FALSE
);
326 register_icall (mono_byvalarray_to_array
, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE
);
327 register_icall (mono_byvalarray_to_byte_array
, "mono_byvalarray_to_byte_array", "void object ptr int32", FALSE
);
328 register_icall (mono_array_to_byvalarray
, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE
);
329 register_icall (mono_array_to_byte_byvalarray
, "mono_array_to_byte_byvalarray", "void ptr object int32", FALSE
);
330 register_icall (mono_delegate_to_ftnptr
, "mono_delegate_to_ftnptr", "ptr object", FALSE
);
331 register_icall (mono_ftnptr_to_delegate
, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE
);
332 register_icall (mono_marshal_asany
, "mono_marshal_asany", "ptr object int32 int32", FALSE
);
333 register_icall (mono_marshal_free_asany
, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE
);
334 register_icall (ves_icall_marshal_alloc
, "ves_icall_marshal_alloc", "ptr int32", FALSE
);
335 register_icall (mono_marshal_free
, "mono_marshal_free", "void ptr", FALSE
);
336 register_icall (mono_marshal_set_last_error
, "mono_marshal_set_last_error", "void", FALSE
);
337 register_icall (mono_marshal_set_last_error_windows
, "mono_marshal_set_last_error_windows", "void int32", FALSE
);
338 register_icall (mono_string_utf8_to_builder
, "mono_string_utf8_to_builder", "void ptr ptr", FALSE
);
339 register_icall (mono_string_utf8_to_builder2
, "mono_string_utf8_to_builder2", "object ptr", FALSE
);
340 register_icall (mono_string_utf16_to_builder
, "mono_string_utf16_to_builder", "void ptr ptr", FALSE
);
341 register_icall (mono_string_utf16_to_builder2
, "mono_string_utf16_to_builder2", "object ptr", FALSE
);
342 register_icall (mono_marshal_free_array
, "mono_marshal_free_array", "void ptr int32", FALSE
);
343 register_icall (mono_string_to_byvalstr
, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE
);
344 register_icall (mono_string_to_byvalwstr
, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE
);
345 register_icall (g_free
, "g_free", "void ptr", FALSE
);
346 register_icall_no_wrapper (mono_object_isinst_icall
, "mono_object_isinst_icall", "object object ptr");
347 register_icall (mono_struct_delete_old
, "mono_struct_delete_old", "void ptr ptr", FALSE
);
348 register_icall (mono_delegate_begin_invoke
, "mono_delegate_begin_invoke", "object object ptr", FALSE
);
349 register_icall (mono_delegate_end_invoke
, "mono_delegate_end_invoke", "object object ptr", FALSE
);
350 register_icall (mono_context_get
, "mono_context_get", "object", FALSE
);
351 register_icall (mono_context_set
, "mono_context_set", "void object", FALSE
);
352 register_icall (mono_gc_wbarrier_generic_nostore
, "wb_generic", "void ptr", FALSE
);
353 register_icall (mono_gchandle_get_target
, "mono_gchandle_get_target", "object int32", TRUE
);
354 register_icall (mono_gchandle_new
, "mono_gchandle_new", "uint32 object bool", TRUE
);
355 register_icall (mono_marshal_isinst_with_cache
, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE
);
356 register_icall (mono_marshal_ftnptr_eh_callback
, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE
);
357 register_icall (mono_threads_enter_gc_safe_region_unbalanced
, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE
);
358 register_icall (mono_threads_exit_gc_safe_region_unbalanced
, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE
);
359 register_icall (mono_threads_attach_coop
, "mono_threads_attach_coop", "ptr ptr ptr", TRUE
);
360 register_icall (mono_threads_detach_coop
, "mono_threads_detach_coop", "void ptr ptr", TRUE
);
361 register_icall (mono_icall_start
, "mono_icall_start", "ptr ptr ptr", TRUE
);
362 register_icall (mono_icall_end
, "mono_icall_end", "void ptr ptr ptr", TRUE
);
363 register_icall (mono_handle_new_full
, "mono_handle_new_full", "ptr ptr bool", TRUE
);
365 mono_cominterop_init ();
366 mono_remoting_init ();
368 mono_counters_register ("MonoClass::class_marshal_info_count count",
369 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_marshal_info_count
);
375 mono_marshal_cleanup (void)
377 mono_cominterop_cleanup ();
379 mono_native_tls_free (load_type_info_tls_id
);
380 mono_native_tls_free (last_error_tls_id
);
381 mono_os_mutex_destroy (&marshal_mutex
);
382 marshal_mutex_initialized
= FALSE
;
386 mono_marshal_lock_internal (void)
388 mono_marshal_lock ();
392 mono_marshal_unlock_internal (void)
394 mono_marshal_unlock ();
397 /* This is a JIT icall, it sets the pending exception and return NULL on error */
399 mono_delegate_to_ftnptr (MonoDelegate
*delegate
)
402 MonoMethod
*method
, *wrapper
;
404 uint32_t target_handle
= 0;
409 if (delegate
->delegate_trampoline
)
410 return delegate
->delegate_trampoline
;
412 klass
= ((MonoObject
*)delegate
)->vtable
->klass
;
413 g_assert (klass
->delegate
);
415 method
= delegate
->method
;
416 if (delegate
->method_is_virtual
)
417 method
= mono_object_get_virtual_method (delegate
->target
, method
);
419 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
420 const char *exc_class
, *exc_arg
;
423 ftnptr
= mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
425 g_assert (exc_class
);
426 mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
432 if (delegate
->target
) {
433 /* Produce a location which can be embedded in JITted code */
434 target_handle
= mono_gchandle_new_weakref (delegate
->target
, FALSE
);
437 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
, &error
);
441 delegate
->delegate_trampoline
= mono_compile_method_checked (wrapper
, &error
);
445 // Add the delegate to the delegate hash table
446 delegate_hash_table_add (delegate
);
448 /* when the object is collected, collect the dynamic method, too */
449 mono_object_register_finalizer ((MonoObject
*)delegate
);
451 return delegate
->delegate_trampoline
;
454 if (target_handle
!= 0)
455 mono_gchandle_free (target_handle
);
456 mono_error_set_pending_exception (&error
);
461 * this hash table maps from a delegate trampoline object to a weak reference
462 * of the delegate. As an optimizations with a non-moving GC we store the
463 * object pointer itself, otherwise we use a GC handle.
465 static GHashTable
*delegate_hash_table
;
468 delegate_hash_table_new (void) {
469 return g_hash_table_new (NULL
, NULL
);
473 delegate_hash_table_remove (MonoDelegate
*d
)
475 guint32 gchandle
= 0;
477 mono_marshal_lock ();
478 if (delegate_hash_table
== NULL
)
479 delegate_hash_table
= delegate_hash_table_new ();
480 if (mono_gc_is_moving ())
481 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
482 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
483 mono_marshal_unlock ();
484 if (gchandle
&& mono_gc_is_moving ())
485 mono_gchandle_free (gchandle
);
489 delegate_hash_table_add (MonoDelegate
*d
)
492 guint32 old_gchandle
;
494 mono_marshal_lock ();
495 if (delegate_hash_table
== NULL
)
496 delegate_hash_table
= delegate_hash_table_new ();
497 if (mono_gc_is_moving ()) {
498 gchandle
= mono_gchandle_new_weakref ((MonoObject
*)d
, FALSE
);
499 old_gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
500 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
502 mono_gchandle_free (old_gchandle
);
504 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, d
);
506 mono_marshal_unlock ();
510 * mono_marshal_use_aot_wrappers:
512 * Instructs this module to use AOT compatible wrappers.
515 mono_marshal_use_aot_wrappers (gboolean use
)
517 use_aot_wrappers
= use
;
521 parse_unmanaged_function_pointer_attr (MonoClass
*klass
, MonoMethodPInvoke
*piinfo
)
524 MonoCustomAttrInfo
*cinfo
;
525 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
527 /* The attribute is only available in Net 2.0 */
528 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
530 * The pinvoke attributes are stored in a real custom attribute so we have to
533 cinfo
= mono_custom_attrs_from_class_checked (klass
, &error
);
534 if (!mono_error_ok (&error
)) {
535 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error
));
536 mono_error_cleanup (&error
);
538 if (cinfo
&& !mono_runtime_get_no_exec ()) {
539 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error
);
541 piinfo
->piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
543 if (!mono_error_ok (&error
)) {
544 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error
));
545 mono_error_cleanup (&error
);
549 mono_custom_attrs_free (cinfo
);
554 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
556 mono_ftnptr_to_delegate (MonoClass
*klass
, gpointer ftn
)
565 mono_marshal_lock ();
566 if (delegate_hash_table
== NULL
)
567 delegate_hash_table
= delegate_hash_table_new ();
569 if (mono_gc_is_moving ()) {
570 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
571 mono_marshal_unlock ();
573 d
= (MonoDelegate
*)mono_gchandle_get_target (gchandle
);
577 d
= (MonoDelegate
*)g_hash_table_lookup (delegate_hash_table
, ftn
);
578 mono_marshal_unlock ();
581 /* This is a native function, so construct a delegate for it */
582 MonoMethodSignature
*sig
;
584 MonoMarshalSpec
**mspecs
;
585 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
586 MonoMethodPInvoke piinfo
;
587 MonoObject
*this_obj
;
590 if (use_aot_wrappers
) {
591 wrapper
= mono_marshal_get_native_func_wrapper_aot (klass
);
592 this_obj
= mono_value_box_checked (mono_domain_get (), mono_defaults
.int_class
, &ftn
, &error
);
593 if (!is_ok (&error
)) {
594 mono_error_set_pending_exception (&error
);
598 memset (&piinfo
, 0, sizeof (piinfo
));
599 parse_unmanaged_function_pointer_attr (klass
, &piinfo
);
601 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
602 mono_method_get_marshal_info (invoke
, mspecs
);
603 /* Freed below so don't alloc from mempool */
604 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
607 wrapper
= mono_marshal_get_native_func_wrapper (klass
->image
, sig
, &piinfo
, mspecs
, ftn
);
610 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
612 mono_metadata_free_marshal_spec (mspecs
[i
]);
617 d
= (MonoDelegate
*)mono_object_new_checked (mono_domain_get (), klass
, &error
);
618 if (!mono_error_ok (&error
)) {
619 mono_error_set_pending_exception (&error
);
622 gpointer compiled_ptr
= mono_compile_method_checked (wrapper
, &error
);
623 if (mono_error_set_pending_exception (&error
))
625 mono_delegate_ctor_with_method ((MonoObject
*)d
, this_obj
, compiled_ptr
, wrapper
, &error
);
626 if (mono_error_set_pending_exception (&error
))
630 if (d
->object
.vtable
->domain
!= mono_domain_get ()) {
631 mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
639 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
644 delegate_hash_table_remove (delegate
);
646 ptr
= (gpointer
)InterlockedExchangePointer (&delegate
->delegate_trampoline
, NULL
);
648 if (!delegate
->target
) {
649 /* The wrapper method is shared between delegates -> no need to free it */
658 ji
= mono_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (ptr
));
661 method
= mono_jit_info_get_method (ji
);
662 method_data
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
664 /*the target gchandle is the first entry after size and the wrapper itself.*/
665 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
668 mono_gchandle_free (gchandle
);
670 mono_runtime_free_method (mono_object_domain (delegate
), method
);
674 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
676 mono_string_from_byvalstr (const char *data
, int max_len
)
679 MonoDomain
*domain
= mono_domain_get ();
685 while (len
< max_len
- 1 && data
[len
])
688 MonoString
*result
= mono_string_new_len_checked (domain
, data
, len
, &error
);
689 mono_error_set_pending_exception (&error
);
693 /* This is a JIT icall, it sets the pending exception and return NULL on error */
695 mono_string_from_byvalwstr (gunichar2
*data
, int max_len
)
698 MonoString
*res
= NULL
;
699 MonoDomain
*domain
= mono_domain_get ();
705 while (data
[len
]) len
++;
707 res
= mono_string_new_utf16_checked (domain
, data
, MIN (len
, max_len
), &error
);
708 if (!mono_error_ok (&error
)) {
709 mono_error_set_pending_exception (&error
);
716 mono_array_to_savearray (MonoArray
*array
)
721 g_assert_not_reached ();
726 mono_array_to_lparray (MonoArray
*array
)
729 gpointer
*nativeArray
= NULL
;
730 int nativeArraySize
= 0;
740 klass
= array
->obj
.vtable
->klass
;
742 switch (klass
->element_class
->byval_arg
.type
) {
744 g_assert_not_reached ();
746 case MONO_TYPE_CLASS
:
747 nativeArraySize
= array
->max_length
;
748 nativeArray
= (void **)malloc(sizeof(gpointer
) * nativeArraySize
);
749 for(i
= 0; i
< nativeArraySize
; ++i
)
750 nativeArray
[i
] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((MonoObject
**)array
->vector
)[i
]);
753 case MONO_TYPE_BOOLEAN
:
766 case MONO_TYPE_VALUETYPE
:
770 case MONO_TYPE_GENERICINST
:
771 case MONO_TYPE_OBJECT
:
772 case MONO_TYPE_ARRAY
:
773 case MONO_TYPE_SZARRAY
:
774 case MONO_TYPE_STRING
:
776 g_warning ("type 0x%x not handled", klass
->element_class
->byval_arg
.type
);
777 g_assert_not_reached ();
780 return array
->vector
;
784 mono_free_lparray (MonoArray
*array
, gpointer
* nativeArray
)
795 klass
= array
->obj
.vtable
->klass
;
797 if (klass
->element_class
->byval_arg
.type
== MONO_TYPE_CLASS
) {
798 for(i
= 0; i
< array
->max_length
; ++i
)
799 mono_marshal_free_ccw (mono_array_get (array
, MonoObject
*, i
));
800 g_free (nativeArray
);
806 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*elclass
, guint32 elnum
)
808 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
810 if (elclass
== mono_defaults
.byte_class
) {
811 GError
*error
= NULL
;
815 ut
= g_utf8_to_utf16 ((const gchar
*)native_arr
, elnum
, NULL
, &items_written
, &error
);
818 memcpy (mono_array_addr (arr
, guint16
, 0), ut
, items_written
* sizeof (guint16
));
822 g_error_free (error
);
825 g_assert_not_reached ();
829 mono_byvalarray_to_byte_array (MonoArray
*arr
, gpointer native_arr
, guint32 elnum
)
831 mono_byvalarray_to_array (arr
, native_arr
, mono_defaults
.byte_class
, elnum
);
834 /* This is a JIT icall, it sets the pending exception and returns on error */
836 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*elclass
, guint32 elnum
)
838 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
840 if (elclass
== mono_defaults
.byte_class
) {
842 GError
*error
= NULL
;
844 as
= g_utf16_to_utf8 (mono_array_addr (arr
, gunichar2
, 0), mono_array_length (arr
), NULL
, NULL
, &error
);
846 mono_set_pending_exception (mono_get_exception_argument ("string", error
->message
));
847 g_error_free (error
);
851 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
854 g_assert_not_reached ();
859 mono_array_to_byte_byvalarray (gpointer native_arr
, MonoArray
*arr
, guint32 elnum
)
861 mono_array_to_byvalarray (native_arr
, arr
, mono_defaults
.byte_class
, elnum
);
864 static MonoStringBuilder
*
865 mono_string_builder_new (int starting_string_length
)
867 static MonoClass
*string_builder_class
;
868 static MonoMethod
*sb_ctor
;
869 static void *args
[1];
872 int initial_len
= starting_string_length
;
878 MonoMethodDesc
*desc
;
881 string_builder_class
= mono_class_get_string_builder_class ();
882 g_assert (string_builder_class
);
883 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
884 m
= mono_method_desc_search_in_class (desc
, string_builder_class
);
886 mono_method_desc_free (desc
);
887 mono_memory_barrier ();
891 // We make a new array in the _to_builder function, so this
892 // array will always be garbage collected.
893 args
[0] = &initial_len
;
895 MonoStringBuilder
*sb
= (MonoStringBuilder
*)mono_object_new_checked (mono_domain_get (), string_builder_class
, &error
);
896 mono_error_assert_ok (&error
);
899 mono_runtime_try_invoke (sb_ctor
, sb
, args
, &exc
, &error
);
900 g_assert (exc
== NULL
);
901 mono_error_assert_ok (&error
);
903 g_assert (sb
->chunkChars
->max_length
>= initial_len
);
909 mono_string_utf16_to_builder_copy (MonoStringBuilder
*sb
, gunichar2
*text
, size_t string_len
)
911 gunichar2
*charDst
= (gunichar2
*)sb
->chunkChars
->vector
;
912 gunichar2
*charSrc
= (gunichar2
*)text
;
913 memcpy (charDst
, charSrc
, sizeof (gunichar2
) * string_len
);
915 sb
->chunkLength
= string_len
;
921 mono_string_utf16_to_builder2 (gunichar2
*text
)
927 for (len
= 0; text
[len
] != 0; ++len
);
929 MonoStringBuilder
*sb
= mono_string_builder_new (len
);
930 mono_string_utf16_to_builder (sb
, text
);
936 mono_string_utf8_to_builder (MonoStringBuilder
*sb
, char *text
)
941 GError
*error
= NULL
;
943 gunichar2
* ut
= g_utf8_to_utf16 (text
, strlen (text
), NULL
, &copied
, &error
);
944 int capacity
= mono_string_builder_capacity (sb
);
946 if (copied
> capacity
)
950 MONO_OBJECT_SETREF (sb
, chunkPrevious
, NULL
);
951 mono_string_utf16_to_builder_copy (sb
, ut
, copied
);
953 g_error_free (error
);
959 mono_string_utf8_to_builder2 (char *text
)
964 int len
= strlen (text
);
965 MonoStringBuilder
*sb
= mono_string_builder_new (len
);
966 mono_string_utf8_to_builder (sb
, text
);
972 mono_string_utf16_to_builder (MonoStringBuilder
*sb
, gunichar2
*text
)
978 for (len
= 0; text
[len
] != 0; ++len
);
980 if (len
> mono_string_builder_capacity (sb
))
981 len
= mono_string_builder_capacity (sb
);
983 mono_string_utf16_to_builder_copy (sb
, text
, len
);
987 * mono_string_builder_to_utf8:
988 * @sb: the string builder
990 * Converts to utf8 the contents of the MonoStringBuilder.
992 * Returns: a utf8 string with the contents of the StringBuilder.
994 * The return value must be released with mono_marshal_free.
996 * This is a JIT icall, it sets the pending exception and returns NULL on error.
999 mono_string_builder_to_utf8 (MonoStringBuilder
*sb
)
1002 GError
*gerror
= NULL
;
1007 gunichar2
*str_utf16
= mono_string_builder_to_utf16 (sb
);
1009 guint str_len
= mono_string_builder_string_length (sb
);
1011 gchar
*tmp
= g_utf16_to_utf8 (str_utf16
, str_len
, NULL
, &byte_count
, &gerror
);
1014 g_error_free (gerror
);
1015 mono_marshal_free (str_utf16
);
1016 mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
1019 guint len
= mono_string_builder_capacity (sb
) + 1;
1020 gchar
*res
= (gchar
*)mono_marshal_alloc (MAX (byte_count
+1, len
* sizeof (gchar
)), &error
);
1021 if (!mono_error_ok (&error
)) {
1022 mono_marshal_free (str_utf16
);
1024 mono_error_set_pending_exception (&error
);
1028 memcpy (res
, tmp
, byte_count
);
1029 res
[byte_count
] = '\0';
1031 mono_marshal_free (str_utf16
);
1038 * mono_string_builder_to_utf16:
1039 * @sb: the string builder
1041 * Converts to utf16 the contents of the MonoStringBuilder.
1043 * Returns: a utf16 string with the contents of the StringBuilder.
1045 * The return value must be released with mono_marshal_free.
1047 * This is a JIT icall, it sets the pending exception and returns NULL on error.
1050 mono_string_builder_to_utf16 (MonoStringBuilder
*sb
)
1057 g_assert (sb
->chunkChars
);
1059 guint len
= mono_string_builder_capacity (sb
);
1064 gunichar2
*str
= (gunichar2
*)mono_marshal_alloc ((len
+ 1) * sizeof (gunichar2
), &error
);
1065 if (!mono_error_ok (&error
)) {
1066 mono_error_set_pending_exception (&error
);
1075 MonoStringBuilder
* chunk
= sb
;
1077 if (chunk
->chunkLength
> 0) {
1078 // Check that we will not overrun our boundaries.
1079 gunichar2
*source
= (gunichar2
*)chunk
->chunkChars
->vector
;
1081 if (chunk
->chunkLength
<= len
) {
1082 memcpy (str
+ chunk
->chunkOffset
, source
, chunk
->chunkLength
* sizeof(gunichar2
));
1084 g_error ("A chunk in the StringBuilder had a length longer than expected from the offset.");
1087 len
-= chunk
->chunkLength
;
1089 chunk
= chunk
->chunkPrevious
;
1090 } while (chunk
!= NULL
);
1096 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1098 mono_string_to_utf8str (MonoString
*s
)
1101 char *result
= mono_string_to_utf8_checked (s
, &error
);
1102 mono_error_set_pending_exception (&error
);
1108 mono_string_to_ansibstr (MonoString
*string_obj
)
1110 g_error ("UnmanagedMarshal.BStr is not implemented.");
1115 * mono_string_to_byvalstr:
1116 * @dst: Where to store the null-terminated utf8 decoded string.
1117 * @src: the MonoString to copy.
1118 * @size: the maximum number of bytes to copy.
1120 * Copies the MonoString pointed to by @src as a utf8 string
1121 * into @dst, it copies at most @size bytes into the destination.
1124 mono_string_to_byvalstr (gpointer dst
, MonoString
*src
, int size
)
1130 g_assert (dst
!= NULL
);
1131 g_assert (size
> 0);
1133 memset (dst
, 0, size
);
1137 s
= mono_string_to_utf8_checked (src
, &error
);
1138 if (mono_error_set_pending_exception (&error
))
1140 len
= MIN (size
, strlen (s
));
1143 memcpy (dst
, s
, len
);
1148 * mono_string_to_byvalwstr:
1149 * @dst: Where to store the null-terminated utf16 decoded string.
1150 * @src: the MonoString to copy.
1151 * @size: the maximum number of wide characters to copy (each consumes 2 bytes)
1153 * Copies the MonoString pointed to by @src as a utf16 string into
1154 * @dst, it copies at most @size bytes into the destination (including
1155 * a terminating 16-bit zero terminator).
1158 mono_string_to_byvalwstr (gpointer dst
, MonoString
*src
, int size
)
1162 g_assert (dst
!= NULL
);
1163 g_assert (size
> 1);
1166 memset (dst
, 0, size
* 2);
1170 len
= MIN (size
, (mono_string_length (src
)));
1171 memcpy (dst
, mono_string_chars (src
), len
* 2);
1172 if (size
<= mono_string_length (src
))
1174 *((gunichar2
*) dst
+ len
) = 0;
1177 /* this is an icall, it sets the pending exception and returns NULL on error */
1179 mono_string_new_len_wrapper (const char *text
, guint length
)
1182 MonoString
*result
= mono_string_new_len_checked (mono_domain_get (), text
, length
, &error
);
1183 mono_error_set_pending_exception (&error
);
1190 * mono_mb_emit_exception_marshal_directive:
1192 * This function assumes ownership of MSG, which should be malloc-ed.
1195 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, char *msg
)
1200 s
= mono_image_strdup (mb
->method
->klass
->image
, msg
);
1205 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", s
);
1208 #endif /* !DISABLE_JIT */
1211 mono_type_to_ldind (MonoType
*type
)
1217 switch (type
->type
) {
1219 return CEE_LDIND_I1
;
1221 case MONO_TYPE_BOOLEAN
:
1222 return CEE_LDIND_U1
;
1224 return CEE_LDIND_I2
;
1226 case MONO_TYPE_CHAR
:
1227 return CEE_LDIND_U2
;
1229 return CEE_LDIND_I4
;
1231 return CEE_LDIND_U4
;
1235 case MONO_TYPE_FNPTR
:
1237 case MONO_TYPE_CLASS
:
1238 case MONO_TYPE_STRING
:
1239 case MONO_TYPE_OBJECT
:
1240 case MONO_TYPE_SZARRAY
:
1241 case MONO_TYPE_ARRAY
:
1242 return CEE_LDIND_REF
;
1245 return CEE_LDIND_I8
;
1247 return CEE_LDIND_R4
;
1249 return CEE_LDIND_R8
;
1250 case MONO_TYPE_VALUETYPE
:
1251 if (type
->data
.klass
->enumtype
) {
1252 type
= mono_class_enum_basetype (type
->data
.klass
);
1256 case MONO_TYPE_TYPEDBYREF
:
1258 case MONO_TYPE_GENERICINST
:
1259 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1262 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1268 mono_type_to_stind (MonoType
*type
)
1271 return MONO_TYPE_IS_REFERENCE (type
) ? CEE_STIND_REF
: CEE_STIND_I
;
1275 switch (type
->type
) {
1278 case MONO_TYPE_BOOLEAN
:
1279 return CEE_STIND_I1
;
1282 case MONO_TYPE_CHAR
:
1283 return CEE_STIND_I2
;
1286 return CEE_STIND_I4
;
1290 case MONO_TYPE_FNPTR
:
1292 case MONO_TYPE_CLASS
:
1293 case MONO_TYPE_STRING
:
1294 case MONO_TYPE_OBJECT
:
1295 case MONO_TYPE_SZARRAY
:
1296 case MONO_TYPE_ARRAY
:
1297 return CEE_STIND_REF
;
1300 return CEE_STIND_I8
;
1302 return CEE_STIND_R4
;
1304 return CEE_STIND_R8
;
1305 case MONO_TYPE_VALUETYPE
:
1306 if (type
->data
.klass
->enumtype
) {
1307 type
= mono_class_enum_basetype (type
->data
.klass
);
1311 case MONO_TYPE_TYPEDBYREF
:
1313 case MONO_TYPE_GENERICINST
:
1314 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1317 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1325 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1328 case MONO_MARSHAL_CONV_BOOL_I4
:
1329 mono_mb_emit_ldloc (mb
, 1);
1330 mono_mb_emit_ldloc (mb
, 0);
1331 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
1332 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1333 mono_mb_emit_byte (mb
, 3);
1334 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1335 mono_mb_emit_byte (mb
, CEE_BR_S
);
1336 mono_mb_emit_byte (mb
, 1);
1337 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1338 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1340 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1341 mono_mb_emit_ldloc (mb
, 1);
1342 mono_mb_emit_ldloc (mb
, 0);
1343 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
1344 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1345 mono_mb_emit_byte (mb
, 3);
1346 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1347 mono_mb_emit_byte (mb
, CEE_BR_S
);
1348 mono_mb_emit_byte (mb
, 1);
1349 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1350 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1352 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1353 MonoClass
*eklass
= NULL
;
1356 if (type
->type
== MONO_TYPE_SZARRAY
) {
1357 eklass
= type
->data
.klass
;
1359 g_assert_not_reached ();
1362 esize
= mono_class_native_size (eklass
, NULL
);
1364 /* create a new array */
1365 mono_mb_emit_ldloc (mb
, 1);
1366 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1367 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
1368 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1370 if (eklass
->blittable
) {
1371 /* copy the elements */
1372 mono_mb_emit_ldloc (mb
, 1);
1373 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1374 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
1375 mono_mb_emit_byte (mb
, CEE_ADD
);
1376 mono_mb_emit_ldloc (mb
, 0);
1377 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1378 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1379 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1382 int array_var
, src_var
, dst_var
, index_var
;
1383 guint32 label2
, label3
;
1385 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1386 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1387 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1390 mono_mb_emit_ldloc (mb
, 1);
1391 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1392 mono_mb_emit_stloc (mb
, array_var
);
1394 /* save the old src pointer */
1395 mono_mb_emit_ldloc (mb
, 0);
1396 mono_mb_emit_stloc (mb
, src_var
);
1397 /* save the old dst pointer */
1398 mono_mb_emit_ldloc (mb
, 1);
1399 mono_mb_emit_stloc (mb
, dst_var
);
1401 /* Emit marshalling loop */
1402 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1403 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1404 mono_mb_emit_stloc (mb
, index_var
);
1407 label2
= mono_mb_get_label (mb
);
1408 mono_mb_emit_ldloc (mb
, index_var
);
1409 mono_mb_emit_ldloc (mb
, array_var
);
1410 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1411 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1413 /* src is already set */
1416 mono_mb_emit_ldloc (mb
, array_var
);
1417 mono_mb_emit_ldloc (mb
, index_var
);
1418 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1419 mono_mb_emit_stloc (mb
, 1);
1421 /* Do the conversion */
1422 emit_struct_conv (mb
, eklass
, TRUE
);
1425 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1427 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
1429 mono_mb_patch_branch (mb
, label3
);
1431 /* restore the old src pointer */
1432 mono_mb_emit_ldloc (mb
, src_var
);
1433 mono_mb_emit_stloc (mb
, 0);
1434 /* restore the old dst pointer */
1435 mono_mb_emit_ldloc (mb
, dst_var
);
1436 mono_mb_emit_stloc (mb
, 1);
1440 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1441 MonoClass
*eclass
= mono_defaults
.char_class
;
1443 /* create a new array */
1444 mono_mb_emit_ldloc (mb
, 1);
1445 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1446 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
1447 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1449 mono_mb_emit_ldloc (mb
, 1);
1450 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1451 mono_mb_emit_ldloc (mb
, 0);
1452 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1453 mono_mb_emit_icall (mb
, mono_byvalarray_to_byte_array
);
1456 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1457 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
1458 mono_mb_emit_ldloc (mb
, 1);
1459 mono_mb_emit_ldloc (mb
, 0);
1460 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1461 mono_mb_emit_icall (mb
, mono_string_from_byvalstr
);
1463 mono_mb_emit_ldloc (mb
, 1);
1464 mono_mb_emit_ldloc (mb
, 0);
1465 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1467 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1469 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
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_byvalwstr
);
1476 mono_mb_emit_ldloc (mb
, 1);
1477 mono_mb_emit_ldloc (mb
, 0);
1478 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
1480 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1482 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1483 mono_mb_emit_ldloc (mb
, 1);
1484 mono_mb_emit_ldloc (mb
, 0);
1485 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1487 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
1489 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1491 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1494 // In Mono historically LPSTR was treated as a UTF8STR
1495 case MONO_MARSHAL_CONV_STR_LPSTR
:
1496 case MONO_MARSHAL_CONV_STR_UTF8STR
:
1497 mono_mb_emit_ldloc (mb
, 1);
1498 mono_mb_emit_ldloc (mb
, 0);
1499 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1500 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1501 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1503 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1504 mono_mb_emit_ldloc (mb
, 1);
1505 mono_mb_emit_ldloc (mb
, 0);
1506 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1507 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
1508 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1510 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1511 MonoClass
*klass
= mono_class_from_mono_type (type
);
1512 int src_var
, dst_var
;
1514 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1515 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1517 /* *dst = new object */
1518 mono_mb_emit_ldloc (mb
, 1);
1519 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1520 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
1521 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1523 /* save the old src pointer */
1524 mono_mb_emit_ldloc (mb
, 0);
1525 mono_mb_emit_stloc (mb
, src_var
);
1526 /* save the old dst pointer */
1527 mono_mb_emit_ldloc (mb
, 1);
1528 mono_mb_emit_stloc (mb
, dst_var
);
1530 /* dst = pointer to newly created object data */
1531 mono_mb_emit_ldloc (mb
, 1);
1532 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1533 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
1534 mono_mb_emit_byte (mb
, CEE_ADD
);
1535 mono_mb_emit_stloc (mb
, 1);
1537 emit_struct_conv (mb
, klass
, TRUE
);
1539 /* restore the old src pointer */
1540 mono_mb_emit_ldloc (mb
, src_var
);
1541 mono_mb_emit_stloc (mb
, 0);
1542 /* restore the old dst pointer */
1543 mono_mb_emit_ldloc (mb
, dst_var
);
1544 mono_mb_emit_stloc (mb
, 1);
1547 case MONO_MARSHAL_CONV_DEL_FTN
: {
1548 MonoClass
*klass
= mono_class_from_mono_type (type
);
1550 mono_mb_emit_ldloc (mb
, 1);
1551 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1552 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1553 mono_mb_emit_ldloc (mb
, 0);
1554 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1555 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
1556 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1559 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1560 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type
)->name
);
1564 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
1565 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1566 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1567 mono_cominterop_emit_ptr_to_object_conv (mb
, type
, conv
, mspec
);
1569 #endif /* DISABLE_COM */
1571 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1573 * Passing SafeHandles as ref does not allow the unmanaged code
1574 * to change the SafeHandle value. If the value is changed,
1575 * we should issue a diagnostic exception (NotSupportedException)
1576 * that informs the user that changes to handles in unmanaged code
1579 * Since we currently have no access to the original
1580 * SafeHandle that was used during the marshalling,
1581 * for now we just ignore this, and ignore/discard any
1582 * changes that might have happened to the handle.
1587 case MONO_MARSHAL_CONV_HANDLEREF
: {
1589 * Passing HandleRefs in a struct that is ref()ed does not
1590 * copy the values back to the HandleRef
1595 case MONO_MARSHAL_CONV_STR_BSTR
:
1596 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1597 case MONO_MARSHAL_CONV_STR_TBSTR
:
1598 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1600 char *msg
= g_strdup_printf ("marshaling conversion %d not implemented", conv
);
1602 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1609 conv_to_icall (MonoMarshalConv conv
, int *ind_store_type
)
1612 if (!ind_store_type
)
1613 ind_store_type
= &dummy
;
1614 *ind_store_type
= CEE_STIND_I
;
1616 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1617 return mono_marshal_string_to_utf16
;
1618 case MONO_MARSHAL_CONV_LPWSTR_STR
:
1619 *ind_store_type
= CEE_STIND_REF
;
1620 return ves_icall_mono_string_from_utf16
;
1621 case MONO_MARSHAL_CONV_LPTSTR_STR
:
1622 *ind_store_type
= CEE_STIND_REF
;
1623 return mono_string_new_wrapper
;
1624 case MONO_MARSHAL_CONV_UTF8STR_STR
:
1625 case MONO_MARSHAL_CONV_LPSTR_STR
:
1626 *ind_store_type
= CEE_STIND_REF
;
1627 return mono_string_new_wrapper
;
1628 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1630 return mono_marshal_string_to_utf16
;
1632 return mono_string_to_utf8str
;
1634 // In Mono historically LPSTR was treated as a UTF8STR
1635 case MONO_MARSHAL_CONV_STR_UTF8STR
:
1636 case MONO_MARSHAL_CONV_STR_LPSTR
:
1637 return mono_string_to_utf8str
;
1638 case MONO_MARSHAL_CONV_STR_BSTR
:
1639 return mono_string_to_bstr
;
1640 case MONO_MARSHAL_CONV_BSTR_STR
:
1641 *ind_store_type
= CEE_STIND_REF
;
1642 return mono_string_from_bstr_icall
;
1643 case MONO_MARSHAL_CONV_STR_TBSTR
:
1644 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1645 return mono_string_to_ansibstr
;
1646 case MONO_MARSHAL_CONV_SB_UTF8STR
:
1647 case MONO_MARSHAL_CONV_SB_LPSTR
:
1648 return mono_string_builder_to_utf8
;
1649 case MONO_MARSHAL_CONV_SB_LPTSTR
:
1651 return mono_string_builder_to_utf16
;
1653 return mono_string_builder_to_utf8
;
1655 case MONO_MARSHAL_CONV_SB_LPWSTR
:
1656 return mono_string_builder_to_utf16
;
1657 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1658 return mono_array_to_savearray
;
1659 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1660 return mono_array_to_lparray
;
1661 case MONO_MARSHAL_FREE_LPARRAY
:
1662 return mono_free_lparray
;
1663 case MONO_MARSHAL_CONV_DEL_FTN
:
1664 return mono_delegate_to_ftnptr
;
1665 case MONO_MARSHAL_CONV_FTN_DEL
:
1666 *ind_store_type
= CEE_STIND_REF
;
1667 return mono_ftnptr_to_delegate
;
1668 case MONO_MARSHAL_CONV_UTF8STR_SB
:
1669 case MONO_MARSHAL_CONV_LPSTR_SB
:
1670 *ind_store_type
= CEE_STIND_REF
;
1671 return mono_string_utf8_to_builder
;
1672 case MONO_MARSHAL_CONV_LPTSTR_SB
:
1673 *ind_store_type
= CEE_STIND_REF
;
1675 return mono_string_utf16_to_builder
;
1677 return mono_string_utf8_to_builder
;
1679 case MONO_MARSHAL_CONV_LPWSTR_SB
:
1680 *ind_store_type
= CEE_STIND_REF
;
1681 return mono_string_utf16_to_builder
;
1682 case MONO_MARSHAL_FREE_ARRAY
:
1683 return mono_marshal_free_array
;
1684 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1685 return mono_string_to_byvalstr
;
1686 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
1687 return mono_string_to_byvalwstr
;
1689 g_assert_not_reached ();
1696 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1702 case MONO_MARSHAL_CONV_BOOL_I4
:
1703 mono_mb_emit_ldloc (mb
, 1);
1704 mono_mb_emit_ldloc (mb
, 0);
1705 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1706 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
1708 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1709 mono_mb_emit_ldloc (mb
, 1);
1710 mono_mb_emit_ldloc (mb
, 0);
1711 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1712 mono_mb_emit_byte (mb
, CEE_NEG
);
1713 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
1715 // In Mono historically LPSTR was treated as a UTF8STR
1716 case MONO_MARSHAL_CONV_STR_UTF8STR
:
1717 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1718 case MONO_MARSHAL_CONV_STR_LPSTR
:
1719 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1720 case MONO_MARSHAL_CONV_STR_BSTR
:
1721 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1722 case MONO_MARSHAL_CONV_STR_TBSTR
: {
1725 /* free space if free == true */
1726 mono_mb_emit_ldloc (mb
, 2);
1727 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1728 mono_mb_emit_ldloc (mb
, 1);
1729 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1730 mono_mb_emit_icall (mb
, g_free
);
1731 mono_mb_patch_short_branch (mb
, pos
);
1733 mono_mb_emit_ldloc (mb
, 1);
1734 mono_mb_emit_ldloc (mb
, 0);
1735 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1736 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
1737 mono_mb_emit_byte (mb
, stind_op
);
1740 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1741 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1742 case MONO_MARSHAL_CONV_DEL_FTN
:
1743 mono_mb_emit_ldloc (mb
, 1);
1744 mono_mb_emit_ldloc (mb
, 0);
1745 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1746 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
1747 mono_mb_emit_byte (mb
, stind_op
);
1749 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1750 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
1753 mono_mb_emit_ldloc (mb
, 1); /* dst */
1754 mono_mb_emit_ldloc (mb
, 0);
1755 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
1756 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1757 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
1760 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1761 MonoClass
*eklass
= NULL
;
1764 if (type
->type
== MONO_TYPE_SZARRAY
) {
1765 eklass
= type
->data
.klass
;
1767 g_assert_not_reached ();
1770 if (eklass
->valuetype
)
1771 esize
= mono_class_native_size (eklass
, NULL
);
1773 esize
= sizeof (gpointer
);
1775 mono_mb_emit_ldloc (mb
, 0);
1776 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1777 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1779 if (eklass
->blittable
) {
1780 mono_mb_emit_ldloc (mb
, 1);
1781 mono_mb_emit_ldloc (mb
, 0);
1782 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1783 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
1784 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1785 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1786 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1788 int array_var
, src_var
, dst_var
, index_var
;
1789 guint32 label2
, label3
;
1791 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1792 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1793 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1796 mono_mb_emit_ldloc (mb
, 0);
1797 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1798 mono_mb_emit_stloc (mb
, array_var
);
1800 /* save the old src pointer */
1801 mono_mb_emit_ldloc (mb
, 0);
1802 mono_mb_emit_stloc (mb
, src_var
);
1803 /* save the old dst pointer */
1804 mono_mb_emit_ldloc (mb
, 1);
1805 mono_mb_emit_stloc (mb
, dst_var
);
1807 /* Emit marshalling loop */
1808 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1809 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1810 mono_mb_emit_stloc (mb
, index_var
);
1813 label2
= mono_mb_get_label (mb
);
1814 mono_mb_emit_ldloc (mb
, index_var
);
1815 mono_mb_emit_ldloc (mb
, array_var
);
1816 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1817 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1820 mono_mb_emit_ldloc (mb
, array_var
);
1821 mono_mb_emit_ldloc (mb
, index_var
);
1822 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1823 mono_mb_emit_stloc (mb
, 0);
1825 /* dst is already set */
1827 /* Do the conversion */
1828 emit_struct_conv (mb
, eklass
, FALSE
);
1831 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1833 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
1835 mono_mb_patch_branch (mb
, label3
);
1837 /* restore the old src pointer */
1838 mono_mb_emit_ldloc (mb
, src_var
);
1839 mono_mb_emit_stloc (mb
, 0);
1840 /* restore the old dst pointer */
1841 mono_mb_emit_ldloc (mb
, dst_var
);
1842 mono_mb_emit_stloc (mb
, 1);
1845 mono_mb_patch_branch (mb
, pos
);
1848 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1849 mono_mb_emit_ldloc (mb
, 0);
1850 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1851 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1853 mono_mb_emit_ldloc (mb
, 1);
1854 mono_mb_emit_ldloc (mb
, 0);
1855 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1856 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1857 mono_mb_emit_icall (mb
, mono_array_to_byte_byvalarray
);
1858 mono_mb_patch_short_branch (mb
, pos
);
1861 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1862 int src_var
, dst_var
;
1864 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1865 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1867 mono_mb_emit_ldloc (mb
, 0);
1868 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1869 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1871 /* save the old src pointer */
1872 mono_mb_emit_ldloc (mb
, 0);
1873 mono_mb_emit_stloc (mb
, src_var
);
1874 /* save the old dst pointer */
1875 mono_mb_emit_ldloc (mb
, 1);
1876 mono_mb_emit_stloc (mb
, dst_var
);
1878 /* src = pointer to object data */
1879 mono_mb_emit_ldloc (mb
, 0);
1880 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1881 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
1882 mono_mb_emit_byte (mb
, CEE_ADD
);
1883 mono_mb_emit_stloc (mb
, 0);
1885 emit_struct_conv (mb
, mono_class_from_mono_type (type
), FALSE
);
1887 /* restore the old src pointer */
1888 mono_mb_emit_ldloc (mb
, src_var
);
1889 mono_mb_emit_stloc (mb
, 0);
1890 /* restore the old dst pointer */
1891 mono_mb_emit_ldloc (mb
, dst_var
);
1892 mono_mb_emit_stloc (mb
, 1);
1894 mono_mb_patch_branch (mb
, pos
);
1899 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
1900 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1901 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1902 mono_cominterop_emit_object_to_ptr_conv (mb
, type
, conv
, mspec
);
1904 #endif /* DISABLE_COM */
1906 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1909 mono_mb_emit_ldloc (mb
, 0);
1910 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1911 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1912 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
1913 mono_mb_patch_branch (mb
, pos
);
1915 /* Pull the handle field from SafeHandle */
1916 mono_mb_emit_ldloc (mb
, 1);
1917 mono_mb_emit_ldloc (mb
, 0);
1918 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1919 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
1920 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1921 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1925 case MONO_MARSHAL_CONV_HANDLEREF
: {
1926 mono_mb_emit_ldloc (mb
, 1);
1927 mono_mb_emit_ldloc (mb
, 0);
1928 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
1929 mono_mb_emit_byte (mb
, CEE_ADD
);
1930 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1931 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1936 g_error ("marshalling conversion %d not implemented", conv
);
1942 offset_of_first_nonstatic_field (MonoClass
*klass
)
1945 int fcount
= mono_class_get_field_count (klass
);
1946 mono_class_setup_fields (klass
);
1947 for (i
= 0; i
< fcount
; 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 get_fixed_buffer_attr (MonoClassField
*field
, MonoType
**out_etype
, int *out_len
)
1959 MonoCustomAttrInfo
*cinfo
;
1960 MonoCustomAttrEntry
*attr
;
1963 cinfo
= mono_custom_attrs_from_field_checked (field
->parent
, field
, &error
);
1964 if (!is_ok (&error
))
1968 for (aindex
= 0; aindex
< cinfo
->num_attrs
; ++aindex
) {
1969 MonoClass
*ctor_class
= cinfo
->attrs
[aindex
].ctor
->klass
;
1970 if (mono_class_has_parent (ctor_class
, mono_class_get_fixed_buffer_attribute_class ())) {
1971 attr
= &cinfo
->attrs
[aindex
];
1977 MonoArray
*typed_args
, *named_args
;
1978 CattrNamedArg
*arginfo
;
1981 mono_reflection_create_custom_attr_data_args (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
, &error
);
1982 if (!is_ok (&error
))
1984 g_assert (mono_array_length (typed_args
) == 2);
1987 o
= mono_array_get (typed_args
, MonoObject
*, 0);
1988 *out_etype
= monotype_cast (o
)->type
;
1989 o
= mono_array_get (typed_args
, MonoObject
*, 1);
1990 g_assert (o
->vtable
->klass
== mono_defaults
.int32_class
);
1991 *out_len
= *(gint32
*)mono_object_unbox (o
);
1994 if (cinfo
&& !cinfo
->cached
)
1995 mono_custom_attrs_free (cinfo
);
1996 return attr
!= NULL
;
2000 emit_fixed_buf_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoType
*etype
, int len
, gboolean to_object
, int *out_usize
)
2002 MonoClass
*klass
= mono_class_from_mono_type (type
);
2003 MonoClass
*eklass
= mono_class_from_mono_type (etype
);
2006 esize
= mono_class_native_size (eklass
, NULL
);
2008 MonoMarshalNative string_encoding
= klass
->unicode
? MONO_NATIVE_LPWSTR
: MONO_NATIVE_LPSTR
;
2009 int usize
= mono_class_value_size (eklass
, NULL
);
2010 int msize
= mono_class_value_size (eklass
, NULL
);
2012 //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), eklass->blittable, string_encoding);
2014 if (eklass
->blittable
) {
2015 /* copy the elements */
2016 mono_mb_emit_ldloc (mb
, 1);
2017 mono_mb_emit_ldloc (mb
, 0);
2018 mono_mb_emit_icon (mb
, len
* esize
);
2019 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2020 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2023 guint32 label2
, label3
;
2025 /* Emit marshalling loop */
2026 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2027 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2028 mono_mb_emit_stloc (mb
, index_var
);
2031 label2
= mono_mb_get_label (mb
);
2032 mono_mb_emit_ldloc (mb
, index_var
);
2033 mono_mb_emit_icon (mb
, len
);
2034 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2036 /* src/dst is already set */
2038 /* Do the conversion */
2039 MonoTypeEnum t
= etype
->type
;
2045 case MONO_TYPE_BOOLEAN
:
2048 case MONO_TYPE_CHAR
:
2054 mono_mb_emit_ldloc (mb
, 1);
2055 mono_mb_emit_ldloc (mb
, 0);
2056 if (t
== MONO_TYPE_CHAR
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
2058 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
2059 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
2061 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
2062 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
2066 mono_mb_emit_byte (mb
, mono_type_to_ldind (etype
));
2067 mono_mb_emit_byte (mb
, mono_type_to_stind (etype
));
2071 g_assert_not_reached ();
2076 mono_mb_emit_add_to_local (mb
, 0, usize
);
2077 mono_mb_emit_add_to_local (mb
, 1, msize
);
2079 mono_mb_emit_add_to_local (mb
, 0, msize
);
2080 mono_mb_emit_add_to_local (mb
, 1, usize
);
2084 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2086 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2088 mono_mb_patch_branch (mb
, label3
);
2091 *out_usize
= usize
* len
;
2095 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
,
2096 int offset_of_first_child_field
, MonoMarshalNative string_encoding
)
2098 MonoMarshalType
*info
;
2102 emit_struct_conv_full (mb
, klass
->parent
, to_object
, offset_of_first_nonstatic_field (klass
), string_encoding
);
2104 info
= mono_marshal_load_type_info (klass
);
2106 if (info
->native_size
== 0)
2109 if (klass
->blittable
) {
2110 int usize
= mono_class_value_size (klass
, NULL
);
2111 g_assert (usize
== info
->native_size
);
2112 mono_mb_emit_ldloc (mb
, 1);
2113 mono_mb_emit_ldloc (mb
, 0);
2114 mono_mb_emit_icon (mb
, usize
);
2115 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2116 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2119 mono_mb_emit_add_to_local (mb
, 0, usize
);
2120 mono_mb_emit_add_to_local (mb
, 1, offset_of_first_child_field
);
2122 mono_mb_emit_add_to_local (mb
, 0, offset_of_first_child_field
);
2123 mono_mb_emit_add_to_local (mb
, 1, usize
);
2128 if (klass
!= mono_class_try_get_safehandle_class ()) {
2129 if (mono_class_is_auto_layout (klass
)) {
2130 char *msg
= g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
2131 mono_type_full_name (&klass
->byval_arg
));
2132 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2137 for (i
= 0; i
< info
->num_fields
; i
++) {
2138 MonoMarshalNative ntype
;
2139 MonoMarshalConv conv
;
2140 MonoType
*ftype
= info
->fields
[i
].field
->type
;
2143 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
2145 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
2148 ntype
= (MonoMarshalNative
)mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, klass
->unicode
, &conv
);
2151 msize
= klass
->instance_size
- info
->fields
[i
].field
->offset
;
2152 usize
= info
->native_size
- info
->fields
[i
].offset
;
2154 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
2155 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
2158 if (klass
!= mono_class_try_get_safehandle_class ()){
2160 * FIXME: Should really check for usize==0 and msize>0, but we apply
2161 * the layout to the managed structure as well.
2164 if (mono_class_is_explicit_layout (klass
) && (usize
== 0)) {
2165 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
2166 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
2167 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
2168 "reference field at the same offset as another field.",
2169 mono_type_full_name (&klass
->byval_arg
));
2174 case MONO_MARSHAL_CONV_NONE
: {
2177 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
2178 g_assert (!ftype
->byref
);
2179 if (ftype
->type
== MONO_TYPE_I
|| ftype
->type
== MONO_TYPE_U
) {
2180 mono_mb_emit_ldloc (mb
, 1);
2181 mono_mb_emit_ldloc (mb
, 0);
2182 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2183 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2194 case MONO_TYPE_BOOLEAN
:
2197 case MONO_TYPE_CHAR
:
2203 mono_mb_emit_ldloc (mb
, 1);
2204 mono_mb_emit_ldloc (mb
, 0);
2205 if (t
== MONO_TYPE_CHAR
&& ntype
== MONO_NATIVE_U1
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
2207 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
2208 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
2210 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
2211 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
2214 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
2215 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
2218 case MONO_TYPE_VALUETYPE
: {
2219 int src_var
, dst_var
;
2223 if (ftype
->data
.klass
->enumtype
) {
2224 ftype
= mono_class_enum_basetype (ftype
->data
.klass
);
2228 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2229 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2231 /* save the old src pointer */
2232 mono_mb_emit_ldloc (mb
, 0);
2233 mono_mb_emit_stloc (mb
, src_var
);
2234 /* save the old dst pointer */
2235 mono_mb_emit_ldloc (mb
, 1);
2236 mono_mb_emit_stloc (mb
, dst_var
);
2238 if (get_fixed_buffer_attr (info
->fields
[i
].field
, &etype
, &len
)) {
2239 emit_fixed_buf_conv (mb
, ftype
, etype
, len
, to_object
, &usize
);
2241 emit_struct_conv (mb
, ftype
->data
.klass
, to_object
);
2244 /* restore the old src pointer */
2245 mono_mb_emit_ldloc (mb
, src_var
);
2246 mono_mb_emit_stloc (mb
, 0);
2247 /* restore the old dst pointer */
2248 mono_mb_emit_ldloc (mb
, dst_var
);
2249 mono_mb_emit_stloc (mb
, 1);
2252 case MONO_TYPE_OBJECT
: {
2255 static MonoMethod
*variant_clear
= NULL
;
2256 static MonoMethod
*get_object_for_native_variant
= NULL
;
2259 variant_clear
= mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2260 if (!get_object_for_native_variant
)
2261 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
2262 mono_mb_emit_ldloc (mb
, 1);
2263 mono_mb_emit_ldloc (mb
, 0);
2264 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
2265 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2267 mono_mb_emit_ldloc (mb
, 0);
2268 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
2271 static MonoMethod
*get_native_variant_for_object
= NULL
;
2273 if (!get_native_variant_for_object
)
2274 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
2276 mono_mb_emit_ldloc (mb
, 0);
2277 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
2278 mono_mb_emit_ldloc (mb
, 1);
2279 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
2282 char *msg
= g_strdup_printf ("COM support was disabled at compilation time.");
2283 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2289 g_warning ("marshaling type %02x not implemented", ftype
->type
);
2290 g_assert_not_reached ();
2295 int src_var
, dst_var
;
2297 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2298 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2300 /* save the old src pointer */
2301 mono_mb_emit_ldloc (mb
, 0);
2302 mono_mb_emit_stloc (mb
, src_var
);
2303 /* save the old dst pointer */
2304 mono_mb_emit_ldloc (mb
, 1);
2305 mono_mb_emit_stloc (mb
, dst_var
);
2308 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
2310 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
2312 /* restore the old src pointer */
2313 mono_mb_emit_ldloc (mb
, src_var
);
2314 mono_mb_emit_stloc (mb
, 0);
2315 /* restore the old dst pointer */
2316 mono_mb_emit_ldloc (mb
, dst_var
);
2317 mono_mb_emit_stloc (mb
, 1);
2322 mono_mb_emit_add_to_local (mb
, 0, usize
);
2323 mono_mb_emit_add_to_local (mb
, 1, msize
);
2325 mono_mb_emit_add_to_local (mb
, 0, msize
);
2326 mono_mb_emit_add_to_local (mb
, 1, usize
);
2332 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
2334 emit_struct_conv_full (mb
, klass
, to_object
, 0, (MonoMarshalNative
)-1);
2338 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
2340 /* Call DestroyStructure */
2341 /* FIXME: Only do this if needed */
2342 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2343 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
2344 mono_mb_emit_ldloc (mb
, struct_var
);
2345 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
2349 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, gpointer checkpoint_func
)
2351 int pos_noabort
, pos_noex
;
2353 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2354 mono_mb_emit_byte (mb
, CEE_MONO_LDPTR_INT_REQ_FLAG
);
2355 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
2356 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2358 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2359 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
2361 mono_mb_emit_icall (mb
, checkpoint_func
);
2362 /* Throw the exception returned by the checkpoint function, if any */
2363 mono_mb_emit_byte (mb
, CEE_DUP
);
2364 pos_noex
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2365 mono_mb_emit_byte (mb
, CEE_THROW
);
2366 mono_mb_patch_branch (mb
, pos_noex
);
2367 mono_mb_emit_byte (mb
, CEE_POP
);
2369 mono_mb_patch_branch (mb
, pos_noabort
);
2373 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2375 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
2378 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_interruption_checkpoint
);
2382 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2384 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_force_interruption_checkpoint_noraise
);
2388 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2390 emit_thread_interrupt_checkpoint (mb
);
2394 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2396 emit_thread_force_interrupt_checkpoint (mb
);
2399 #endif /* DISABLE_JIT */
2401 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
2402 static MonoAsyncResult
*
2403 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
2406 MonoMulticastDelegate
*mcast_delegate
;
2410 g_assert (delegate
);
2411 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
2412 if (mcast_delegate
->delegates
!= NULL
) {
2413 mono_set_pending_exception (mono_get_exception_argument (NULL
, "The delegate must have only one target"));
2417 #ifndef DISABLE_REMOTING
2418 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
2419 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
2420 if (!mono_class_is_contextbound (tp
->remote_class
->proxy_class
) || tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
2421 /* If the target is a proxy, make a direct call. Is proxy's work
2422 // to make the call asynchronous.
2424 MonoMethodMessage
*msg
;
2425 MonoDelegate
*async_callback
;
2427 MonoAsyncResult
*ares
;
2429 MonoArray
*out_args
;
2430 method
= delegate
->method
;
2432 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
, &error
);
2433 if (mono_error_set_pending_exception (&error
))
2435 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
, &error
);
2436 if (mono_error_set_pending_exception (&error
))
2438 MONO_OBJECT_SETREF (ares
, async_delegate
, (MonoObject
*)delegate
);
2439 MONO_OBJECT_SETREF (ares
, async_callback
, (MonoObject
*)async_callback
);
2440 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
2441 msg
->call_type
= CallType_BeginInvoke
;
2444 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, &error
);
2445 if (!mono_error_ok (&error
)) {
2446 mono_error_set_pending_exception (&error
);
2450 mono_set_pending_exception ((MonoException
*) exc
);
2456 klass
= delegate
->object
.vtable
->klass
;
2458 method
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
2460 method
= mono_get_delegate_invoke (klass
);
2463 MonoAsyncResult
*result
= mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject
*) delegate
, method
, params
, &error
);
2464 mono_error_set_pending_exception (&error
);
2471 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
2473 int i
, params_var
, tmp_var
;
2475 /* allocate local (pointer) *params[] */
2476 params_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2477 /* allocate local (pointer) tmp */
2478 tmp_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2480 /* alloate space on stack to store an array of pointers to the arguments */
2481 mono_mb_emit_icon (mb
, sizeof (gpointer
) * (sig
->param_count
+ 1));
2482 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2483 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2484 mono_mb_emit_stloc (mb
, params_var
);
2487 mono_mb_emit_ldloc (mb
, params_var
);
2488 mono_mb_emit_stloc (mb
, tmp_var
);
2490 if (save_this
&& sig
->hasthis
) {
2491 mono_mb_emit_ldloc (mb
, tmp_var
);
2492 mono_mb_emit_ldarg_addr (mb
, 0);
2493 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2494 /* tmp = tmp + sizeof (gpointer) */
2495 if (sig
->param_count
)
2496 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2500 for (i
= 0; i
< sig
->param_count
; i
++) {
2501 mono_mb_emit_ldloc (mb
, tmp_var
);
2502 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
2503 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2504 /* tmp = tmp + sizeof (gpointer) */
2505 if (i
< (sig
->param_count
- 1))
2506 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2512 #endif /* DISABLE_JIT */
2515 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
2519 GString
*res
= g_string_new ("");
2522 g_string_append (res
, prefix
);
2523 g_string_append_c (res
, '_');
2526 mono_type_get_desc (res
, sig
->ret
, FALSE
);
2529 g_string_append (res
, "__this__");
2531 for (i
= 0; i
< sig
->param_count
; ++i
) {
2532 g_string_append_c (res
, '_');
2533 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
2536 g_string_free (res
, FALSE
);
2541 * mono_marshal_get_string_encoding:
2543 * Return the string encoding which should be used for a given parameter.
2545 static MonoMarshalNative
2546 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2548 /* First try the parameter marshal info */
2550 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
2551 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
2552 return spec
->data
.array_data
.elem_type
;
2555 return spec
->native
;
2559 return MONO_NATIVE_LPSTR
;
2561 /* Then try the method level marshal info */
2562 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
2563 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
2564 return MONO_NATIVE_LPSTR
;
2565 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
2566 return MONO_NATIVE_LPWSTR
;
2567 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
2569 return MONO_NATIVE_LPWSTR
;
2571 return MONO_NATIVE_LPSTR
;
2574 return MONO_NATIVE_LPSTR
;
2578 static MonoMarshalConv
2579 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2581 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2584 case MONO_NATIVE_LPWSTR
:
2585 return MONO_MARSHAL_CONV_STR_LPWSTR
;
2586 case MONO_NATIVE_LPSTR
:
2587 case MONO_NATIVE_VBBYREFSTR
:
2588 return MONO_MARSHAL_CONV_STR_LPSTR
;
2589 case MONO_NATIVE_LPTSTR
:
2590 return MONO_MARSHAL_CONV_STR_LPTSTR
;
2591 case MONO_NATIVE_BSTR
:
2592 return MONO_MARSHAL_CONV_STR_BSTR
;
2593 case MONO_NATIVE_UTF8STR
:
2594 return MONO_MARSHAL_CONV_STR_UTF8STR
;
2596 return MONO_MARSHAL_CONV_INVALID
;
2600 static MonoMarshalConv
2601 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2603 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2606 case MONO_NATIVE_LPWSTR
:
2607 return MONO_MARSHAL_CONV_SB_LPWSTR
;
2608 case MONO_NATIVE_LPSTR
:
2609 return MONO_MARSHAL_CONV_SB_LPSTR
;
2610 case MONO_NATIVE_UTF8STR
:
2611 return MONO_MARSHAL_CONV_SB_UTF8STR
;
2612 case MONO_NATIVE_LPTSTR
:
2613 return MONO_MARSHAL_CONV_SB_LPTSTR
;
2615 return MONO_MARSHAL_CONV_INVALID
;
2619 static MonoMarshalConv
2620 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2622 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2627 case MONO_NATIVE_LPWSTR
:
2629 return MONO_MARSHAL_CONV_LPWSTR_STR
;
2630 case MONO_NATIVE_UTF8STR
:
2631 return MONO_MARSHAL_CONV_UTF8STR_STR
;
2632 case MONO_NATIVE_LPSTR
:
2633 case MONO_NATIVE_VBBYREFSTR
:
2634 return MONO_MARSHAL_CONV_LPSTR_STR
;
2635 case MONO_NATIVE_LPTSTR
:
2639 return MONO_MARSHAL_CONV_LPTSTR_STR
;
2640 case MONO_NATIVE_BSTR
:
2641 return MONO_MARSHAL_CONV_BSTR_STR
;
2643 return MONO_MARSHAL_CONV_INVALID
;
2647 static MonoMarshalConv
2648 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2650 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2655 case MONO_NATIVE_LPWSTR
:
2657 * mono_string_builder_to_utf16 does not allocate a
2658 * new buffer, so no need to free it.
2661 return MONO_MARSHAL_CONV_LPWSTR_SB
;
2662 case MONO_NATIVE_UTF8STR
:
2663 return MONO_MARSHAL_CONV_UTF8STR_SB
;
2664 case MONO_NATIVE_LPSTR
:
2665 return MONO_MARSHAL_CONV_LPSTR_SB
;
2667 case MONO_NATIVE_LPTSTR
:
2668 return MONO_MARSHAL_CONV_LPTSTR_SB
;
2671 return MONO_MARSHAL_CONV_INVALID
;
2676 * Return whenever a field of a native structure or an array member needs to
2680 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2682 MonoMarshalNative encoding
;
2685 case MONO_TYPE_VALUETYPE
:
2686 /* FIXME: Optimize this */
2688 case MONO_TYPE_OBJECT
:
2689 case MONO_TYPE_CLASS
:
2690 if (t
->data
.klass
== mono_defaults
.stringbuilder_class
) {
2692 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
2696 case MONO_TYPE_STRING
:
2697 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2698 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
2705 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
2708 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
2711 mono_marshal_lock ();
2714 g_hash_table_new (hash_func
, equal_func
);
2715 mono_memory_barrier ();
2718 mono_marshal_unlock ();
2724 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
2726 return get_cache (var
, hash_func
, equal_func
);
2730 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
2734 mono_marshal_lock ();
2735 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2736 mono_marshal_unlock ();
2743 * Create a MonoMethod from MB, set INFO as wrapper info.
2746 mono_mb_create (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2747 int max_stack
, WrapperInfo
*info
)
2751 res
= mono_mb_create_method (mb
, sig
, max_stack
);
2753 mono_marshal_set_wrapper_info (res
, info
);
2757 /* Create the method from the builder and place it in the cache */
2759 mono_mb_create_and_cache_full (GHashTable
*cache
, gpointer key
,
2760 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2761 int max_stack
, WrapperInfo
*info
, gboolean
*out_found
)
2768 mono_marshal_lock ();
2769 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2770 mono_marshal_unlock ();
2773 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
2774 mono_marshal_lock ();
2775 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2778 g_hash_table_insert (cache
, key
, res
);
2779 mono_marshal_set_wrapper_info (res
, info
);
2780 mono_marshal_unlock ();
2784 mono_marshal_unlock ();
2785 mono_free_method (newm
);
2793 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
2794 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2797 return mono_mb_create_and_cache_full (cache
, key
, mb
, sig
, max_stack
, NULL
, NULL
);
2801 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
2804 int wrapper_type
= wrapper
->wrapper_type
;
2807 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2810 info
= mono_marshal_get_wrapper_info (wrapper
);
2812 switch (wrapper_type
) {
2813 case MONO_WRAPPER_REMOTING_INVOKE
:
2814 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
2815 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2816 m
= info
->d
.remoting
.method
;
2817 if (wrapper
->is_inflated
) {
2821 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
2822 * contains an uninflated method.
2824 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), &error
);
2825 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2829 case MONO_WRAPPER_SYNCHRONIZED
:
2830 m
= info
->d
.synchronized
.method
;
2831 if (wrapper
->is_inflated
) {
2834 result
= mono_class_inflate_generic_method_checked (m
, mono_method_get_context (wrapper
), &error
);
2835 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2839 case MONO_WRAPPER_UNBOX
:
2840 return info
->d
.unbox
.method
;
2841 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
2842 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_NONE
|| info
->subtype
== WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
|| info
->subtype
== WRAPPER_SUBTYPE_PINVOKE
))
2843 return info
->d
.managed_to_native
.method
;
2846 case MONO_WRAPPER_RUNTIME_INVOKE
:
2847 if (info
&& (info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
|| info
->subtype
== WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
))
2848 return info
->d
.runtime_invoke
.method
;
2851 case MONO_WRAPPER_DELEGATE_INVOKE
:
2853 return info
->d
.delegate_invoke
.method
;
2862 * mono_marshal_get_wrapper_info:
2864 * Retrieve the WrapperInfo structure associated with WRAPPER.
2867 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
2869 g_assert (wrapper
->wrapper_type
);
2871 return (WrapperInfo
*)mono_method_get_wrapper_data (wrapper
, 1);
2875 * mono_marshal_set_wrapper_info:
2877 * Set the WrapperInfo structure associated with the wrapper
2878 * method METHOD to INFO.
2881 mono_marshal_set_wrapper_info (MonoMethod
*method
, WrapperInfo
*info
)
2885 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2888 datav
= (void **)((MonoMethodWrapper
*)method
)->method_data
;
2893 mono_wrapper_info_create (MonoMethodBuilder
*mb
, WrapperSubtype subtype
)
2897 info
= (WrapperInfo
*)mono_image_alloc0 (mb
->method
->klass
->image
, sizeof (WrapperInfo
));
2898 info
->subtype
= subtype
;
2903 * get_wrapper_target_class:
2905 * Return the class where a wrapper method should be placed.
2908 get_wrapper_target_class (MonoImage
*image
)
2915 * - can't put all wrappers into an mscorlib class, because they reference
2916 * metadata (signature) so they should be put into the same image as the
2917 * method they wrap, so they are unloaded together.
2918 * - putting them into a class with a type initalizer could cause the
2919 * initializer to be executed which can be a problem if the wrappers are
2921 * - putting them into an inflated class can cause problems if the the
2922 * class is deleted because it references an image which is unloaded.
2923 * To avoid these problems, we put the wrappers into the <Module> class of
2926 if (image_is_dynamic (image
)) {
2927 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
2929 klass
= mono_class_get_checked (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1), &error
);
2930 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2938 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
2939 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
2943 * check_generic_wrapper_cache:
2945 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
2946 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
2947 * generic method definition.
2950 check_generic_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, gpointer key
, gpointer def_key
)
2953 MonoMethod
*inst
, *def
;
2954 MonoGenericContext
*ctx
;
2956 g_assert (orig_method
->is_inflated
);
2957 ctx
= mono_method_get_context (orig_method
);
2960 * Look for the instance
2962 res
= mono_marshal_find_in_cache (cache
, key
);
2967 * Look for the definition
2969 def
= mono_marshal_find_in_cache (cache
, def_key
);
2972 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
2973 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2975 mono_memory_barrier ();
2976 mono_marshal_lock ();
2977 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
2979 g_hash_table_insert (cache
, key
, inst
);
2982 mono_marshal_unlock ();
2989 cache_generic_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
, gpointer key
)
2992 MonoMethod
*inst
, *res
;
2995 * We use the same cache for the generic definition and the instances.
2997 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
2998 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
2999 mono_memory_barrier ();
3000 mono_marshal_lock ();
3001 res
= (MonoMethod
*)g_hash_table_lookup (cache
, key
);
3003 g_hash_table_insert (cache
, key
, inst
);
3006 mono_marshal_unlock ();
3011 check_generic_delegate_wrapper_cache (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def_method
, MonoGenericContext
*ctx
)
3015 MonoMethod
*inst
, *def
;
3018 * Look for the instance
3020 res
= mono_marshal_find_in_cache (cache
, orig_method
->klass
);
3025 * Look for the definition
3027 def
= mono_marshal_find_in_cache (cache
, def_method
->klass
);
3029 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
3030 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
3033 mono_memory_barrier ();
3034 mono_marshal_lock ();
3035 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
3037 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
3040 mono_marshal_unlock ();
3047 cache_generic_delegate_wrapper (GHashTable
*cache
, MonoMethod
*orig_method
, MonoMethod
*def
, MonoGenericContext
*ctx
)
3050 MonoMethod
*inst
, *res
;
3051 WrapperInfo
*ginfo
, *info
;
3054 * We use the same cache for the generic definition and the instances.
3056 inst
= mono_class_inflate_generic_method_checked (def
, ctx
, &error
);
3057 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
3059 ginfo
= mono_marshal_get_wrapper_info (def
);
3061 info
= (WrapperInfo
*)mono_image_alloc0 (def
->klass
->image
, sizeof (WrapperInfo
));
3062 info
->subtype
= ginfo
->subtype
;
3063 if (info
->subtype
== WRAPPER_SUBTYPE_NONE
) {
3064 info
->d
.delegate_invoke
.method
= mono_class_inflate_generic_method_checked (ginfo
->d
.delegate_invoke
.method
, ctx
, &error
);
3065 mono_error_assert_ok (&error
);
3069 mono_memory_barrier ();
3070 mono_marshal_lock ();
3071 res
= (MonoMethod
*)g_hash_table_lookup (cache
, orig_method
->klass
);
3073 g_hash_table_insert (cache
, orig_method
->klass
, inst
);
3076 mono_marshal_unlock ();
3081 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
3083 MonoMethodSignature
*sig
;
3084 MonoMethodBuilder
*mb
;
3089 MonoGenericContext
*ctx
= NULL
;
3090 MonoMethod
*orig_method
= NULL
;
3092 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3093 !strcmp (method
->name
, "BeginInvoke"));
3096 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
3098 if (method
->is_inflated
) {
3099 orig_method
= method
;
3100 ctx
= &((MonoMethodInflated
*)method
)->context
;
3101 method
= ((MonoMethodInflated
*)method
)->declaring
;
3104 sig
= mono_signature_no_pinvoke (method
);
3110 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_begin_invoke_cache
, mono_aligned_addr_hash
, NULL
);
3111 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
3115 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.delegate_begin_invoke_cache
,
3116 (GHashFunc
)mono_signature_hash
,
3117 (GCompareFunc
)mono_metadata_signature_equal
);
3118 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
3122 g_assert (sig
->hasthis
);
3124 name
= mono_signature_to_name (sig
, "begin_invoke");
3126 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
3128 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
3132 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3134 mono_mb_emit_ldarg (mb
, 0);
3135 mono_mb_emit_ldloc (mb
, params_var
);
3136 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
3137 mono_mb_emit_byte (mb
, CEE_RET
);
3142 def
= mono_mb_create_and_cache (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16);
3143 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
3145 res
= mono_mb_create_and_cache (cache
, sig
, mb
, sig
, sig
->param_count
+ 16);
3152 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
3154 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
3157 MonoDomain
*domain
= mono_domain_get ();
3158 MonoAsyncResult
*ares
;
3159 MonoMethod
*method
= NULL
;
3160 MonoMethodSignature
*sig
;
3161 MonoMethodMessage
*msg
;
3162 MonoObject
*res
, *exc
;
3163 MonoArray
*out_args
;
3166 g_assert (delegate
);
3168 if (!delegate
->method_info
) {
3169 g_assert (delegate
->method
);
3170 MonoReflectionMethod
*rm
= mono_method_get_object_checked (domain
, delegate
->method
, NULL
, &error
);
3171 if (!mono_error_ok (&error
)) {
3172 mono_error_set_pending_exception (&error
);
3175 MONO_OBJECT_SETREF (delegate
, method_info
, rm
);
3178 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
3179 g_assert_not_reached ();
3181 klass
= delegate
->object
.vtable
->klass
;
3183 method
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
3184 g_assert (method
!= NULL
);
3186 sig
= mono_signature_no_pinvoke (method
);
3188 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
, &error
);
3189 if (mono_error_set_pending_exception (&error
))
3192 ares
= (MonoAsyncResult
*)mono_array_get (msg
->args
, gpointer
, sig
->param_count
- 1);
3194 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."));
3198 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
3199 mono_set_pending_exception (mono_get_exception_invalid_operation (
3200 "The IAsyncResult object provided does not match this delegate."));
3204 #ifndef DISABLE_REMOTING
3205 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
3206 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
3207 msg
= (MonoMethodMessage
*)mono_object_new_checked (domain
, mono_defaults
.mono_method_message_class
, &error
);
3208 if (!mono_error_ok (&error
)) {
3209 mono_error_set_pending_exception (&error
);
3212 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
, &error
);
3213 if (mono_error_set_pending_exception (&error
))
3215 msg
->call_type
= CallType_EndInvoke
;
3216 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
3217 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
, &error
);
3218 if (!mono_error_ok (&error
)) {
3219 mono_error_set_pending_exception (&error
);
3225 res
= mono_threadpool_end_invoke (ares
, &out_args
, &exc
, &error
);
3226 if (mono_error_set_pending_exception (&error
))
3231 if (((MonoException
*)exc
)->stack_trace
) {
3232 MonoError inner_error
;
3233 char *strace
= mono_string_to_utf8_checked (((MonoException
*)exc
)->stack_trace
, &inner_error
);
3234 if (is_ok (&inner_error
)) {
3236 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
3238 MONO_OBJECT_SETREF (((MonoException
*)exc
), stack_trace
, mono_string_new (domain
, tmp
));
3241 mono_error_cleanup (&inner_error
); /* no stack trace, but at least throw the original exception */
3243 mono_set_pending_exception ((MonoException
*)exc
);
3246 mono_method_return_message_restore (method
, params
, out_args
, &error
);
3247 mono_error_set_pending_exception (&error
);
3254 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
3256 MonoType
*t
= mono_type_get_underlying_type (return_type
);
3258 if (return_type
->byref
)
3259 return_type
= &mono_defaults
.int_class
->byval_arg
;
3262 case MONO_TYPE_VOID
:
3263 g_assert_not_reached ();
3266 case MONO_TYPE_STRING
:
3267 case MONO_TYPE_CLASS
:
3268 case MONO_TYPE_OBJECT
:
3269 case MONO_TYPE_ARRAY
:
3270 case MONO_TYPE_SZARRAY
:
3274 case MONO_TYPE_BOOLEAN
:
3277 case MONO_TYPE_CHAR
:
3287 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (return_type
));
3288 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
3290 case MONO_TYPE_GENERICINST
:
3291 if (!mono_type_generic_inst_is_valuetype (t
))
3294 case MONO_TYPE_VALUETYPE
: {
3295 MonoClass
*klass
= mono_class_from_mono_type (return_type
);
3296 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
3297 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
3301 case MONO_TYPE_MVAR
: {
3302 MonoClass
*klass
= mono_class_from_mono_type (return_type
);
3303 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, klass
);
3307 g_warning ("type 0x%x not handled", return_type
->type
);
3308 g_assert_not_reached ();
3311 mono_mb_emit_byte (mb
, CEE_RET
);
3314 #endif /* DISABLE_JIT */
3317 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
3319 MonoMethodSignature
*sig
;
3320 MonoMethodBuilder
*mb
;
3325 MonoGenericContext
*ctx
= NULL
;
3326 MonoMethod
*orig_method
= NULL
;
3328 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3329 !strcmp (method
->name
, "EndInvoke"));
3332 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
3334 if (method
->is_inflated
) {
3335 orig_method
= method
;
3336 ctx
= &((MonoMethodInflated
*)method
)->context
;
3337 method
= ((MonoMethodInflated
*)method
)->declaring
;
3340 sig
= mono_signature_no_pinvoke (method
);
3346 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_end_invoke_cache
, mono_aligned_addr_hash
, NULL
);
3347 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
3351 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.delegate_end_invoke_cache
,
3352 (GHashFunc
)mono_signature_hash
,
3353 (GCompareFunc
)mono_metadata_signature_equal
);
3354 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
3358 g_assert (sig
->hasthis
);
3360 name
= mono_signature_to_name (sig
, "end_invoke");
3362 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
3364 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
3368 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3370 mono_mb_emit_ldarg (mb
, 0);
3371 mono_mb_emit_ldloc (mb
, params_var
);
3372 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
3374 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
3375 mono_mb_emit_byte (mb
, CEE_POP
);
3376 mono_mb_emit_byte (mb
, CEE_RET
);
3378 mono_mb_emit_restore_result (mb
, sig
->ret
);
3383 def
= mono_mb_create_and_cache (cache
, method
->klass
, mb
, sig
, sig
->param_count
+ 16);
3384 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
3386 res
= mono_mb_create_and_cache (cache
, sig
,
3387 mb
, sig
, sig
->param_count
+ 16);
3396 MonoMethodSignature
*sig
;
3398 } SignaturePointerPair
;
3401 signature_pointer_pair_hash (gconstpointer data
)
3403 SignaturePointerPair
*pair
= (SignaturePointerPair
*)data
;
3405 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->pointer
);
3409 signature_pointer_pair_equal (gconstpointer data1
, gconstpointer data2
)
3411 SignaturePointerPair
*pair1
= (SignaturePointerPair
*) data1
, *pair2
= (SignaturePointerPair
*) data2
;
3412 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->pointer
== pair2
->pointer
);
3416 signature_pointer_pair_matches_pointer (gpointer key
, gpointer value
, gpointer user_data
)
3418 SignaturePointerPair
*pair
= (SignaturePointerPair
*)key
;
3420 return pair
->pointer
== user_data
;
3424 free_signature_pointer_pair (SignaturePointerPair
*pair
)
3430 mono_marshal_get_delegate_invoke_internal (MonoMethod
*method
, gboolean callvirt
, gboolean static_method_with_first_arg_bound
, MonoMethod
*target_method
)
3432 MonoMethodSignature
*sig
, *static_sig
, *invoke_sig
;
3434 MonoMethodBuilder
*mb
;
3437 gpointer cache_key
= NULL
;
3438 SignaturePointerPair key
= { NULL
, NULL
};
3439 SignaturePointerPair
*new_key
;
3440 int local_i
, local_len
, local_delegates
, local_d
, local_target
, local_res
;
3441 int pos0
, pos1
, pos2
;
3443 MonoClass
*target_class
= NULL
;
3444 gboolean closed_over_null
= FALSE
;
3445 MonoGenericContext
*ctx
= NULL
;
3446 MonoGenericContainer
*container
= NULL
;
3447 MonoMethod
*orig_method
= method
;
3449 WrapperSubtype subtype
= WRAPPER_SUBTYPE_NONE
;
3453 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3454 !strcmp (method
->name
, "Invoke"));
3456 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
3459 * If the delegate target is null, and the target method is not static, a virtual
3460 * call is made to that method with the first delegate argument as this. This is
3461 * a non-documented .NET feature.
3464 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL
;
3465 if (target_method
->is_inflated
) {
3467 MonoType
*target_type
;
3469 g_assert (method
->signature
->hasthis
);
3470 target_type
= mono_class_inflate_generic_type_checked (method
->signature
->params
[0],
3471 mono_method_get_context (method
), &error
);
3472 mono_error_assert_ok (&error
); /* FIXME don't swallow the error */
3473 target_class
= mono_class_from_mono_type (target_type
);
3475 target_class
= target_method
->klass
;
3478 closed_over_null
= sig
->param_count
== mono_method_signature (target_method
)->param_count
;
3481 if (static_method_with_first_arg_bound
) {
3482 subtype
= WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
;
3483 g_assert (!callvirt
);
3484 invoke_sig
= mono_method_signature (target_method
);
3488 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
3490 if (method
->is_inflated
&& subtype
== WRAPPER_SUBTYPE_NONE
) {
3491 ctx
= &((MonoMethodInflated
*)method
)->context
;
3492 method
= ((MonoMethodInflated
*)method
)->declaring
;
3494 container
= mono_method_get_generic_container (method
);
3496 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
3497 g_assert (container
);
3499 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
3506 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.delegate_invoke_cache
, mono_aligned_addr_hash
, NULL
);
3507 res
= check_generic_delegate_wrapper_cache (cache
, orig_method
, method
, ctx
);
3510 cache_key
= method
->klass
;
3511 } else if (static_method_with_first_arg_bound
) {
3512 cache
= get_cache (&method
->klass
->image
->delegate_bound_static_invoke_cache
,
3513 (GHashFunc
)mono_signature_hash
,
3514 (GCompareFunc
)mono_metadata_signature_equal
);
3516 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
3518 res
= mono_marshal_find_in_cache (cache
, invoke_sig
);
3521 cache_key
= invoke_sig
;
3522 } else if (callvirt
) {
3523 GHashTable
**cache_ptr
;
3525 cache_ptr
= &mono_method_get_wrapper_cache (method
)->delegate_abstract_invoke_cache
;
3527 /* We need to cache the signature+method pair */
3528 mono_marshal_lock ();
3530 *cache_ptr
= g_hash_table_new_full (signature_pointer_pair_hash
, (GEqualFunc
)signature_pointer_pair_equal
, (GDestroyNotify
)free_signature_pointer_pair
, NULL
);
3532 key
.sig
= invoke_sig
;
3533 key
.pointer
= target_method
;
3534 res
= (MonoMethod
*)g_hash_table_lookup (cache
, &key
);
3535 mono_marshal_unlock ();
3539 // Inflated methods should not be in this cache because it's not stored on the imageset.
3540 g_assert (!method
->is_inflated
);
3541 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.delegate_invoke_cache
,
3542 (GHashFunc
)mono_signature_hash
,
3543 (GCompareFunc
)mono_metadata_signature_equal
);
3544 res
= mono_marshal_find_in_cache (cache
, sig
);
3550 static_sig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
3551 static_sig
->hasthis
= 0;
3552 if (!static_method_with_first_arg_bound
)
3553 invoke_sig
= static_sig
;
3555 if (static_method_with_first_arg_bound
)
3556 name
= mono_signature_to_name (invoke_sig
, "invoke_bound");
3557 else if (closed_over_null
)
3558 name
= mono_signature_to_name (invoke_sig
, "invoke_closed_over_null");
3560 name
= mono_signature_to_name (invoke_sig
, "invoke_callvirt");
3562 name
= mono_signature_to_name (invoke_sig
, "invoke");
3564 mb
= mono_mb_new (method
->klass
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
3566 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
3570 void_ret
= sig
->ret
->type
== MONO_TYPE_VOID
&& !method
->string_ctor
;
3572 /* allocate local 0 (object) */
3573 local_i
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
3574 local_len
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
3575 local_delegates
= mono_mb_add_local (mb
, &mono_defaults
.array_class
->byval_arg
);
3576 local_d
= mono_mb_add_local (mb
, &mono_defaults
.multicastdelegate_class
->byval_arg
);
3577 local_target
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3580 local_res
= mono_mb_add_local (mb
, &mono_class_from_mono_type (sig
->ret
)->byval_arg
);
3582 g_assert (sig
->hasthis
);
3585 * {type: sig->ret} res;
3586 * if (delegates == null) {
3587 * return this.<target> ( args .. );
3589 * int i = 0, len = this.delegates.Length;
3591 * res = this.delegates [i].Invoke ( args .. );
3592 * } while (++i < len);
3597 /* this wrapper can be used in unmanaged-managed transitions */
3598 emit_thread_interrupt_checkpoint (mb
);
3600 /* delegates = this.delegates */
3601 mono_mb_emit_ldarg (mb
, 0);
3602 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoMulticastDelegate
, delegates
));
3603 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3604 mono_mb_emit_stloc (mb
, local_delegates
);
3606 /* if (delegates == null) */
3607 mono_mb_emit_ldloc (mb
, local_delegates
);
3608 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3610 /* return target.<target_method|method_ptr> ( args .. ); */
3612 /* target = d.target; */
3613 mono_mb_emit_ldarg (mb
, 0);
3614 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
3615 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3616 mono_mb_emit_stloc (mb
, local_target
);
3618 /*static methods with bound first arg can have null target and still be bound*/
3619 if (!static_method_with_first_arg_bound
) {
3620 /* if target != null */
3621 mono_mb_emit_ldloc (mb
, local_target
);
3622 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3624 /* then call this->method_ptr nonstatic */
3627 mono_mb_emit_exception_full (mb
, "System", "NotImplementedException", "");
3629 mono_mb_emit_ldloc (mb
, local_target
);
3630 for (i
= 0; i
< sig
->param_count
; ++i
)
3631 mono_mb_emit_ldarg (mb
, i
+ 1);
3632 mono_mb_emit_ldarg (mb
, 0);
3633 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3634 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3635 mono_mb_emit_ldarg (mb
, 0);
3636 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
3637 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3638 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3639 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, sig
);
3640 mono_mb_emit_byte (mb
, CEE_RET
);
3643 /* else [target == null] call this->method_ptr static */
3644 mono_mb_patch_branch (mb
, pos0
);
3648 if (!closed_over_null
) {
3649 if (target_class
->valuetype
) {
3650 mono_mb_emit_ldarg (mb
, 1);
3651 for (i
= 1; i
< sig
->param_count
; ++i
)
3652 mono_mb_emit_ldarg (mb
, i
+ 1);
3653 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3655 mono_mb_emit_ldarg (mb
, 1);
3656 mono_mb_emit_op (mb
, CEE_CASTCLASS
, target_class
);
3657 for (i
= 1; i
< sig
->param_count
; ++i
)
3658 mono_mb_emit_ldarg (mb
, i
+ 1);
3659 mono_mb_emit_op (mb
, CEE_CALLVIRT
, target_method
);
3662 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3663 for (i
= 0; i
< sig
->param_count
; ++i
)
3664 mono_mb_emit_ldarg (mb
, i
+ 1);
3665 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3668 if (static_method_with_first_arg_bound
) {
3669 mono_mb_emit_ldloc (mb
, local_target
);
3670 if (!MONO_TYPE_IS_REFERENCE (invoke_sig
->params
[0]))
3671 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type (invoke_sig
->params
[0]));
3673 for (i
= 0; i
< sig
->param_count
; ++i
)
3674 mono_mb_emit_ldarg (mb
, i
+ 1);
3675 mono_mb_emit_ldarg (mb
, 0);
3676 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3677 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3678 mono_mb_emit_ldarg (mb
, 0);
3679 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
3680 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3681 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3682 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, invoke_sig
);
3685 mono_mb_emit_byte (mb
, CEE_RET
);
3687 /* else [delegates != null] */
3688 mono_mb_patch_branch (mb
, pos2
);
3690 /* len = delegates.Length; */
3691 mono_mb_emit_ldloc (mb
, local_delegates
);
3692 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3693 mono_mb_emit_byte (mb
, CEE_CONV_I4
);
3694 mono_mb_emit_stloc (mb
, local_len
);
3697 mono_mb_emit_icon (mb
, 0);
3698 mono_mb_emit_stloc (mb
, local_i
);
3700 pos1
= mono_mb_get_label (mb
);
3702 /* d = delegates [i]; */
3703 mono_mb_emit_ldloc (mb
, local_delegates
);
3704 mono_mb_emit_ldloc (mb
, local_i
);
3705 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3706 mono_mb_emit_stloc (mb
, local_d
);
3708 /* res = d.Invoke ( args .. ); */
3709 mono_mb_emit_ldloc (mb
, local_d
);
3710 for (i
= 0; i
< sig
->param_count
; i
++)
3711 mono_mb_emit_ldarg (mb
, i
+ 1);
3713 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
3716 mono_mb_emit_op (mb
, CEE_CALLVIRT
, mono_class_inflate_generic_method_checked (method
, &container
->context
, &error
));
3717 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
3720 mono_mb_emit_stloc (mb
, local_res
);
3723 mono_mb_emit_add_to_local (mb
, local_i
, 1);
3726 mono_mb_emit_ldloc (mb
, local_i
);
3727 mono_mb_emit_ldloc (mb
, local_len
);
3728 mono_mb_emit_branch_label (mb
, CEE_BLT
, pos1
);
3732 mono_mb_emit_ldloc (mb
, local_res
);
3733 mono_mb_emit_byte (mb
, CEE_RET
);
3735 mb
->skip_visibility
= 1;
3736 #endif /* DISABLE_JIT */
3738 info
= mono_wrapper_info_create (mb
, subtype
);
3739 info
->d
.delegate_invoke
.method
= method
;
3744 def
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
3745 res
= cache_generic_delegate_wrapper (cache
, orig_method
, def
, ctx
);
3746 } else if (callvirt
) {
3747 new_key
= g_new0 (SignaturePointerPair
, 1);
3750 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, sig
, sig
->param_count
+ 16, info
, &found
);
3754 res
= mono_mb_create_and_cache_full (cache
, cache_key
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
3758 /* mono_method_print_code (res); */
3764 * the returned method invokes all methods in a multicast delegate.
3767 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
3769 gboolean callvirt
= FALSE
;
3770 gboolean static_method_with_first_arg_bound
= FALSE
;
3771 MonoMethod
*target_method
= NULL
;
3772 MonoMethodSignature
*sig
;
3774 sig
= mono_signature_no_pinvoke (method
);
3776 if (del
&& !del
->target
&& del
->method
&& mono_method_signature (del
->method
)->hasthis
) {
3778 target_method
= del
->method
;
3781 if (del
&& del
->method
&& mono_method_signature (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
3782 static_method_with_first_arg_bound
= TRUE
;
3783 target_method
= del
->method
;
3786 return mono_marshal_get_delegate_invoke_internal (method
, callvirt
, static_method_with_first_arg_bound
, target_method
);
3790 MonoMethodSignature
*ctor_sig
;
3791 MonoMethodSignature
*sig
;
3794 /* protected by the marshal lock, contains CtorSigPair pointers */
3795 static GSList
*strsig_list
= NULL
;
3797 static MonoMethodSignature
*
3798 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
3800 MonoMethodSignature
*callsig
;
3804 mono_marshal_lock ();
3806 for (item
= strsig_list
; item
; item
= item
->next
) {
3807 cs
= (CtorSigPair
*)item
->data
;
3808 /* mono_metadata_signature_equal () is safe to call with the marshal lock
3809 * because it is lock-free.
3811 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
3816 mono_marshal_unlock ();
3820 static MonoMethodSignature
*
3821 add_string_ctor_signature (MonoMethod
*method
)
3823 MonoMethodSignature
*callsig
;
3826 callsig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
3827 callsig
->ret
= &mono_defaults
.string_class
->byval_arg
;
3828 cs
= g_new (CtorSigPair
, 1);
3830 cs
->ctor_sig
= mono_method_signature (method
);
3832 mono_marshal_lock ();
3833 strsig_list
= g_slist_prepend (strsig_list
, cs
);
3834 mono_marshal_unlock ();
3839 * mono_marshal_get_string_ctor_signature:
3841 * Return the modified signature used by string ctors (they return the newly created
3844 MonoMethodSignature
*
3845 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
3847 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature (method
));
3849 sig
= add_string_ctor_signature (method
);
3855 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
3858 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
)))
3860 /* Can't share this with 'I' as that needs another indirection */
3861 return &mono_defaults
.int_class
->this_arg
;
3864 if (MONO_TYPE_IS_REFERENCE (t
))
3865 return &mono_defaults
.object_class
->byval_arg
;
3868 /* The result needs to be boxed */
3873 /* Can't share these as the argument needs to be loaded using sign/zero extension */
3876 return &mono_defaults.sbyte_class->byval_arg;
3878 return &mono_defaults.int16_class->byval_arg;
3880 return &mono_defaults.int32_class->byval_arg;
3883 return &mono_defaults
.int64_class
->byval_arg
;
3884 case MONO_TYPE_BOOLEAN
:
3885 return &mono_defaults
.byte_class
->byval_arg
;
3886 case MONO_TYPE_CHAR
:
3887 return &mono_defaults
.uint16_class
->byval_arg
;
3889 return &mono_defaults
.int_class
->byval_arg
;
3890 case MONO_TYPE_VALUETYPE
:
3891 if (t
->data
.klass
->enumtype
) {
3892 t
= mono_class_enum_basetype (t
->data
.klass
);
3902 * mono_marshal_get_runtime_invoke_sig:
3904 * Return a common signature used for sharing runtime invoke wrappers.
3906 static MonoMethodSignature
*
3907 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
3909 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
3912 res
->generic_param_count
= 0;
3913 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
3914 for (i
= 0; i
< res
->param_count
; ++i
)
3915 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
3921 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
3923 /* Can't share wrappers which return a vtype since it needs to be boxed */
3924 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
))
3927 return mono_metadata_signature_equal (sig1
, sig2
);
3935 * Emit the call to the wrapper method from a runtime invoke wrapper.
3938 emit_invoke_call (MonoMethodBuilder
*mb
, MonoMethod
*method
,
3939 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
3941 gboolean virtual_
, gboolean need_direct_wrapper
)
3943 static MonoString
*string_dummy
= NULL
;
3945 int *tmp_nullable_locals
;
3946 gboolean void_ret
= FALSE
;
3947 gboolean string_ctor
= method
&& method
->string_ctor
;
3949 /* to make it work with our special string constructors */
3950 if (!string_dummy
) {
3951 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy
, MONO_ROOT_SOURCE_MARSHAL
, "dummy marshal string");
3952 string_dummy
= mono_string_new_wrapper ("dummy");
3956 g_assert (sig
->hasthis
);
3957 g_assert (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
);
3962 if (mono_gc_is_moving ()) {
3963 mono_mb_emit_ptr (mb
, &string_dummy
);
3964 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3966 mono_mb_emit_ptr (mb
, string_dummy
);
3969 mono_mb_emit_ldarg (mb
, 0);
3973 tmp_nullable_locals
= g_new0 (int, sig
->param_count
);
3975 for (i
= 0; i
< sig
->param_count
; i
++) {
3976 MonoType
*t
= sig
->params
[i
];
3979 mono_mb_emit_ldarg (mb
, 1);
3981 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
3982 mono_mb_emit_byte (mb
, CEE_ADD
);
3986 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3987 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
3988 * So to make this work we unbox it to a local variablee and push a reference to that.
3990 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
3991 tmp_nullable_locals
[i
] = mono_mb_add_local (mb
, &mono_class_from_mono_type (t
)->byval_arg
);
3993 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type (t
));
3994 mono_mb_emit_stloc (mb
, tmp_nullable_locals
[i
]);
3995 mono_mb_emit_ldloc_addr (mb
, tmp_nullable_locals
[i
]);
4000 /*FIXME 'this doesn't handle generic enums. Shouldn't we?*/
4001 type
= sig
->params
[i
]->type
;
4005 case MONO_TYPE_BOOLEAN
:
4009 case MONO_TYPE_CHAR
:
4018 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4019 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4021 case MONO_TYPE_STRING
:
4022 case MONO_TYPE_CLASS
:
4023 case MONO_TYPE_ARRAY
:
4025 case MONO_TYPE_SZARRAY
:
4026 case MONO_TYPE_OBJECT
:
4027 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4029 case MONO_TYPE_GENERICINST
:
4030 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
4031 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4036 case MONO_TYPE_VALUETYPE
:
4037 if (type
== MONO_TYPE_VALUETYPE
&& t
->data
.klass
->enumtype
) {
4038 type
= mono_class_enum_basetype (t
->data
.klass
)->type
;
4041 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4042 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->params
[i
]))) {
4043 /* Need to convert a boxed vtype to an mp to a Nullable struct */
4044 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (sig
->params
[i
]));
4045 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
4047 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
4051 g_assert_not_reached ();
4056 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4057 } else if (need_direct_wrapper
) {
4058 mono_mb_emit_op (mb
, CEE_CALL
, method
);
4060 mono_mb_emit_ldarg (mb
, 3);
4061 mono_mb_emit_calli (mb
, callsig
);
4064 if (sig
->ret
->byref
) {
4066 g_assert_not_reached ();
4069 switch (sig
->ret
->type
) {
4070 case MONO_TYPE_VOID
:
4074 case MONO_TYPE_BOOLEAN
:
4075 case MONO_TYPE_CHAR
:
4088 case MONO_TYPE_VALUETYPE
:
4089 case MONO_TYPE_TYPEDBYREF
:
4090 case MONO_TYPE_GENERICINST
:
4091 /* box value types */
4092 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
4094 case MONO_TYPE_STRING
:
4095 case MONO_TYPE_CLASS
:
4096 case MONO_TYPE_ARRAY
:
4097 case MONO_TYPE_SZARRAY
:
4098 case MONO_TYPE_OBJECT
:
4102 /* The result is an IntPtr */
4103 mono_mb_emit_op (mb
, CEE_BOX
, mono_defaults
.int_class
);
4106 g_assert_not_reached ();
4110 mono_mb_emit_stloc (mb
, loc_res
);
4112 /* Convert back nullable-byref arguments */
4113 for (i
= 0; i
< sig
->param_count
; i
++) {
4114 MonoType
*t
= sig
->params
[i
];
4117 * Box the result and put it back into the array, the caller will have
4118 * to obtain it from there.
4120 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
4121 mono_mb_emit_ldarg (mb
, 1);
4122 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
4123 mono_mb_emit_byte (mb
, CEE_ADD
);
4125 mono_mb_emit_ldloc (mb
, tmp_nullable_locals
[i
]);
4126 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
4128 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4132 g_free (tmp_nullable_locals
);
4136 emit_runtime_invoke_body (MonoMethodBuilder
*mb
, MonoImage
*image
, MonoMethod
*method
,
4137 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
4138 gboolean virtual_
, gboolean need_direct_wrapper
)
4141 MonoExceptionClause
*clause
;
4142 int loc_res
, loc_exc
;
4144 /* The wrapper looks like this:
4150 * } catch (Exception e) {
4158 /* allocate local 0 (object) tmp */
4159 loc_res
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4160 /* allocate local 1 (object) exc */
4161 loc_exc
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4163 /* *exc is assumed to be initialized to NULL by the caller */
4165 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4166 labels
[0] = mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4171 labels
[1] = mono_mb_get_label (mb
);
4172 emit_thread_force_interrupt_checkpoint (mb
);
4173 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
4175 labels
[2] = mono_mb_emit_branch (mb
, CEE_LEAVE
);
4177 /* Add a try clause around the call */
4178 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
4179 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4180 clause
->data
.catch_class
= mono_defaults
.exception_class
;
4181 clause
->try_offset
= labels
[1];
4182 clause
->try_len
= mono_mb_get_label (mb
) - labels
[1];
4184 clause
->handler_offset
= mono_mb_get_label (mb
);
4187 mono_mb_emit_stloc (mb
, loc_exc
);
4188 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4189 mono_mb_emit_ldloc (mb
, loc_exc
);
4190 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4192 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4194 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4196 mono_mb_set_clauses (mb
, 1, clause
);
4198 mono_mb_patch_branch (mb
, labels
[2]);
4199 mono_mb_emit_ldloc (mb
, loc_res
);
4200 mono_mb_emit_byte (mb
, CEE_RET
);
4205 mono_mb_patch_branch (mb
, labels
[0]);
4206 emit_thread_force_interrupt_checkpoint (mb
);
4207 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
4209 mono_mb_emit_ldloc (mb
, 0);
4210 mono_mb_emit_byte (mb
, CEE_RET
);
4215 * generates IL code for the runtime invoke function
4216 * MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)
4218 * we also catch exceptions if exc != null
4219 * If VIRTUAL is TRUE, then METHOD is invoked virtually on THIS. This is useful since
4220 * it means that the compiled code for METHOD does not have to be looked up
4221 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
4222 * its METHOD argument.
4225 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean virtual_
)
4227 MonoMethodSignature
*sig
, *csig
, *callsig
;
4228 MonoMethodBuilder
*mb
;
4229 GHashTable
*cache
= NULL
;
4230 MonoClass
*target_klass
;
4231 MonoMethod
*res
= NULL
;
4232 static MonoMethodSignature
*cctor_signature
= NULL
;
4233 static MonoMethodSignature
*finalize_signature
= NULL
;
4235 const char *param_names
[16];
4236 gboolean need_direct_wrapper
= FALSE
;
4241 if (!cctor_signature
) {
4242 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4243 cctor_signature
->ret
= &mono_defaults
.void_class
->byval_arg
;
4245 if (!finalize_signature
) {
4246 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4247 finalize_signature
->ret
= &mono_defaults
.void_class
->byval_arg
;
4248 finalize_signature
->hasthis
= 1;
4252 need_direct_wrapper
= TRUE
;
4255 * Use a separate cache indexed by methods to speed things up and to avoid the
4256 * boundless mempool growth caused by the signature_dup stuff below.
4259 cache
= get_cache (&method
->klass
->image
->runtime_invoke_vcall_cache
, mono_aligned_addr_hash
, NULL
);
4261 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->runtime_invoke_direct_cache
, mono_aligned_addr_hash
, NULL
);
4263 res
= mono_marshal_find_in_cache (cache
, method
);
4267 if (method
->klass
->rank
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
4268 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
4270 * Array Get/Set/Address methods. The JIT implements them using inline code
4271 * so we need to create an invoke wrapper which calls the method directly.
4273 need_direct_wrapper
= TRUE
;
4276 if (method
->string_ctor
) {
4277 callsig
= lookup_string_ctor_signature (mono_method_signature (method
));
4279 callsig
= add_string_ctor_signature (method
);
4280 /* Can't share this as we push a string as this */
4281 need_direct_wrapper
= TRUE
;
4283 if (method_is_dynamic (method
))
4284 callsig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
4286 callsig
= mono_method_signature (method
);
4289 sig
= mono_method_signature (method
);
4291 target_klass
= get_wrapper_target_class (method
->klass
->image
);
4293 /* Try to share wrappers for non-corlib methods with simple signatures */
4294 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
4295 callsig
= cctor_signature
;
4296 target_klass
= mono_defaults
.object_class
;
4297 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
4298 callsig
= finalize_signature
;
4299 target_klass
= mono_defaults
.object_class
;
4302 if (need_direct_wrapper
) {
4303 /* Already searched at the start */
4305 MonoMethodSignature
*tmp_sig
;
4307 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
4308 GHashTable
**cache_table
= NULL
;
4310 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
)
4311 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_vtype_cache
;
4313 cache_table
= &mono_method_get_wrapper_cache (method
)->runtime_invoke_cache
;
4315 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
4316 (GCompareFunc
)runtime_invoke_signature_equal
);
4318 /* from mono_marshal_find_in_cache */
4319 mono_marshal_lock ();
4320 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4321 mono_marshal_unlock ();
4328 /* Make a copy of the signature from the image mempool */
4330 callsig
= mono_metadata_signature_dup_full (target_klass
->image
, callsig
);
4334 csig
= mono_metadata_signature_alloc (target_klass
->image
, 4);
4336 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4337 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
)
4338 csig
->params
[0] = get_runtime_invoke_type (&method
->klass
->this_arg
, FALSE
);
4340 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4341 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4342 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4343 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4346 /* This is called from runtime code so it has to be cdecl */
4347 csig
->call_convention
= MONO_CALL_C
;
4350 name
= mono_signature_to_name (callsig
, virtual_
? "runtime_invoke_virtual" : "runtime_invoke");
4351 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4355 param_names
[0] = "this";
4356 param_names
[1] = "params";
4357 param_names
[2] = "exc";
4358 param_names
[3] = "method";
4359 mono_mb_set_param_names (mb
, param_names
);
4361 emit_runtime_invoke_body (mb
, target_klass
->image
, method
, sig
, callsig
, virtual_
, need_direct_wrapper
);
4364 if (need_direct_wrapper
) {
4366 mb
->skip_visibility
= 1;
4368 info
= mono_wrapper_info_create (mb
, virtual_
? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL
: WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT
);
4369 info
->d
.runtime_invoke
.method
= method
;
4370 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, sig
->param_count
+ 16, info
, NULL
);
4372 /* taken from mono_mb_create_and_cache */
4373 mono_marshal_lock ();
4374 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4375 mono_marshal_unlock ();
4377 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
4378 info
->d
.runtime_invoke
.sig
= callsig
;
4380 /* Somebody may have created it before us */
4383 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
4385 mono_marshal_lock ();
4386 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4388 GHashTable
*direct_cache
;
4390 g_hash_table_insert (cache
, callsig
, res
);
4391 /* Can't insert it into wrapper_hash since the key is a signature */
4392 direct_cache
= mono_method_get_wrapper_cache (method
)->runtime_invoke_direct_cache
;
4394 g_hash_table_insert (direct_cache
, method
, res
);
4396 mono_free_method (newm
);
4398 mono_marshal_unlock ();
4401 /* end mono_mb_create_and_cache */
4410 * mono_marshal_get_runtime_invoke_dynamic:
4412 * Return a method which can be used to invoke managed methods from native code
4414 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
4415 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
4416 * ARGS should point to an architecture specific structure containing
4417 * the arguments and space for the return value.
4418 * The other arguments are the same as for runtime_invoke (), except that
4419 * ARGS should contain the this argument too.
4420 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
4421 * is only one copy of it, which is useful in full-aot.
4424 mono_marshal_get_runtime_invoke_dynamic (void)
4426 static MonoMethod
*method
;
4427 MonoMethodSignature
*csig
;
4428 MonoExceptionClause
*clause
;
4429 MonoMethodBuilder
*mb
;
4437 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
4439 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
4440 csig
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
4441 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4442 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4443 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4445 name
= g_strdup ("runtime_invoke_dynamic");
4446 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4450 /* allocate local 0 (object) tmp */
4451 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4452 /* allocate local 1 (object) exc */
4453 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4455 /* cond set *exc to null */
4456 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4457 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
4458 mono_mb_emit_byte (mb
, 3);
4459 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4460 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4461 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4463 emit_thread_force_interrupt_checkpoint (mb
);
4465 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
4466 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4467 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4468 mono_mb_emit_byte (mb
, CEE_MONO_DYN_CALL
);
4470 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4472 clause
= (MonoExceptionClause
*)mono_image_alloc0 (mono_defaults
.corlib
, sizeof (MonoExceptionClause
));
4473 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
4474 clause
->try_len
= mono_mb_get_label (mb
);
4477 clause
->data
.filter_offset
= mono_mb_get_label (mb
);
4479 mono_mb_emit_byte (mb
, CEE_POP
);
4480 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4481 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
4482 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4483 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
4484 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4485 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
4487 clause
->handler_offset
= mono_mb_get_label (mb
);
4490 /* store exception */
4491 mono_mb_emit_stloc (mb
, 1);
4493 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4494 mono_mb_emit_ldloc (mb
, 1);
4495 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4497 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4498 mono_mb_emit_stloc (mb
, 0);
4500 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4502 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4504 mono_mb_set_clauses (mb
, 1, clause
);
4507 mono_mb_patch_branch (mb
, pos
);
4508 //mono_mb_emit_ldloc (mb, 0);
4509 mono_mb_emit_byte (mb
, CEE_RET
);
4510 #endif /* DISABLE_JIT */
4512 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC
);
4514 mono_marshal_lock ();
4515 /* double-checked locking */
4517 method
= mono_mb_create (mb
, csig
, 16, info
);
4519 mono_marshal_unlock ();
4527 * mono_marshal_get_runtime_invoke_for_sig:
4529 * Return a runtime invoke wrapper for a given signature.
4532 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature
*sig
)
4534 MonoMethodSignature
*csig
, *callsig
;
4535 MonoMethodBuilder
*mb
;
4537 GHashTable
*cache
= NULL
;
4538 GHashTable
**cache_table
= NULL
;
4539 MonoMethod
*res
= NULL
;
4541 const char *param_names
[16];
4544 /* A simplified version of mono_marshal_get_runtime_invoke */
4546 image
= mono_defaults
.corlib
;
4548 callsig
= mono_marshal_get_runtime_invoke_sig (sig
);
4550 cache_table
= &image
->wrapper_caches
.runtime_invoke_sig_cache
;
4552 cache
= get_cache (cache_table
, (GHashFunc
)mono_signature_hash
,
4553 (GCompareFunc
)runtime_invoke_signature_equal
);
4555 /* from mono_marshal_find_in_cache */
4556 mono_marshal_lock ();
4557 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4558 mono_marshal_unlock ();
4565 /* Make a copy of the signature from the image mempool */
4566 callsig
= mono_metadata_signature_dup_full (image
, callsig
);
4568 csig
= mono_metadata_signature_alloc (image
, 4);
4569 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4570 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4571 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4572 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4573 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4576 /* This is called from runtime code so it has to be cdecl */
4577 csig
->call_convention
= MONO_CALL_C
;
4580 name
= mono_signature_to_name (callsig
, "runtime_invoke_sig");
4581 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4585 param_names
[0] = "this";
4586 param_names
[1] = "params";
4587 param_names
[2] = "exc";
4588 param_names
[3] = "method";
4589 mono_mb_set_param_names (mb
, param_names
);
4591 emit_runtime_invoke_body (mb
, image
, NULL
, sig
, callsig
, FALSE
, FALSE
);
4594 /* taken from mono_mb_create_and_cache */
4595 mono_marshal_lock ();
4596 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4597 mono_marshal_unlock ();
4599 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL
);
4600 info
->d
.runtime_invoke
.sig
= callsig
;
4602 /* Somebody may have created it before us */
4605 newm
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, info
);
4607 mono_marshal_lock ();
4608 res
= (MonoMethod
*)g_hash_table_lookup (cache
, callsig
);
4611 g_hash_table_insert (cache
, callsig
, res
);
4613 mono_free_method (newm
);
4615 mono_marshal_unlock ();
4618 /* end mono_mb_create_and_cache */
4627 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4629 char *msg
= g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
4630 klass
->name_space
, klass
->name
);
4632 mono_mb_emit_exception_marshal_directive (mb
, msg
);
4637 * generates IL code for the icall wrapper (the generated method
4638 * calls the unmanaged code in func)
4641 mono_marshal_get_icall_wrapper (MonoMethodSignature
*sig
, const char *name
, gconstpointer func
, gboolean check_exceptions
)
4643 MonoMethodSignature
*csig
, *csig2
;
4644 MonoMethodBuilder
*mb
;
4649 GHashTable
*cache
= get_cache (&mono_defaults
.object_class
->image
->icall_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4650 if ((res
= mono_marshal_find_in_cache (cache
, (gpointer
) func
)))
4653 g_assert (sig
->pinvoke
);
4655 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
4657 mb
->method
->save_lmf
= 1;
4659 /* Add an explicit this argument */
4661 csig2
= mono_metadata_signature_dup_add_this (mono_defaults
.corlib
, sig
, mono_defaults
.object_class
);
4663 csig2
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4667 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
4669 for (i
= 0; i
< sig
->param_count
; i
++)
4670 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
4672 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4673 mono_mb_emit_op (mb
, CEE_MONO_JIT_ICALL_ADDR
, (gpointer
)func
);
4674 mono_mb_emit_calli (mb
, csig2
);
4675 if (check_exceptions
)
4676 emit_thread_interrupt_checkpoint (mb
);
4677 mono_mb_emit_byte (mb
, CEE_RET
);
4680 csig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
4682 if (csig
->call_convention
== MONO_CALL_VARARG
)
4683 csig
->call_convention
= 0;
4685 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ICALL_WRAPPER
);
4686 info
->d
.icall
.func
= (gpointer
)func
;
4687 res
= mono_mb_create_and_cache_full (cache
, (gpointer
) func
, mb
, csig
, csig
->param_count
+ 16, info
, NULL
);
4694 emit_marshal_custom (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4695 MonoMarshalSpec
*spec
,
4696 int conv_arg
, MonoType
**conv_arg_type
,
4697 MarshalAction action
)
4700 if (action
== MARSHAL_ACTION_CONV_IN
&& t
->type
== MONO_TYPE_VALUETYPE
)
4701 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
4707 static MonoClass
*ICustomMarshaler
= NULL
;
4708 static MonoMethod
*cleanup_native
, *cleanup_managed
;
4709 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
4710 MonoMethod
*get_instance
= NULL
;
4711 MonoMethodBuilder
*mb
= m
->mb
;
4712 char *exception_msg
= NULL
;
4716 if (!ICustomMarshaler
) {
4717 MonoClass
*klass
= mono_class_try_get_icustom_marshaler_class ();
4719 exception_msg
= g_strdup ("Current profile doesn't support ICustomMarshaler");
4720 goto handle_exception
;
4723 cleanup_native
= mono_class_get_method_from_name (klass
, "CleanUpNativeData", 1);
4724 g_assert (cleanup_native
);
4725 cleanup_managed
= mono_class_get_method_from_name (klass
, "CleanUpManagedData", 1);
4726 g_assert (cleanup_managed
);
4727 marshal_managed_to_native
= mono_class_get_method_from_name (klass
, "MarshalManagedToNative", 1);
4728 g_assert (marshal_managed_to_native
);
4729 marshal_native_to_managed
= mono_class_get_method_from_name (klass
, "MarshalNativeToManaged", 1);
4730 g_assert (marshal_native_to_managed
);
4732 mono_memory_barrier ();
4733 ICustomMarshaler
= klass
;
4736 if (spec
->data
.custom_data
.image
)
4737 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, spec
->data
.custom_data
.image
, &error
);
4739 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, m
->image
, &error
);
4740 g_assert (mtype
!= NULL
);
4741 mono_error_assert_ok (&error
);
4742 mklass
= mono_class_from_mono_type (mtype
);
4743 g_assert (mklass
!= NULL
);
4745 if (!mono_class_is_assignable_from (ICustomMarshaler
, mklass
))
4746 exception_msg
= g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass
->name
);
4748 get_instance
= mono_class_get_method_from_name_flags (mklass
, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC
);
4750 MonoMethodSignature
*get_sig
= mono_method_signature (get_instance
);
4751 if ((get_sig
->ret
->type
!= MONO_TYPE_CLASS
) ||
4752 (mono_class_from_mono_type (get_sig
->ret
) != ICustomMarshaler
) ||
4753 (get_sig
->params
[0]->type
!= MONO_TYPE_STRING
))
4754 get_instance
= NULL
;
4758 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
);
4761 /* Throw exception and emit compensation code if neccesary */
4762 if (exception_msg
) {
4764 case MARSHAL_ACTION_CONV_IN
:
4765 case MARSHAL_ACTION_CONV_RESULT
:
4766 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4767 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
4768 mono_mb_emit_byte (mb
, CEE_POP
);
4770 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
4771 g_free (exception_msg
);
4774 case MARSHAL_ACTION_PUSH
:
4775 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4783 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
4784 /* FIXME: MS.NET throws an exception if GetInstance returns null */
4787 case MARSHAL_ACTION_CONV_IN
:
4789 case MONO_TYPE_CLASS
:
4790 case MONO_TYPE_OBJECT
:
4791 case MONO_TYPE_STRING
:
4792 case MONO_TYPE_ARRAY
:
4793 case MONO_TYPE_SZARRAY
:
4794 case MONO_TYPE_VALUETYPE
:
4798 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
4799 g_assert_not_reached ();
4803 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
4805 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4806 mono_mb_emit_stloc (mb
, conv_arg
);
4808 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4811 /* Minic MS.NET behavior */
4812 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
4815 /* Check for null */
4816 mono_mb_emit_ldarg (mb
, argnum
);
4818 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4819 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4821 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4823 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4825 mono_mb_emit_ldarg (mb
, argnum
);
4827 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4829 if (t
->type
== MONO_TYPE_VALUETYPE
) {
4831 * Since we can't determine the type of the argument, we
4832 * will assume the unmanaged function takes a pointer.
4834 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
4836 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
4839 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4840 mono_mb_emit_stloc (mb
, conv_arg
);
4842 mono_mb_patch_branch (mb
, pos2
);
4845 case MARSHAL_ACTION_CONV_OUT
:
4846 /* Check for null */
4847 mono_mb_emit_ldloc (mb
, conv_arg
);
4848 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4851 mono_mb_emit_ldarg (mb
, argnum
);
4853 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4855 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4857 mono_mb_emit_ldloc (mb
, conv_arg
);
4858 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4859 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4860 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
4861 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4863 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4865 mono_mb_emit_ldloc (mb
, conv_arg
);
4866 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4868 /* We have nowhere to store the result */
4869 mono_mb_emit_byte (mb
, CEE_POP
);
4872 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4874 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4876 mono_mb_emit_ldloc (mb
, conv_arg
);
4878 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4880 mono_mb_patch_branch (mb
, pos2
);
4883 case MARSHAL_ACTION_PUSH
:
4885 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4887 mono_mb_emit_ldloc (mb
, conv_arg
);
4890 case MARSHAL_ACTION_CONV_RESULT
:
4891 loc1
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
4893 mono_mb_emit_stloc (mb
, 3);
4895 mono_mb_emit_ldloc (mb
, 3);
4896 mono_mb_emit_stloc (mb
, loc1
);
4898 /* Check for null */
4899 mono_mb_emit_ldloc (mb
, 3);
4900 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4902 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4904 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4905 mono_mb_emit_byte (mb
, CEE_DUP
);
4907 mono_mb_emit_ldloc (mb
, 3);
4908 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4909 mono_mb_emit_stloc (mb
, 3);
4911 mono_mb_emit_ldloc (mb
, loc1
);
4912 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4914 mono_mb_patch_branch (mb
, pos2
);
4917 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4918 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4920 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4921 mono_mb_emit_stloc (mb
, conv_arg
);
4923 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4926 /* Check for null */
4927 mono_mb_emit_ldarg (mb
, argnum
);
4929 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4930 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4932 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4933 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4935 mono_mb_emit_ldarg (mb
, argnum
);
4937 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4939 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4940 mono_mb_emit_stloc (mb
, conv_arg
);
4942 mono_mb_patch_branch (mb
, pos2
);
4945 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4946 g_assert (!t
->byref
);
4948 loc1
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4950 mono_mb_emit_stloc (mb
, 3);
4952 mono_mb_emit_ldloc (mb
, 3);
4953 mono_mb_emit_stloc (mb
, loc1
);
4955 /* Check for null */
4956 mono_mb_emit_ldloc (mb
, 3);
4957 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4959 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4960 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4961 mono_mb_emit_byte (mb
, CEE_DUP
);
4963 mono_mb_emit_ldloc (mb
, 3);
4964 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4965 mono_mb_emit_stloc (mb
, 3);
4967 mono_mb_emit_ldloc (mb
, loc1
);
4968 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4970 mono_mb_patch_branch (mb
, pos2
);
4973 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4975 /* Check for null */
4976 mono_mb_emit_ldloc (mb
, conv_arg
);
4977 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4980 mono_mb_emit_ldarg (mb
, argnum
);
4982 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4984 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4986 mono_mb_emit_ldloc (mb
, conv_arg
);
4987 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4988 mono_mb_emit_byte (mb
, CEE_STIND_I
);
4991 /* Call CleanUpManagedData */
4992 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4994 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4996 mono_mb_emit_ldloc (mb
, conv_arg
);
4997 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4999 mono_mb_patch_branch (mb
, pos2
);
5003 g_assert_not_reached ();
5011 emit_marshal_asany (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5012 MonoMarshalSpec
*spec
,
5013 int conv_arg
, MonoType
**conv_arg_type
,
5014 MarshalAction action
)
5017 MonoMethodBuilder
*mb
= m
->mb
;
5020 case MARSHAL_ACTION_CONV_IN
: {
5021 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
5023 g_assert (t
->type
== MONO_TYPE_OBJECT
);
5024 g_assert (!t
->byref
);
5026 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5027 mono_mb_emit_ldarg (mb
, argnum
);
5028 mono_mb_emit_icon (mb
, encoding
);
5029 mono_mb_emit_icon (mb
, t
->attrs
);
5030 mono_mb_emit_icall (mb
, mono_marshal_asany
);
5031 mono_mb_emit_stloc (mb
, conv_arg
);
5035 case MARSHAL_ACTION_PUSH
:
5036 mono_mb_emit_ldloc (mb
, conv_arg
);
5039 case MARSHAL_ACTION_CONV_OUT
: {
5040 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
5042 mono_mb_emit_ldarg (mb
, argnum
);
5043 mono_mb_emit_ldloc (mb
, conv_arg
);
5044 mono_mb_emit_icon (mb
, encoding
);
5045 mono_mb_emit_icon (mb
, t
->attrs
);
5046 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
5051 g_assert_not_reached ();
5058 emit_marshal_vtype (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5059 MonoMarshalSpec
*spec
,
5060 int conv_arg
, MonoType
**conv_arg_type
,
5061 MarshalAction action
)
5064 MonoMethodBuilder
*mb
= m
->mb
;
5065 MonoClass
*klass
, *date_time_class
;
5068 klass
= mono_class_from_mono_type (t
);
5070 date_time_class
= mono_class_get_date_time_class ();
5073 case MARSHAL_ACTION_CONV_IN
:
5074 if (klass
== date_time_class
) {
5075 /* Convert it to an OLE DATE type */
5076 static MonoMethod
*to_oadate
;
5079 to_oadate
= mono_class_get_method_from_name (date_time_class
, "ToOADate", 0);
5080 g_assert (to_oadate
);
5082 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.double_class
->byval_arg
);
5085 mono_mb_emit_ldarg (mb
, argnum
);
5086 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5089 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5091 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.double_class
->byval_arg
;
5093 mono_mb_emit_ldarg_addr (mb
, argnum
);
5094 mono_mb_emit_managed_call (mb
, to_oadate
, NULL
);
5095 mono_mb_emit_stloc (mb
, conv_arg
);
5099 mono_mb_patch_branch (mb
, pos
);
5103 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
)
5106 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5108 /* store the address of the source into local variable 0 */
5110 mono_mb_emit_ldarg (mb
, argnum
);
5112 mono_mb_emit_ldarg_addr (mb
, argnum
);
5114 mono_mb_emit_stloc (mb
, 0);
5116 /* allocate space for the native struct and
5117 * store the address into local variable 1 (dest) */
5118 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5119 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5120 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5121 mono_mb_emit_stloc (mb
, conv_arg
);
5124 mono_mb_emit_ldloc (mb
, 0);
5125 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5128 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5130 mono_mb_emit_ldloc (mb
, conv_arg
);
5131 mono_mb_emit_stloc (mb
, 1);
5133 /* emit valuetype conversion code */
5134 emit_struct_conv (mb
, klass
, FALSE
);
5138 mono_mb_patch_branch (mb
, pos
);
5141 case MARSHAL_ACTION_PUSH
:
5142 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
5144 g_assert (!t
->byref
);
5146 /* Have to change the signature since the vtype is passed byref */
5147 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.int_class
->byval_arg
;
5149 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
)
5150 mono_mb_emit_ldarg_addr (mb
, argnum
);
5152 mono_mb_emit_ldloc (mb
, conv_arg
);
5156 if (klass
== date_time_class
) {
5158 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5160 mono_mb_emit_ldloc (mb
, conv_arg
);
5164 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
) {
5165 mono_mb_emit_ldarg (mb
, argnum
);
5168 mono_mb_emit_ldloc (mb
, conv_arg
);
5170 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5171 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
5175 case MARSHAL_ACTION_CONV_OUT
:
5176 if (klass
== date_time_class
) {
5177 /* Convert from an OLE DATE type */
5178 static MonoMethod
*from_oadate
;
5183 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5185 from_oadate
= mono_class_get_method_from_name (date_time_class
, "FromOADate", 1);
5186 g_assert (from_oadate
);
5188 mono_mb_emit_ldarg (mb
, argnum
);
5189 mono_mb_emit_ldloc (mb
, conv_arg
);
5190 mono_mb_emit_managed_call (mb
, from_oadate
, NULL
);
5191 mono_mb_emit_op (mb
, CEE_STOBJ
, date_time_class
);
5196 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
)
5200 /* dst = argument */
5201 mono_mb_emit_ldarg (mb
, argnum
);
5202 mono_mb_emit_stloc (mb
, 1);
5204 mono_mb_emit_ldloc (mb
, 1);
5205 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5207 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5208 /* src = tmp_locals [i] */
5209 mono_mb_emit_ldloc (mb
, conv_arg
);
5210 mono_mb_emit_stloc (mb
, 0);
5212 /* emit valuetype conversion code */
5213 emit_struct_conv (mb
, klass
, TRUE
);
5217 emit_struct_free (mb
, klass
, conv_arg
);
5220 mono_mb_patch_branch (mb
, pos
);
5223 case MARSHAL_ACTION_CONV_RESULT
:
5224 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
) {
5225 mono_mb_emit_stloc (mb
, 3);
5229 /* load pointer to returned value type */
5230 g_assert (m
->vtaddr_var
);
5231 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
5232 /* store the address of the source into local variable 0 */
5233 mono_mb_emit_stloc (mb
, 0);
5235 mono_mb_emit_ldloc_addr (mb
, 3);
5236 mono_mb_emit_stloc (mb
, 1);
5238 /* emit valuetype conversion code */
5239 emit_struct_conv (mb
, klass
, TRUE
);
5242 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5243 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
) {
5248 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
5250 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5254 mono_mb_emit_ldarg (mb
, argnum
);
5256 mono_mb_emit_ldarg_addr (mb
, argnum
);
5257 mono_mb_emit_stloc (mb
, 0);
5260 mono_mb_emit_ldloc (mb
, 0);
5261 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5264 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5265 mono_mb_emit_stloc (mb
, 1);
5267 /* emit valuetype conversion code */
5268 emit_struct_conv (mb
, klass
, TRUE
);
5271 mono_mb_patch_branch (mb
, pos
);
5274 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5275 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
)
5277 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5280 /* Check for null */
5281 mono_mb_emit_ldarg (mb
, argnum
);
5282 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5285 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5286 mono_mb_emit_stloc (mb
, 0);
5289 mono_mb_emit_ldarg (mb
, argnum
);
5290 mono_mb_emit_stloc (mb
, 1);
5292 /* emit valuetype conversion code */
5293 emit_struct_conv (mb
, klass
, FALSE
);
5295 mono_mb_patch_branch (mb
, pos2
);
5298 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5299 if (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
) {
5300 mono_mb_emit_stloc (mb
, 3);
5305 /* load pointer to returned value type */
5306 g_assert (m
->vtaddr_var
);
5307 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
5309 /* store the address of the source into local variable 0 */
5310 mono_mb_emit_stloc (mb
, 0);
5311 /* allocate space for the native struct and
5312 * store the address into dst_ptr */
5313 m
->retobj_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5314 m
->retobj_class
= klass
;
5315 g_assert (m
->retobj_var
);
5316 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5317 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5318 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5319 mono_mb_emit_stloc (mb
, 1);
5320 mono_mb_emit_ldloc (mb
, 1);
5321 mono_mb_emit_stloc (mb
, m
->retobj_var
);
5323 /* emit valuetype conversion code */
5324 emit_struct_conv (mb
, klass
, FALSE
);
5328 g_assert_not_reached ();
5335 emit_marshal_string (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5336 MonoMarshalSpec
*spec
,
5337 int conv_arg
, MonoType
**conv_arg_type
,
5338 MarshalAction action
)
5342 case MARSHAL_ACTION_CONV_IN
:
5343 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5345 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5346 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5350 MonoMethodBuilder
*mb
= m
->mb
;
5351 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5352 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
5356 case MARSHAL_ACTION_CONV_IN
:
5357 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5358 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5361 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5364 mono_mb_emit_ldarg (mb
, argnum
);
5365 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5367 mono_mb_emit_ldarg (mb
, argnum
);
5370 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5371 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5372 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5374 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5376 mono_mb_emit_stloc (mb
, conv_arg
);
5380 case MARSHAL_ACTION_CONV_OUT
:
5381 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5382 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5383 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5384 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5388 if (encoding
== MONO_NATIVE_VBBYREFSTR
) {
5389 static MonoMethod
*m
;
5392 m
= mono_class_get_method_from_name_flags (mono_defaults
.string_class
, "get_Length", -1, 0);
5397 char *msg
= g_strdup_printf ("VBByRefStr marshalling requires a ref parameter.", encoding
);
5398 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5403 * Have to allocate a new string with the same length as the original, and
5404 * copy the contents of the buffer pointed to by CONV_ARG into it.
5406 g_assert (t
->byref
);
5407 mono_mb_emit_ldarg (mb
, argnum
);
5408 mono_mb_emit_ldloc (mb
, conv_arg
);
5409 mono_mb_emit_ldarg (mb
, argnum
);
5410 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5411 mono_mb_emit_managed_call (mb
, m
, NULL
);
5412 mono_mb_emit_icall (mb
, mono_string_new_len_wrapper
);
5413 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5414 } else if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5416 mono_mb_emit_ldarg (mb
, argnum
);
5417 mono_mb_emit_ldloc (mb
, conv_arg
);
5418 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
5419 mono_mb_emit_byte (mb
, stind_op
);
5424 mono_mb_emit_ldloc (mb
, conv_arg
);
5425 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5426 mono_mb_emit_icall (mb
, mono_free_bstr
);
5428 mono_mb_emit_icall (mb
, mono_marshal_free
);
5432 case MARSHAL_ACTION_PUSH
:
5433 if (t
->byref
&& encoding
!= MONO_NATIVE_VBBYREFSTR
)
5434 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5436 mono_mb_emit_ldloc (mb
, conv_arg
);
5439 case MARSHAL_ACTION_CONV_RESULT
:
5440 mono_mb_emit_stloc (mb
, 0);
5442 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5443 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5444 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5445 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5449 mono_mb_emit_ldloc (mb
, 0);
5450 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5451 mono_mb_emit_stloc (mb
, 3);
5453 /* free the string */
5454 mono_mb_emit_ldloc (mb
, 0);
5455 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5456 mono_mb_emit_icall (mb
, mono_free_bstr
);
5458 mono_mb_emit_icall (mb
, mono_marshal_free
);
5461 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5462 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
5464 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5467 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5471 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5472 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5473 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5474 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5478 mono_mb_emit_ldarg (mb
, argnum
);
5480 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5481 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5482 mono_mb_emit_stloc (mb
, conv_arg
);
5485 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5489 mono_mb_emit_ldarg (mb
, argnum
);
5490 mono_mb_emit_ldloc (mb
, conv_arg
);
5491 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
5492 mono_mb_emit_byte (mb
, stind_op
);
5497 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5498 if (conv_to_icall (conv
, NULL
) == mono_marshal_string_to_utf16
)
5499 /* We need to make a copy so the caller is able to free it */
5500 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
5502 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5503 mono_mb_emit_stloc (mb
, 3);
5507 g_assert_not_reached ();
5515 emit_marshal_safehandle (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5516 MonoMarshalSpec
*spec
, int conv_arg
,
5517 MonoType
**conv_arg_type
, MarshalAction action
)
5520 if (action
== MARSHAL_ACTION_CONV_IN
)
5521 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5523 MonoMethodBuilder
*mb
= m
->mb
;
5526 case MARSHAL_ACTION_CONV_IN
: {
5527 MonoType
*intptr_type
;
5528 int dar_release_slot
, pos
;
5530 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
5531 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
5532 *conv_arg_type
= intptr_type
;
5534 if (!sh_dangerous_add_ref
)
5535 init_safe_handle ();
5537 mono_mb_emit_ldarg (mb
, argnum
);
5538 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5539 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5541 mono_mb_patch_branch (mb
, pos
);
5544 * My tests in show that ref SafeHandles are not really
5545 * passed as ref objects. Instead a NULL is passed as the
5548 mono_mb_emit_icon (mb
, 0);
5549 mono_mb_emit_stloc (mb
, conv_arg
);
5553 /* Create local to hold the ref parameter to DangerousAddRef */
5554 dar_release_slot
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
5556 /* set release = false; */
5557 mono_mb_emit_icon (mb
, 0);
5558 mono_mb_emit_stloc (mb
, dar_release_slot
);
5560 /* safehandle.DangerousAddRef (ref release) */
5561 mono_mb_emit_ldarg (mb
, argnum
);
5562 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5563 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5565 /* Pull the handle field from SafeHandle */
5566 mono_mb_emit_ldarg (mb
, argnum
);
5567 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5568 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5569 mono_mb_emit_stloc (mb
, conv_arg
);
5574 case MARSHAL_ACTION_PUSH
:
5576 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5578 mono_mb_emit_ldloc (mb
, conv_arg
);
5581 case MARSHAL_ACTION_CONV_OUT
: {
5582 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5583 int dar_release_slot
= conv_arg
+ 1;
5586 if (!sh_dangerous_release
)
5587 init_safe_handle ();
5593 * My tests indicate that ref SafeHandles parameters are not actually
5594 * passed by ref, but instead a new Handle is created regardless of
5595 * whether a change happens in the unmanaged side.
5597 * Also, the Handle is created before calling into unmanaged code,
5598 * but we do not support that mechanism (getting to the original
5599 * handle) and it makes no difference where we create this
5601 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
5603 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5606 /* refval = new SafeHandleDerived ()*/
5607 mono_mb_emit_ldarg (mb
, argnum
);
5608 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5609 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5611 /* refval.handle = returned_handle */
5612 mono_mb_emit_ldarg (mb
, argnum
);
5613 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5614 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5615 mono_mb_emit_ldloc (mb
, conv_arg
);
5616 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5618 mono_mb_emit_ldloc (mb
, dar_release_slot
);
5619 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5620 mono_mb_emit_ldarg (mb
, argnum
);
5621 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5622 mono_mb_patch_branch (mb
, label_next
);
5627 case MARSHAL_ACTION_CONV_RESULT
: {
5628 MonoMethod
*ctor
= NULL
;
5629 int intptr_handle_slot
;
5631 if (mono_class_is_abstract (t
->data
.klass
)) {
5632 mono_mb_emit_byte (mb
, CEE_POP
);
5633 mono_mb_emit_exception_marshal_directive (mb
, g_strdup ("Returned SafeHandles should not be abstract"));
5637 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
5639 mono_mb_emit_byte (mb
, CEE_POP
);
5640 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5643 /* Store the IntPtr results into a local */
5644 intptr_handle_slot
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5645 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
5647 /* Create return value */
5648 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5649 mono_mb_emit_stloc (mb
, 3);
5651 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5652 mono_mb_emit_ldloc (mb
, 3);
5653 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5654 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
5655 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5659 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5660 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5663 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5664 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5667 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5668 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5671 printf ("Unhandled case for MarshalAction: %d\n", action
);
5679 emit_marshal_handleref (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5680 MonoMarshalSpec
*spec
, int conv_arg
,
5681 MonoType
**conv_arg_type
, MarshalAction action
)
5684 if (action
== MARSHAL_ACTION_CONV_IN
)
5685 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5687 MonoMethodBuilder
*mb
= m
->mb
;
5690 case MARSHAL_ACTION_CONV_IN
: {
5691 MonoType
*intptr_type
;
5693 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
5694 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
5695 *conv_arg_type
= intptr_type
;
5698 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5699 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5702 mono_mb_emit_ldarg_addr (mb
, argnum
);
5703 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
5704 mono_mb_emit_byte (mb
, CEE_ADD
);
5705 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5706 mono_mb_emit_stloc (mb
, conv_arg
);
5710 case MARSHAL_ACTION_PUSH
:
5711 mono_mb_emit_ldloc (mb
, conv_arg
);
5714 case MARSHAL_ACTION_CONV_OUT
: {
5715 /* no resource release required */
5719 case MARSHAL_ACTION_CONV_RESULT
: {
5720 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5721 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5725 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5726 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5729 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5730 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5733 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5734 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5737 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
5745 emit_marshal_object (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5746 MonoMarshalSpec
*spec
,
5747 int conv_arg
, MonoType
**conv_arg_type
,
5748 MarshalAction action
)
5751 if (action
== MARSHAL_ACTION_CONV_IN
)
5752 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5754 MonoMethodBuilder
*mb
= m
->mb
;
5755 MonoClass
*klass
= mono_class_from_mono_type (t
);
5759 case MARSHAL_ACTION_CONV_IN
:
5760 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5761 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5763 m
->orig_conv_args
[argnum
] = 0;
5765 if (mono_class_from_mono_type (t
) == mono_defaults
.object_class
) {
5766 char *msg
= g_strdup_printf ("Marshalling of type object is not implemented");
5767 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5771 if (klass
->delegate
) {
5773 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5774 char *msg
= g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5775 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5777 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5778 mono_mb_emit_stloc (mb
, conv_arg
);
5780 mono_mb_emit_ldarg (mb
, argnum
);
5781 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5782 mono_mb_emit_stloc (mb
, conv_arg
);
5784 } else if (klass
== mono_defaults
.stringbuilder_class
) {
5785 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5786 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
5790 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5791 char *msg
= g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5792 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5798 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5801 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5802 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
5803 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5807 mono_mb_emit_ldarg (mb
, argnum
);
5809 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5811 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5812 mono_mb_emit_stloc (mb
, conv_arg
);
5813 } else if (klass
->blittable
) {
5814 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5815 mono_mb_emit_stloc (mb
, conv_arg
);
5817 mono_mb_emit_ldarg (mb
, argnum
);
5818 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5820 mono_mb_emit_ldarg (mb
, argnum
);
5821 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
5822 mono_mb_emit_stloc (mb
, conv_arg
);
5824 mono_mb_patch_branch (mb
, pos
);
5827 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5828 mono_mb_emit_stloc (mb
, conv_arg
);
5831 /* we dont need any conversions for out parameters */
5832 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5835 mono_mb_emit_ldarg (mb
, argnum
);
5836 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5839 mono_mb_emit_ldarg (mb
, argnum
);
5840 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5841 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5844 /* store the address of the source into local variable 0 */
5845 mono_mb_emit_stloc (mb
, 0);
5846 mono_mb_emit_ldloc (mb
, 0);
5847 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5849 /* allocate space for the native struct and store the address */
5850 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5851 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5852 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5853 mono_mb_emit_stloc (mb
, conv_arg
);
5856 /* Need to store the original buffer so we can free it later */
5857 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5858 mono_mb_emit_ldloc (mb
, conv_arg
);
5859 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
5862 /* set the src_ptr */
5863 mono_mb_emit_ldloc (mb
, 0);
5864 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
5865 mono_mb_emit_stloc (mb
, 0);
5868 mono_mb_emit_ldloc (mb
, conv_arg
);
5869 mono_mb_emit_stloc (mb
, 1);
5871 /* emit valuetype conversion code */
5872 emit_struct_conv (mb
, klass
, FALSE
);
5874 mono_mb_patch_branch (mb
, pos
);
5878 case MARSHAL_ACTION_CONV_OUT
:
5879 if (klass
== mono_defaults
.stringbuilder_class
) {
5881 MonoMarshalNative encoding
;
5882 MonoMarshalConv conv
;
5884 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5885 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
5887 g_assert (encoding
!= -1);
5890 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5894 mono_mb_emit_ldarg (mb
, argnum
);
5895 mono_mb_emit_ldloc (mb
, conv_arg
);
5898 case MONO_NATIVE_LPWSTR
:
5899 mono_mb_emit_icall (mb
, mono_string_utf16_to_builder2
);
5901 case MONO_NATIVE_LPSTR
:
5902 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5904 case MONO_NATIVE_UTF8STR
:
5905 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5908 g_assert_not_reached ();
5911 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5913 mono_mb_emit_ldarg (mb
, argnum
);
5914 mono_mb_emit_ldloc (mb
, conv_arg
);
5916 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
5920 mono_mb_emit_ldloc (mb
, conv_arg
);
5921 mono_mb_emit_icall (mb
, mono_marshal_free
);
5926 if (klass
->delegate
) {
5928 mono_mb_emit_ldarg (mb
, argnum
);
5929 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5930 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5931 mono_mb_emit_ldloc (mb
, conv_arg
);
5932 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5933 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5938 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5939 /* allocate a new object */
5940 mono_mb_emit_ldarg (mb
, argnum
);
5941 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5942 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5943 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5946 /* dst = *argument */
5947 mono_mb_emit_ldarg (mb
, argnum
);
5950 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5952 mono_mb_emit_stloc (mb
, 1);
5954 mono_mb_emit_ldloc (mb
, 1);
5955 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5957 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5958 mono_mb_emit_ldloc (mb
, 1);
5959 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
5960 mono_mb_emit_byte (mb
, CEE_ADD
);
5961 mono_mb_emit_stloc (mb
, 1);
5963 /* src = tmp_locals [i] */
5964 mono_mb_emit_ldloc (mb
, conv_arg
);
5965 mono_mb_emit_stloc (mb
, 0);
5967 /* emit valuetype conversion code */
5968 emit_struct_conv (mb
, klass
, TRUE
);
5970 /* Free the structure returned by the native code */
5971 emit_struct_free (mb
, klass
, conv_arg
);
5973 if (m
->orig_conv_args
[argnum
]) {
5975 * If the native function changed the pointer, then free
5976 * the original structure plus the new pointer.
5978 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
5979 mono_mb_emit_ldloc (mb
, conv_arg
);
5980 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5982 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5983 g_assert (m
->orig_conv_args
[argnum
]);
5985 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
5988 mono_mb_emit_ldloc (mb
, conv_arg
);
5989 mono_mb_emit_icall (mb
, mono_marshal_free
);
5991 mono_mb_patch_branch (mb
, pos2
);
5995 /* Free the original structure passed to native code */
5996 emit_struct_free (mb
, klass
, conv_arg
);
5998 mono_mb_patch_branch (mb
, pos
);
6001 case MARSHAL_ACTION_PUSH
:
6003 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6005 mono_mb_emit_ldloc (mb
, conv_arg
);
6008 case MARSHAL_ACTION_CONV_RESULT
:
6009 if (klass
->delegate
) {
6010 g_assert (!t
->byref
);
6011 mono_mb_emit_stloc (mb
, 0);
6012 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6013 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6014 mono_mb_emit_ldloc (mb
, 0);
6015 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
6016 mono_mb_emit_stloc (mb
, 3);
6017 } else if (klass
== mono_defaults
.stringbuilder_class
){
6021 mono_mb_emit_stloc (mb
, 0);
6023 /* Make a copy since emit_conv modifies local 0 */
6024 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6025 mono_mb_emit_ldloc (mb
, 0);
6026 mono_mb_emit_stloc (mb
, loc
);
6028 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6029 mono_mb_emit_stloc (mb
, 3);
6031 mono_mb_emit_ldloc (mb
, 0);
6032 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6034 /* allocate result object */
6036 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6037 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6038 mono_mb_emit_stloc (mb
, 3);
6042 mono_mb_emit_ldloc (mb
, 3);
6043 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6044 mono_mb_emit_stloc (mb
, 1);
6046 /* emit conversion code */
6047 emit_struct_conv (mb
, klass
, TRUE
);
6049 emit_struct_free (mb
, klass
, loc
);
6051 /* Free the pointer allocated by unmanaged code */
6052 mono_mb_emit_ldloc (mb
, loc
);
6053 mono_mb_emit_icall (mb
, mono_marshal_free
);
6054 mono_mb_patch_branch (mb
, pos
);
6058 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6059 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
6061 if (klass
->delegate
) {
6062 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6063 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6064 mono_mb_emit_ldarg (mb
, argnum
);
6066 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6067 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
6068 mono_mb_emit_stloc (mb
, conv_arg
);
6072 if (klass
== mono_defaults
.stringbuilder_class
) {
6073 MonoMarshalNative encoding
;
6075 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6078 g_assert (encoding
== MONO_NATIVE_LPSTR
|| encoding
== MONO_NATIVE_UTF8STR
);
6080 g_assert (!t
->byref
);
6081 g_assert (encoding
!= -1);
6083 mono_mb_emit_ldarg (mb
, argnum
);
6084 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
6085 mono_mb_emit_stloc (mb
, conv_arg
);
6089 /* The class can not have an automatic layout */
6090 if (mono_class_is_auto_layout (klass
)) {
6091 mono_mb_emit_auto_layout_exception (mb
, klass
);
6095 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
6096 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6097 mono_mb_emit_stloc (mb
, conv_arg
);
6102 mono_mb_emit_ldarg (mb
, argnum
);
6106 /* Check for NULL and raise an exception */
6107 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6109 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
6111 mono_mb_patch_branch (mb
, pos2
);
6112 mono_mb_emit_ldarg (mb
, argnum
);
6113 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6116 mono_mb_emit_stloc (mb
, 0);
6118 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6119 mono_mb_emit_stloc (mb
, conv_arg
);
6121 mono_mb_emit_ldloc (mb
, 0);
6122 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6124 /* Create and set dst */
6125 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6126 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6127 mono_mb_emit_stloc (mb
, conv_arg
);
6128 mono_mb_emit_ldloc (mb
, conv_arg
);
6129 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6130 mono_mb_emit_stloc (mb
, 1);
6132 /* emit valuetype conversion code */
6133 emit_struct_conv (mb
, klass
, TRUE
);
6135 mono_mb_patch_branch (mb
, pos
);
6138 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6139 if (klass
->delegate
) {
6142 mono_mb_emit_ldarg (mb
, argnum
);
6143 mono_mb_emit_ldloc (mb
, conv_arg
);
6144 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, &stind_op
));
6145 mono_mb_emit_byte (mb
, stind_op
);
6151 /* Check for null */
6152 mono_mb_emit_ldloc (mb
, conv_arg
);
6153 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6154 mono_mb_emit_ldarg (mb
, argnum
);
6155 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6156 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6157 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6159 mono_mb_patch_branch (mb
, pos
);
6162 mono_mb_emit_ldloc (mb
, conv_arg
);
6163 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6164 mono_mb_emit_stloc (mb
, 0);
6166 /* Allocate and set dest */
6167 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6168 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6169 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
6170 mono_mb_emit_stloc (mb
, 1);
6172 /* Update argument pointer */
6173 mono_mb_emit_ldarg (mb
, argnum
);
6174 mono_mb_emit_ldloc (mb
, 1);
6175 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6177 /* emit valuetype conversion code */
6178 emit_struct_conv (mb
, klass
, FALSE
);
6180 mono_mb_patch_branch (mb
, pos2
);
6181 } else if (klass
== mono_defaults
.stringbuilder_class
) {
6182 // FIXME: What to do here ?
6184 /* byval [Out] marshalling */
6186 /* FIXME: Handle null */
6189 mono_mb_emit_ldloc (mb
, conv_arg
);
6190 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6191 mono_mb_emit_stloc (mb
, 0);
6194 mono_mb_emit_ldarg (mb
, argnum
);
6195 mono_mb_emit_stloc (mb
, 1);
6197 /* emit valuetype conversion code */
6198 emit_struct_conv (mb
, klass
, FALSE
);
6202 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6203 if (klass
->delegate
) {
6204 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
6205 mono_mb_emit_stloc (mb
, 3);
6209 /* The class can not have an automatic layout */
6210 if (mono_class_is_auto_layout (klass
)) {
6211 mono_mb_emit_auto_layout_exception (mb
, klass
);
6215 mono_mb_emit_stloc (mb
, 0);
6216 /* Check for null */
6217 mono_mb_emit_ldloc (mb
, 0);
6218 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6219 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6220 mono_mb_emit_stloc (mb
, 3);
6221 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6223 mono_mb_patch_branch (mb
, pos
);
6226 mono_mb_emit_ldloc (mb
, 0);
6227 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6228 mono_mb_emit_stloc (mb
, 0);
6230 /* Allocate and set dest */
6231 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6232 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6233 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
6234 mono_mb_emit_byte (mb
, CEE_DUP
);
6235 mono_mb_emit_stloc (mb
, 1);
6236 mono_mb_emit_stloc (mb
, 3);
6238 emit_struct_conv (mb
, klass
, FALSE
);
6240 mono_mb_patch_branch (mb
, pos2
);
6244 g_assert_not_reached ();
6255 emit_marshal_variant (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6256 MonoMarshalSpec
*spec
,
6257 int conv_arg
, MonoType
**conv_arg_type
,
6258 MarshalAction action
)
6260 MonoMethodBuilder
*mb
= m
->mb
;
6261 static MonoMethod
*get_object_for_native_variant
= NULL
;
6262 static MonoMethod
*get_native_variant_for_object
= NULL
;
6264 if (!get_object_for_native_variant
)
6265 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
6266 g_assert (get_object_for_native_variant
);
6268 if (!get_native_variant_for_object
)
6269 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
6270 g_assert (get_native_variant_for_object
);
6273 case MARSHAL_ACTION_CONV_IN
: {
6274 conv_arg
= mono_mb_add_local (mb
, &mono_class_get_variant_class ()->byval_arg
);
6277 *conv_arg_type
= &mono_class_get_variant_class ()->this_arg
;
6279 *conv_arg_type
= &mono_class_get_variant_class ()->byval_arg
;
6281 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6284 mono_mb_emit_ldarg (mb
, argnum
);
6286 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
6287 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6288 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
6292 case MARSHAL_ACTION_CONV_OUT
: {
6293 static MonoMethod
*variant_clear
= NULL
;
6296 variant_clear
= mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
6297 g_assert (variant_clear
);
6300 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6301 mono_mb_emit_ldarg (mb
, argnum
);
6302 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6303 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
6304 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6307 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6308 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
6312 case MARSHAL_ACTION_PUSH
:
6314 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6316 mono_mb_emit_ldloc (mb
, conv_arg
);
6319 case MARSHAL_ACTION_CONV_RESULT
: {
6320 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6321 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6325 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
6326 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6329 *conv_arg_type
= &mono_class_get_variant_class ()->this_arg
;
6331 *conv_arg_type
= &mono_class_get_variant_class ()->byval_arg
;
6333 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6337 mono_mb_emit_ldarg (mb
, argnum
);
6339 mono_mb_emit_ldarg_addr (mb
, argnum
);
6340 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
6341 mono_mb_emit_stloc (mb
, conv_arg
);
6345 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
6346 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6347 mono_mb_emit_ldloc (mb
, conv_arg
);
6348 mono_mb_emit_ldarg (mb
, argnum
);
6349 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
6354 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
6355 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6356 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6361 g_assert_not_reached ();
6367 #endif /* DISABLE_COM */
6368 #endif /* DISABLE_JIT */
6371 mono_pinvoke_is_unicode (MonoMethodPInvoke
*piinfo
)
6373 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
6374 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
6376 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
6378 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
6390 emit_marshal_array (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6391 MonoMarshalSpec
*spec
,
6392 int conv_arg
, MonoType
**conv_arg_type
,
6393 MarshalAction action
)
6397 case MARSHAL_ACTION_CONV_IN
:
6398 *conv_arg_type
= &mono_defaults
.object_class
->byval_arg
;
6400 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6401 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6405 MonoMethodBuilder
*mb
= m
->mb
;
6406 MonoClass
*klass
= mono_class_from_mono_type (t
);
6407 gboolean need_convert
, need_free
;
6408 MonoMarshalNative encoding
;
6410 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6413 case MARSHAL_ACTION_CONV_IN
:
6414 *conv_arg_type
= &mono_defaults
.object_class
->byval_arg
;
6415 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6417 if (klass
->element_class
->blittable
) {
6418 mono_mb_emit_ldarg (mb
, argnum
);
6420 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6421 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
, NULL
));
6422 mono_mb_emit_stloc (mb
, conv_arg
);
6425 guint32 label1
, label2
, label3
;
6426 int index_var
, src_var
, dest_ptr
, esize
;
6427 MonoMarshalConv conv
;
6428 gboolean is_string
= FALSE
;
6430 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6432 eklass
= klass
->element_class
;
6434 if (eklass
== mono_defaults
.string_class
) {
6436 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6438 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6440 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6443 conv
= MONO_MARSHAL_CONV_INVALID
;
6445 if (is_string
&& conv
== MONO_MARSHAL_CONV_INVALID
) {
6446 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
6447 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6451 src_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6452 mono_mb_emit_ldarg (mb
, argnum
);
6454 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6455 mono_mb_emit_stloc (mb
, src_var
);
6458 mono_mb_emit_ldloc (mb
, src_var
);
6459 mono_mb_emit_stloc (mb
, conv_arg
);
6460 mono_mb_emit_ldloc (mb
, src_var
);
6461 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6464 esize
= sizeof (gpointer
);
6465 else if (eklass
== mono_defaults
.char_class
) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
6466 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
6468 esize
= mono_class_native_size (eklass
, NULL
);
6470 /* allocate space for the native struct and store the address */
6471 mono_mb_emit_icon (mb
, esize
);
6472 mono_mb_emit_ldloc (mb
, src_var
);
6473 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6475 if (eklass
== mono_defaults
.string_class
) {
6476 /* Make the array bigger for the terminating null */
6477 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
6478 mono_mb_emit_byte (mb
, CEE_ADD
);
6480 mono_mb_emit_byte (mb
, CEE_MUL
);
6481 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6482 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
6483 mono_mb_emit_stloc (mb
, conv_arg
);
6485 mono_mb_emit_ldloc (mb
, conv_arg
);
6486 mono_mb_emit_stloc (mb
, dest_ptr
);
6488 /* Emit marshalling loop */
6489 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6490 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6491 mono_mb_emit_stloc (mb
, index_var
);
6492 label2
= mono_mb_get_label (mb
);
6493 mono_mb_emit_ldloc (mb
, index_var
);
6494 mono_mb_emit_ldloc (mb
, src_var
);
6495 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6496 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6498 /* Emit marshalling code */
6502 mono_mb_emit_ldloc (mb
, dest_ptr
);
6503 mono_mb_emit_ldloc (mb
, src_var
);
6504 mono_mb_emit_ldloc (mb
, index_var
);
6505 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6506 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
6507 mono_mb_emit_byte (mb
, stind_op
);
6509 /* set the src_ptr */
6510 mono_mb_emit_ldloc (mb
, src_var
);
6511 mono_mb_emit_ldloc (mb
, index_var
);
6512 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
6513 mono_mb_emit_stloc (mb
, 0);
6516 mono_mb_emit_ldloc (mb
, dest_ptr
);
6517 mono_mb_emit_stloc (mb
, 1);
6519 /* emit valuetype conversion code */
6520 emit_struct_conv_full (mb
, eklass
, FALSE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
6523 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6524 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
6526 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6528 mono_mb_patch_branch (mb
, label3
);
6530 if (eklass
== mono_defaults
.string_class
) {
6531 /* Null terminate */
6532 mono_mb_emit_ldloc (mb
, dest_ptr
);
6533 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6534 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6537 mono_mb_patch_branch (mb
, label1
);
6542 case MARSHAL_ACTION_CONV_OUT
:
6543 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
6544 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
);
6545 need_free
= mono_marshal_need_free (&klass
->element_class
->byval_arg
,
6548 if ((t
->attrs
& PARAM_ATTRIBUTE_OUT
) && spec
&& spec
->native
== MONO_NATIVE_LPARRAY
&& spec
->data
.array_data
.param_num
!= -1) {
6549 int param_num
= spec
->data
.array_data
.param_num
;
6550 MonoType
*param_type
;
6552 param_type
= m
->sig
->params
[param_num
];
6554 if (param_type
->byref
&& param_type
->type
!= MONO_TYPE_I4
) {
6555 char *msg
= g_strdup ("Not implemented.");
6556 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6561 mono_mb_emit_ldarg (mb
, argnum
);
6563 /* Create the managed array */
6564 mono_mb_emit_ldarg (mb
, param_num
);
6565 if (m
->sig
->params
[param_num
]->byref
)
6566 // FIXME: Support other types
6567 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
6568 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
6569 mono_mb_emit_op (mb
, CEE_NEWARR
, klass
->element_class
);
6570 /* Store into argument */
6571 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6575 if (need_convert
|| need_free
) {
6576 /* FIXME: Optimize blittable case */
6578 guint32 label1
, label2
, label3
;
6579 int index_var
, src_ptr
, loc
, esize
;
6581 eklass
= klass
->element_class
;
6582 if ((eklass
== mono_defaults
.stringbuilder_class
) || (eklass
== mono_defaults
.string_class
))
6583 esize
= sizeof (gpointer
);
6584 else if (eklass
== mono_defaults
.char_class
)
6585 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
6587 esize
= mono_class_native_size (eklass
, NULL
);
6588 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6589 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6592 mono_mb_emit_ldarg (mb
, argnum
);
6594 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6595 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6597 mono_mb_emit_ldloc (mb
, conv_arg
);
6598 mono_mb_emit_stloc (mb
, src_ptr
);
6600 /* Emit marshalling loop */
6601 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6602 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6603 mono_mb_emit_stloc (mb
, index_var
);
6604 label2
= mono_mb_get_label (mb
);
6605 mono_mb_emit_ldloc (mb
, index_var
);
6606 mono_mb_emit_ldarg (mb
, argnum
);
6608 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6609 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6610 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6612 /* Emit marshalling code */
6614 if (eklass
== mono_defaults
.stringbuilder_class
) {
6615 gboolean need_free2
;
6616 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
6618 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6621 mono_mb_emit_ldarg (mb
, argnum
);
6623 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6624 mono_mb_emit_ldloc (mb
, index_var
);
6625 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6628 mono_mb_emit_ldloc (mb
, src_ptr
);
6629 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6631 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
6635 mono_mb_emit_ldloc (mb
, src_ptr
);
6636 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6638 mono_mb_emit_icall (mb
, mono_marshal_free
);
6641 else if (eklass
== mono_defaults
.string_class
) {
6644 mono_mb_emit_ldloc (mb
, src_ptr
);
6645 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6647 mono_mb_emit_icall (mb
, mono_marshal_free
);
6652 /* set the src_ptr */
6653 mono_mb_emit_ldloc (mb
, src_ptr
);
6654 mono_mb_emit_stloc (mb
, 0);
6657 mono_mb_emit_ldarg (mb
, argnum
);
6659 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6660 mono_mb_emit_ldloc (mb
, index_var
);
6661 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
6662 mono_mb_emit_stloc (mb
, 1);
6664 /* emit valuetype conversion code */
6665 emit_struct_conv_full (mb
, eklass
, TRUE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
6669 mono_mb_emit_ldloc (mb
, src_ptr
);
6670 mono_mb_emit_stloc (mb
, loc
);
6671 mono_mb_emit_ldloc (mb
, loc
);
6673 emit_struct_free (mb
, eklass
, loc
);
6677 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6678 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
6680 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6682 mono_mb_patch_branch (mb
, label1
);
6683 mono_mb_patch_branch (mb
, label3
);
6686 if (klass
->element_class
->blittable
) {
6687 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
6689 mono_mb_emit_ldarg (mb
, argnum
);
6691 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6692 mono_mb_emit_ldloc (mb
, conv_arg
);
6693 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY
, NULL
));
6698 case MARSHAL_ACTION_PUSH
:
6700 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6702 mono_mb_emit_ldloc (mb
, conv_arg
);
6705 case MARSHAL_ACTION_CONV_RESULT
:
6706 /* fixme: we need conversions here */
6707 mono_mb_emit_stloc (mb
, 3);
6710 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
6712 guint32 label1
, label2
, label3
;
6713 int index_var
, src_ptr
, esize
, param_num
, num_elem
;
6714 MonoMarshalConv conv
;
6715 gboolean is_string
= FALSE
;
6717 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6718 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6721 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
6722 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6726 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
6727 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6730 if (spec
->native
!= MONO_NATIVE_LPARRAY
) {
6731 char *msg
= g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
6732 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6736 /* FIXME: t is from the method which is wrapped, not the delegate type */
6737 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
6739 param_num
= spec
->data
.array_data
.param_num
;
6740 num_elem
= spec
->data
.array_data
.num_elem
;
6741 if (spec
->data
.array_data
.elem_mult
== 0)
6742 /* param_num is not specified */
6745 if (param_num
== -1) {
6746 if (num_elem
<= 0) {
6747 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
6748 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6753 /* FIXME: Optimize blittable case */
6755 eklass
= klass
->element_class
;
6756 if (eklass
== mono_defaults
.string_class
) {
6758 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
6760 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6762 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
6765 conv
= MONO_MARSHAL_CONV_INVALID
;
6767 mono_marshal_load_type_info (eklass
);
6770 esize
= sizeof (gpointer
);
6772 esize
= mono_class_native_size (eklass
, NULL
);
6773 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6775 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6776 mono_mb_emit_stloc (mb
, conv_arg
);
6778 /* Check param index */
6779 if (param_num
!= -1) {
6780 if (param_num
>= m
->sig
->param_count
) {
6781 char *msg
= g_strdup ("Array size control parameter index is out of range.");
6782 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6785 switch (m
->sig
->params
[param_num
]->type
) {
6798 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
6799 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6806 mono_mb_emit_ldarg (mb
, argnum
);
6807 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6809 mono_mb_emit_ldarg (mb
, argnum
);
6810 mono_mb_emit_stloc (mb
, src_ptr
);
6812 /* Create managed array */
6814 * The LPArray marshalling spec says that sometimes param_num starts
6815 * from 1, sometimes it starts from 0. But MS seems to allways start
6819 if (param_num
== -1) {
6820 mono_mb_emit_icon (mb
, num_elem
);
6822 mono_mb_emit_ldarg (mb
, param_num
);
6824 mono_mb_emit_icon (mb
, num_elem
);
6825 mono_mb_emit_byte (mb
, CEE_ADD
);
6827 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
6830 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
6831 mono_mb_emit_stloc (mb
, conv_arg
);
6833 if (eklass
->blittable
) {
6834 mono_mb_emit_ldloc (mb
, conv_arg
);
6835 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6836 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
6837 mono_mb_emit_byte (mb
, CEE_ADD
);
6838 mono_mb_emit_ldarg (mb
, argnum
);
6839 mono_mb_emit_ldloc (mb
, conv_arg
);
6840 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6841 mono_mb_emit_icon (mb
, esize
);
6842 mono_mb_emit_byte (mb
, CEE_MUL
);
6843 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6844 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6845 mono_mb_patch_branch (mb
, label1
);
6849 /* Emit marshalling loop */
6850 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6851 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6852 mono_mb_emit_stloc (mb
, index_var
);
6853 label2
= mono_mb_get_label (mb
);
6854 mono_mb_emit_ldloc (mb
, index_var
);
6855 mono_mb_emit_ldloc (mb
, conv_arg
);
6856 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6857 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6859 /* Emit marshalling code */
6861 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6863 mono_mb_emit_ldloc (mb
, conv_arg
);
6864 mono_mb_emit_ldloc (mb
, index_var
);
6866 mono_mb_emit_ldloc (mb
, src_ptr
);
6867 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6869 mono_mb_emit_icall (mb
, conv_to_icall (conv
, NULL
));
6870 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
6873 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
6874 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6878 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6879 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
6881 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
6883 mono_mb_patch_branch (mb
, label1
);
6884 mono_mb_patch_branch (mb
, label3
);
6888 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
6890 guint32 label1
, label2
, label3
;
6891 int index_var
, dest_ptr
, esize
, param_num
, num_elem
;
6892 MonoMarshalConv conv
;
6893 gboolean is_string
= FALSE
;
6896 /* Already handled in CONV_IN */
6899 /* These are already checked in CONV_IN */
6900 g_assert (!t
->byref
);
6901 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
6902 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
6904 param_num
= spec
->data
.array_data
.param_num
;
6905 num_elem
= spec
->data
.array_data
.num_elem
;
6907 if (spec
->data
.array_data
.elem_mult
== 0)
6908 /* param_num is not specified */
6911 if (param_num
== -1) {
6912 if (num_elem
<= 0) {
6913 g_assert_not_reached ();
6917 /* FIXME: Optimize blittable case */
6919 eklass
= klass
->element_class
;
6920 if (eklass
== mono_defaults
.string_class
) {
6922 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6924 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6926 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6929 conv
= MONO_MARSHAL_CONV_INVALID
;
6931 mono_marshal_load_type_info (eklass
);
6934 esize
= sizeof (gpointer
);
6936 esize
= mono_class_native_size (eklass
, NULL
);
6938 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6941 mono_mb_emit_ldloc (mb
, conv_arg
);
6942 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6944 mono_mb_emit_ldarg (mb
, argnum
);
6945 mono_mb_emit_stloc (mb
, dest_ptr
);
6947 if (eklass
->blittable
) {
6949 mono_mb_emit_ldarg (mb
, argnum
);
6951 mono_mb_emit_ldloc (mb
, conv_arg
);
6952 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6953 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
6954 mono_mb_emit_byte (mb
, CEE_ADD
);
6956 mono_mb_emit_ldloc (mb
, conv_arg
);
6957 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6958 mono_mb_emit_icon (mb
, esize
);
6959 mono_mb_emit_byte (mb
, CEE_MUL
);
6960 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6961 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6965 /* Emit marshalling loop */
6966 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6967 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6968 mono_mb_emit_stloc (mb
, index_var
);
6969 label2
= mono_mb_get_label (mb
);
6970 mono_mb_emit_ldloc (mb
, index_var
);
6971 mono_mb_emit_ldloc (mb
, conv_arg
);
6972 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6973 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6975 /* Emit marshalling code */
6978 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
6981 mono_mb_emit_ldloc (mb
, dest_ptr
);
6984 mono_mb_emit_ldloc (mb
, conv_arg
);
6985 mono_mb_emit_ldloc (mb
, index_var
);
6987 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6989 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
6990 mono_mb_emit_byte (mb
, stind_op
);
6993 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
6994 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6998 mono_mb_emit_add_to_local (mb
, index_var
, 1);
6999 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
7001 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7003 mono_mb_patch_branch (mb
, label1
);
7004 mono_mb_patch_branch (mb
, label3
);
7008 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
7010 guint32 label1
, label2
, label3
;
7011 int index_var
, src
, dest
, esize
;
7012 MonoMarshalConv conv
= MONO_MARSHAL_CONV_INVALID
;
7013 gboolean is_string
= FALSE
;
7015 g_assert (!t
->byref
);
7017 eklass
= klass
->element_class
;
7019 mono_marshal_load_type_info (eklass
);
7021 if (eklass
== mono_defaults
.string_class
) {
7023 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
7026 g_assert_not_reached ();
7030 esize
= sizeof (gpointer
);
7031 else if (eklass
== mono_defaults
.char_class
)
7032 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
7034 esize
= mono_class_native_size (eklass
, NULL
);
7036 src
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7037 dest
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7039 mono_mb_emit_stloc (mb
, src
);
7040 mono_mb_emit_ldloc (mb
, src
);
7041 mono_mb_emit_stloc (mb
, 3);
7043 /* Check for null */
7044 mono_mb_emit_ldloc (mb
, src
);
7045 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7047 /* Allocate native array */
7048 mono_mb_emit_icon (mb
, esize
);
7049 mono_mb_emit_ldloc (mb
, src
);
7050 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7052 if (eklass
== mono_defaults
.string_class
) {
7053 /* Make the array bigger for the terminating null */
7054 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7055 mono_mb_emit_byte (mb
, CEE_ADD
);
7057 mono_mb_emit_byte (mb
, CEE_MUL
);
7058 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
7059 mono_mb_emit_stloc (mb
, dest
);
7060 mono_mb_emit_ldloc (mb
, dest
);
7061 mono_mb_emit_stloc (mb
, 3);
7063 /* Emit marshalling loop */
7064 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7065 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7066 mono_mb_emit_stloc (mb
, index_var
);
7067 label2
= mono_mb_get_label (mb
);
7068 mono_mb_emit_ldloc (mb
, index_var
);
7069 mono_mb_emit_ldloc (mb
, src
);
7070 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7071 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7073 /* Emit marshalling code */
7076 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
7079 mono_mb_emit_ldloc (mb
, dest
);
7082 mono_mb_emit_ldloc (mb
, src
);
7083 mono_mb_emit_ldloc (mb
, index_var
);
7085 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
7087 mono_mb_emit_icall (mb
, conv_to_icall (conv
, &stind_op
));
7088 mono_mb_emit_byte (mb
, stind_op
);
7091 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
7092 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7096 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7097 mono_mb_emit_add_to_local (mb
, dest
, esize
);
7099 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7101 mono_mb_patch_branch (mb
, label3
);
7102 mono_mb_patch_branch (mb
, label1
);
7106 g_assert_not_reached ();
7113 marshal_boolean_conv_in_get_local_type (MonoMarshalSpec
*spec
, guint8
*ldc_op
/*out*/)
7116 return &mono_defaults
.int32_class
->byval_arg
;
7118 switch (spec
->native
) {
7119 case MONO_NATIVE_I1
:
7120 case MONO_NATIVE_U1
:
7121 return &mono_defaults
.byte_class
->byval_arg
;
7122 case MONO_NATIVE_VARIANTBOOL
:
7123 if (ldc_op
) *ldc_op
= CEE_LDC_I4_M1
;
7124 return &mono_defaults
.int16_class
->byval_arg
;
7125 case MONO_NATIVE_BOOLEAN
:
7126 return &mono_defaults
.int32_class
->byval_arg
;
7128 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
7129 return &mono_defaults
.int32_class
->byval_arg
;
7135 marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec
*spec
, guint8
*ldop
/*out*/)
7137 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
7139 switch (spec
->native
) {
7140 case MONO_NATIVE_I1
:
7141 case MONO_NATIVE_U1
:
7142 conv_arg_class
= mono_defaults
.byte_class
;
7143 if (ldop
) *ldop
= CEE_LDIND_I1
;
7145 case MONO_NATIVE_VARIANTBOOL
:
7146 conv_arg_class
= mono_defaults
.int16_class
;
7147 if (ldop
) *ldop
= CEE_LDIND_I2
;
7149 case MONO_NATIVE_BOOLEAN
:
7152 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
7155 return conv_arg_class
;
7159 emit_marshal_boolean (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7160 MonoMarshalSpec
*spec
,
7161 int conv_arg
, MonoType
**conv_arg_type
,
7162 MarshalAction action
)
7166 case MARSHAL_ACTION_CONV_IN
:
7168 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7170 *conv_arg_type
= marshal_boolean_conv_in_get_local_type (spec
, NULL
);
7173 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7174 MonoClass
* conv_arg_class
= marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, NULL
);
7176 *conv_arg_type
= &conv_arg_class
->this_arg
;
7178 *conv_arg_type
= &conv_arg_class
->byval_arg
;
7184 MonoMethodBuilder
*mb
= m
->mb
;
7187 case MARSHAL_ACTION_CONV_IN
: {
7188 MonoType
*local_type
;
7190 guint8 ldc_op
= CEE_LDC_I4_1
;
7192 local_type
= marshal_boolean_conv_in_get_local_type (spec
, &ldc_op
);
7194 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7196 *conv_arg_type
= local_type
;
7197 conv_arg
= mono_mb_add_local (mb
, local_type
);
7199 mono_mb_emit_ldarg (mb
, argnum
);
7201 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
7202 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7203 mono_mb_emit_byte (mb
, ldc_op
);
7204 mono_mb_emit_stloc (mb
, conv_arg
);
7205 mono_mb_patch_branch (mb
, label_false
);
7210 case MARSHAL_ACTION_CONV_OUT
:
7212 int label_false
, label_end
;
7216 mono_mb_emit_ldarg (mb
, argnum
);
7217 mono_mb_emit_ldloc (mb
, conv_arg
);
7219 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7220 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7222 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
7223 mono_mb_patch_branch (mb
, label_false
);
7224 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7225 mono_mb_patch_branch (mb
, label_end
);
7227 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
7231 case MARSHAL_ACTION_PUSH
:
7233 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7235 mono_mb_emit_ldloc (mb
, conv_arg
);
7237 mono_mb_emit_ldarg (mb
, argnum
);
7240 case MARSHAL_ACTION_CONV_RESULT
:
7241 /* maybe we need to make sure that it fits within 8 bits */
7242 mono_mb_emit_stloc (mb
, 3);
7245 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7246 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
7247 guint8 ldop
= CEE_LDIND_I4
;
7248 int label_null
, label_false
;
7250 conv_arg_class
= marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, &ldop
);
7251 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
7254 *conv_arg_type
= &conv_arg_class
->this_arg
;
7256 *conv_arg_type
= &conv_arg_class
->byval_arg
;
7259 mono_mb_emit_ldarg (mb
, argnum
);
7263 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7264 mono_mb_emit_ldarg (mb
, argnum
);
7265 mono_mb_emit_byte (mb
, ldop
);
7269 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7270 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7271 mono_mb_emit_stloc (mb
, conv_arg
);
7272 mono_mb_patch_branch (mb
, label_false
);
7275 mono_mb_patch_branch (mb
, label_null
);
7279 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7280 guint8 stop
= CEE_STIND_I4
;
7281 guint8 ldc_op
= CEE_LDC_I4_1
;
7282 int label_null
,label_false
, label_end
;;
7287 switch (spec
->native
) {
7288 case MONO_NATIVE_I1
:
7289 case MONO_NATIVE_U1
:
7290 stop
= CEE_STIND_I1
;
7292 case MONO_NATIVE_VARIANTBOOL
:
7293 stop
= CEE_STIND_I2
;
7294 ldc_op
= CEE_LDC_I4_M1
;
7302 mono_mb_emit_ldarg (mb
, argnum
);
7303 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7305 mono_mb_emit_ldarg (mb
, argnum
);
7306 mono_mb_emit_ldloc (mb
, conv_arg
);
7308 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7309 mono_mb_emit_byte (mb
, ldc_op
);
7310 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
7312 mono_mb_patch_branch (mb
, label_false
);
7313 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7314 mono_mb_patch_branch (mb
, label_end
);
7316 mono_mb_emit_byte (mb
, stop
);
7317 mono_mb_patch_branch (mb
, label_null
);
7322 g_assert_not_reached ();
7329 emit_marshal_ptr (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7330 MonoMarshalSpec
*spec
, int conv_arg
,
7331 MonoType
**conv_arg_type
, MarshalAction action
)
7334 MonoMethodBuilder
*mb
= m
->mb
;
7337 case MARSHAL_ACTION_CONV_IN
:
7338 /* MS seems to allow this in some cases, ie. bxc #158 */
7340 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
7341 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
7342 mono_mb_emit_exception_marshal_directive (m->mb, msg);
7347 case MARSHAL_ACTION_PUSH
:
7348 mono_mb_emit_ldarg (mb
, argnum
);
7351 case MARSHAL_ACTION_CONV_RESULT
:
7352 /* no conversions necessary */
7353 mono_mb_emit_stloc (mb
, 3);
7364 emit_marshal_char (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7365 MonoMarshalSpec
*spec
, int conv_arg
,
7366 MonoType
**conv_arg_type
, MarshalAction action
)
7369 MonoMethodBuilder
*mb
= m
->mb
;
7372 case MARSHAL_ACTION_PUSH
:
7373 /* fixme: dont know how to marshal that. We cant simply
7374 * convert it to a one byte UTF8 character, because an
7375 * unicode character may need more that one byte in UTF8 */
7376 mono_mb_emit_ldarg (mb
, argnum
);
7379 case MARSHAL_ACTION_CONV_RESULT
:
7380 /* fixme: we need conversions here */
7381 mono_mb_emit_stloc (mb
, 3);
7392 emit_marshal_scalar (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7393 MonoMarshalSpec
*spec
, int conv_arg
,
7394 MonoType
**conv_arg_type
, MarshalAction action
)
7397 MonoMethodBuilder
*mb
= m
->mb
;
7400 case MARSHAL_ACTION_PUSH
:
7401 mono_mb_emit_ldarg (mb
, argnum
);
7404 case MARSHAL_ACTION_CONV_RESULT
:
7405 /* no conversions necessary */
7406 mono_mb_emit_stloc (mb
, 3);
7417 emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7418 MonoMarshalSpec
*spec
, int conv_arg
,
7419 MonoType
**conv_arg_type
, MarshalAction action
)
7421 /* Ensure that we have marshalling info for this param */
7422 mono_marshal_load_type_info (mono_class_from_mono_type (t
));
7424 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
7425 return emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7427 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
7428 return emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7431 case MONO_TYPE_VALUETYPE
:
7432 if (t
->data
.klass
== mono_defaults
.handleref_class
)
7433 return emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7435 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7436 case MONO_TYPE_STRING
:
7437 return emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7438 case MONO_TYPE_CLASS
:
7439 case MONO_TYPE_OBJECT
:
7440 #if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
7441 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
7442 return emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7445 #if !defined(DISABLE_COM)
7446 if (spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
7447 spec
->native
== MONO_NATIVE_IDISPATCH
||
7448 spec
->native
== MONO_NATIVE_INTERFACE
))
7449 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7450 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
7451 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
7452 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
7453 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7456 if (mono_class_try_get_safehandle_class () != NULL
&& t
->data
.klass
&&
7457 mono_class_is_subclass_of (t
->data
.klass
, mono_class_try_get_safehandle_class (), FALSE
))
7458 return emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7460 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7461 case MONO_TYPE_ARRAY
:
7462 case MONO_TYPE_SZARRAY
:
7463 return emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7464 case MONO_TYPE_BOOLEAN
:
7465 return emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7467 return emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7468 case MONO_TYPE_CHAR
:
7469 return emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7482 case MONO_TYPE_FNPTR
:
7483 return emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7484 case MONO_TYPE_GENERICINST
:
7485 if (mono_type_generic_inst_is_valuetype (t
))
7486 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7488 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7494 /* How the arguments of an icall should be wrapped */
7496 /* Don't wrap at all, pass the argument as is */
7497 ICALL_HANDLES_WRAP_NONE
,
7498 /* Wrap the argument in an object handle, pass the handle to the icall */
7499 ICALL_HANDLES_WRAP_OBJ
,
7500 /* Wrap the argument in an object handle, pass the handle to the icall,
7501 write the value out from the handle when the icall returns */
7502 ICALL_HANDLES_WRAP_OBJ_INOUT
,
7503 /* Wrap the argument (a valuetype reference) in a handle to pin its enclosing object,
7504 but pass the raw reference to the icall */
7505 ICALL_HANDLES_WRAP_VALUETYPE_REF
,
7509 IcallHandlesWrap wrap
;
7510 /* if wrap is NONE or OBJ or VALUETYPE_REF, this is not meaningful.
7511 if wrap is OBJ_INOUT it's the local var that holds the MonoObjectHandle.
7514 } IcallHandlesLocal
;
7517 * Describes how to wrap the given parameter.
7520 static IcallHandlesWrap
7521 signature_param_uses_handles (MonoMethodSignature
*sig
, int param
)
7523 if (MONO_TYPE_IS_REFERENCE (sig
->params
[param
])) {
7524 return mono_signature_param_is_out (sig
, param
) ? ICALL_HANDLES_WRAP_OBJ_INOUT
: ICALL_HANDLES_WRAP_OBJ
;
7525 } else if (mono_type_is_byref (sig
->params
[param
]))
7526 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
7528 return ICALL_HANDLES_WRAP_NONE
;
7534 * mono_marshal_emit_native_wrapper:
7535 * @image: the image to use for looking up custom marshallers
7536 * @sig: The signature of the native function
7537 * @piinfo: Marshalling information
7538 * @mspecs: Marshalling information
7539 * @aot: whenever the created method will be compiled by the AOT compiler
7540 * @method: if non-NULL, the pinvoke method to call
7541 * @check_exceptions: Whenever to check for pending exceptions after the native call
7542 * @func_param: the function to call is passed as a boxed IntPtr as the first parameter
7544 * generates IL code for the pinvoke wrapper, the generated code calls @func.
7547 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
)
7549 EmitMarshalContext m
;
7550 MonoMethodSignature
*csig
;
7552 int i
, argnum
, *tmp_locals
;
7553 int type
, param_shift
= 0;
7554 int coop_gc_stack_dummy
, coop_gc_var
;
7556 memset (&m
, 0, sizeof (m
));
7561 /* we copy the signature, so that we can set pinvoke to 0 */
7563 /* The function address is passed as the first argument */
7564 g_assert (!sig
->hasthis
);
7567 csig
= mono_metadata_signature_dup_full (mb
->method
->klass
->image
, sig
);
7575 /* we allocate local for use with emit_struct_conv() */
7576 /* allocate local 0 (pointer) src_ptr */
7577 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7578 /* allocate local 1 (pointer) dst_ptr */
7579 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7580 /* allocate local 2 (boolean) delete_old */
7581 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
7583 /* delete_old = FALSE */
7584 mono_mb_emit_icon (mb
, 0);
7585 mono_mb_emit_stloc (mb
, 2);
7587 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
7588 /* allocate local 3 to store the return value */
7589 mono_mb_add_local (mb
, sig
->ret
);
7592 if (mono_threads_is_coop_enabled ()) {
7593 /* local 4, dummy local used to get a stack address for suspend funcs */
7594 coop_gc_stack_dummy
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7595 /* local 5, the local to be used when calling the suspend funcs */
7596 coop_gc_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7600 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
7602 * ret = method (...);
7604 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
7611 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
7612 m
.vtaddr_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7614 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
7615 /* Return type custom marshaling */
7617 * Since we can't determine the return type of the unmanaged function,
7618 * we assume it returns a pointer, and pass that pointer to
7619 * MarshalNativeToManaged.
7621 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
7624 /* we first do all conversions */
7625 tmp_locals
= (int *)alloca (sizeof (int) * sig
->param_count
);
7626 m
.orig_conv_args
= (int *)alloca (sizeof (int) * (sig
->param_count
+ 1));
7628 for (i
= 0; i
< sig
->param_count
; i
++) {
7629 tmp_locals
[i
] = emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
7632 // In coop mode need to register blocking state during native call
7633 if (mono_threads_is_coop_enabled ()) {
7634 // Perform an extra, early lookup of the function address, so any exceptions
7635 // potentially resulting from the lookup occur before entering blocking mode.
7636 if (!func_param
&& !MONO_CLASS_IS_IMPORT (mb
->method
->klass
) && aot
) {
7637 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7638 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
7639 mono_mb_emit_byte (mb
, CEE_POP
); // Result not needed yet
7642 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
7643 mono_mb_emit_icall (mb
, mono_threads_enter_gc_safe_region_unbalanced
);
7644 mono_mb_emit_stloc (mb
, coop_gc_var
);
7647 /* push all arguments */
7650 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7652 for (i
= 0; i
< sig
->param_count
; i
++) {
7653 emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
7656 /* call the native method */
7658 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7659 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_defaults
.int_class
);
7660 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7661 mono_mb_emit_calli (mb
, csig
);
7662 } else if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
7664 mono_mb_emit_cominterop_call (mb
, csig
, &piinfo
->method
);
7666 g_assert_not_reached ();
7670 /* Reuse the ICALL_ADDR opcode for pinvokes too */
7671 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7672 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
7673 mono_mb_emit_calli (mb
, csig
);
7675 mono_mb_emit_native_call (mb
, csig
, func
);
7679 /* Set LastError if needed */
7680 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
7683 static MonoMethodSignature
*get_last_error_sig
= NULL
;
7684 if (!get_last_error_sig
) {
7685 get_last_error_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
7686 get_last_error_sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
7687 get_last_error_sig
->pinvoke
= 1;
7691 * Have to call GetLastError () early and without a wrapper, since various runtime components could
7692 * clobber its value.
7694 mono_mb_emit_native_call (mb
, get_last_error_sig
, GetLastError
);
7695 mono_mb_emit_icall (mb
, mono_marshal_set_last_error_windows
);
7697 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7698 mono_mb_emit_byte (mb
, CEE_MONO_GET_LAST_ERROR
);
7699 mono_mb_emit_icall (mb
, mono_marshal_set_last_error_windows
);
7702 mono_mb_emit_icall (mb
, mono_marshal_set_last_error
);
7706 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
7707 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
7708 mono_class_init (klass
);
7709 if (!(mono_class_is_explicit_layout (klass
) || klass
->blittable
)) {
7710 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
7711 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
7712 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
7713 mono_mb_emit_stloc (mb
, m
.vtaddr_var
);
7717 /* Unblock before converting the result, since that can involve calls into the runtime */
7718 if (mono_threads_is_coop_enabled ()) {
7719 mono_mb_emit_ldloc (mb
, coop_gc_var
);
7720 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
7721 mono_mb_emit_icall (mb
, mono_threads_exit_gc_safe_region_unbalanced
);
7724 /* convert the result */
7725 if (!sig
->ret
->byref
) {
7726 MonoMarshalSpec
*spec
= mspecs
[0];
7727 type
= sig
->ret
->type
;
7729 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
7730 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
7734 case MONO_TYPE_VOID
:
7736 case MONO_TYPE_VALUETYPE
:
7737 klass
= sig
->ret
->data
.klass
;
7738 if (klass
->enumtype
) {
7739 type
= mono_class_enum_basetype (sig
->ret
->data
.klass
)->type
;
7742 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
7756 case MONO_TYPE_FNPTR
:
7757 case MONO_TYPE_STRING
:
7758 case MONO_TYPE_CLASS
:
7759 case MONO_TYPE_OBJECT
:
7760 case MONO_TYPE_BOOLEAN
:
7761 case MONO_TYPE_ARRAY
:
7762 case MONO_TYPE_SZARRAY
:
7763 case MONO_TYPE_CHAR
:
7765 case MONO_TYPE_GENERICINST
:
7766 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
7768 case MONO_TYPE_TYPEDBYREF
:
7770 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
7771 g_assert_not_reached ();
7775 mono_mb_emit_stloc (mb
, 3);
7779 * Need to call this after converting the result since MONO_VTADDR needs
7780 * to be adjacent to the call instruction.
7782 if (check_exceptions
)
7783 emit_thread_interrupt_checkpoint (mb
);
7785 /* we need to convert byref arguments back and free string arrays */
7786 for (i
= 0; i
< sig
->param_count
; i
++) {
7787 MonoType
*t
= sig
->params
[i
];
7788 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
7790 argnum
= i
+ param_shift
;
7792 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
7793 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
7798 case MONO_TYPE_STRING
:
7799 case MONO_TYPE_VALUETYPE
:
7800 case MONO_TYPE_CLASS
:
7801 case MONO_TYPE_OBJECT
:
7802 case MONO_TYPE_SZARRAY
:
7803 case MONO_TYPE_BOOLEAN
:
7804 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
7811 if (!MONO_TYPE_IS_VOID(sig
->ret
))
7812 mono_mb_emit_ldloc (mb
, 3);
7814 mono_mb_emit_byte (mb
, CEE_RET
);
7816 #endif /* DISABLE_JIT */
7819 * mono_marshal_get_native_wrapper:
7820 * @method: The MonoMethod to wrap.
7821 * @check_exceptions: Whenever to check for pending exceptions
7823 * generates IL code for the pinvoke wrapper (the generated method
7824 * calls the unmanaged code in piinfo->addr)
7827 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
7829 MonoMethodSignature
*sig
, *csig
;
7830 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
7831 MonoMethodBuilder
*mb
;
7832 MonoMarshalSpec
**mspecs
;
7835 gboolean pinvoke
= FALSE
;
7838 const char *exc_class
= "MissingMethodException";
7839 const char *exc_arg
= NULL
;
7842 g_assert (method
!= NULL
);
7843 g_assert (mono_method_signature (method
)->pinvoke
);
7845 GHashTable
**cache_ptr
;
7848 if (check_exceptions
)
7849 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_check_cache
;
7851 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_aot_cache
;
7853 if (check_exceptions
)
7854 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_check_cache
;
7856 cache_ptr
= &mono_method_get_wrapper_cache (method
)->native_wrapper_cache
;
7859 cache
= get_cache (cache_ptr
, mono_aligned_addr_hash
, NULL
);
7861 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
7864 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
7865 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
7869 return mono_cominterop_get_native_wrapper (method
);
7871 g_assert_not_reached ();
7875 sig
= mono_method_signature (method
);
7877 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
7878 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
7881 if (!piinfo
->addr
) {
7883 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
7884 exc_arg
= "Method contains unsupported native code";
7886 mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
7888 piinfo
->addr
= mono_lookup_internal_call (method
);
7892 /* hack - redirect certain string constructors to CreateString */
7893 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
7894 g_assert (!pinvoke
);
7895 g_assert (method
->string_ctor
);
7896 g_assert (sig
->hasthis
);
7898 /* CreateString returns a value */
7899 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7900 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
7904 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
7905 if (!strcmp ("CreateString", res
->name
) &&
7906 mono_metadata_signature_equal (csig
, mono_method_signature (res
))) {
7909 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
7910 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
7912 /* create a wrapper to preserve .ctor in stack trace */
7913 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
7916 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7917 for (i
= 1; i
<= csig
->param_count
; i
++)
7918 mono_mb_emit_ldarg (mb
, i
);
7919 mono_mb_emit_managed_call (mb
, res
, NULL
);
7920 mono_mb_emit_byte (mb
, CEE_RET
);
7923 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRING_CTOR
);
7924 info
->d
.string_ctor
.method
= method
;
7926 /* use native_wrapper_cache because internal calls are looked up there */
7927 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
7928 csig
->param_count
+ 1, info
, NULL
);
7935 /* exception will be thrown */
7936 piinfo
->addr
= NULL
;
7937 g_warning ("cannot find CreateString for .ctor");
7940 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
7942 mb
->method
->save_lmf
= 1;
7945 * In AOT mode and embedding scenarios, it is possible that the icall is not
7946 * registered in the runtime doing the AOT compilation.
7948 if (!piinfo
->addr
&& !aot
) {
7950 mono_mb_emit_exception (mb
, exc_class
, exc_arg
);
7952 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
7953 info
->d
.managed_to_native
.method
= method
;
7955 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7957 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
,
7958 csig
->param_count
+ 16, info
, NULL
);
7964 /* internal calls: we simply push all arguments and call the method (no conversions) */
7965 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
7967 csig
= mono_metadata_signature_dup_add_this (method
->klass
->image
, sig
, method
->klass
);
7969 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
7971 //printf ("%s\n", mono_method_full_name (method, 1));
7973 /* hack - string constructors returns a value */
7974 if (method
->string_ctor
)
7975 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
7979 MonoClass
*handle_stack_mark_class
;
7980 MonoClass
*error_class
;
7981 int thread_info_var
= -1, stack_mark_var
= -1, error_var
= -1;
7982 MonoMethodSignature
*call_sig
= csig
;
7983 gboolean uses_handles
= FALSE
;
7984 gboolean save_handles_to_locals
= FALSE
;
7985 IcallHandlesLocal
*handles_locals
= NULL
;
7986 (void) mono_lookup_internal_call_full (method
, &uses_handles
);
7989 /* If it uses handles and MonoError, it had better check exceptions */
7990 g_assert (!uses_handles
|| check_exceptions
);
7993 MonoMethodSignature
*ret
;
7995 /* Add a MonoError argument and figure out which args need to be wrapped in handles */
7996 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
7997 ret
= mono_metadata_signature_alloc (method
->klass
->image
, csig
->param_count
+ 1);
7999 ret
->param_count
= csig
->param_count
+ 1;
8000 ret
->ret
= csig
->ret
;
8002 handles_locals
= g_new0 (IcallHandlesLocal
, csig
->param_count
);
8003 for (int i
= 0; i
< csig
->param_count
; ++i
) {
8004 IcallHandlesWrap w
= signature_param_uses_handles (csig
, i
);
8005 handles_locals
[i
].wrap
= w
;
8007 case ICALL_HANDLES_WRAP_OBJ
:
8008 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
8009 ret
->params
[i
] = mono_class_get_byref_type (mono_class_from_mono_type(csig
->params
[i
]));
8010 if (w
== ICALL_HANDLES_WRAP_OBJ_INOUT
)
8011 save_handles_to_locals
= TRUE
;
8013 case ICALL_HANDLES_WRAP_NONE
:
8014 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
8015 ret
->params
[i
] = csig
->params
[i
];
8018 g_assert_not_reached ();
8021 /* Add MonoError* param */
8022 ret
->params
[csig
->param_count
] = &mono_get_intptr_class ()->byval_arg
;
8023 ret
->pinvoke
= csig
->pinvoke
;
8029 handle_stack_mark_class
= mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
8030 error_class
= mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
8032 thread_info_var
= mono_mb_add_local (mb
, &mono_get_intptr_class ()->byval_arg
);
8033 stack_mark_var
= mono_mb_add_local (mb
, &handle_stack_mark_class
->byval_arg
);
8034 error_var
= mono_mb_add_local (mb
, &error_class
->byval_arg
);
8036 if (save_handles_to_locals
) {
8037 /* add a local var to hold the handles for each out arg */
8038 for (int i
= 0; i
< sig
->param_count
; ++i
) {
8039 int j
= i
+ sig
->hasthis
;
8040 switch (handles_locals
[j
].wrap
) {
8041 case ICALL_HANDLES_WRAP_NONE
:
8042 case ICALL_HANDLES_WRAP_OBJ
:
8043 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
8044 handles_locals
[j
].handle
= -1;
8046 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
8047 handles_locals
[j
].handle
= mono_mb_add_local (mb
, sig
->params
[i
]);
8050 g_assert_not_reached ();
8060 * Add a null check since public icalls can be called with 'call' which
8061 * does no such check.
8063 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8064 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
8065 mono_mb_emit_exception (mb
, "NullReferenceException", NULL
);
8066 mono_mb_patch_branch (mb
, pos
);
8070 mono_mb_emit_ldloc_addr (mb
, stack_mark_var
);
8071 mono_mb_emit_ldloc_addr (mb
, error_var
);
8072 mono_mb_emit_icall (mb
, mono_icall_start
);
8073 mono_mb_emit_stloc (mb
, thread_info_var
);
8076 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8077 /* TODO support adding wrappers to non-static struct methods */
8078 g_assert (!mono_class_is_valuetype(mono_method_get_class (method
)));
8079 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
8080 mono_mb_emit_icall (mb
, mono_handle_new_full
);
8082 for (i
= 0; i
< sig
->param_count
; i
++) {
8083 /* load each argument. references into the managed heap get wrapped in handles */
8084 int j
= i
+ sig
->hasthis
;
8085 switch (handles_locals
[j
].wrap
) {
8086 case ICALL_HANDLES_WRAP_NONE
:
8087 mono_mb_emit_ldarg (mb
, j
);
8089 case ICALL_HANDLES_WRAP_OBJ
:
8090 /* argI = mono_handle_new_full (argI_raw, FALSE) */
8091 mono_mb_emit_ldarg (mb
, j
);
8092 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
8093 mono_mb_emit_icall (mb
, mono_handle_new_full
);
8095 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
8096 /* handleI = argI = mono_handle_new_full (NULL, FALSE) */
8097 mono_mb_emit_byte (mb
, CEE_LDNULL
);
8098 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
8099 mono_mb_emit_icall (mb
, mono_handle_new_full
);
8101 mono_mb_emit_byte (mb
, CEE_DUP
);
8103 mono_mb_emit_stloc (mb
, handles_locals
[j
].handle
);
8105 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
8106 /* (void) mono_handle_new_full (argI, TRUE); argI */
8107 mono_mb_emit_ldarg (mb
, j
);
8108 mono_mb_emit_byte (mb
, CEE_DUP
);
8109 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
8110 mono_mb_emit_icall (mb
, mono_handle_new_full
);
8111 mono_mb_emit_byte (mb
, CEE_POP
);
8113 fprintf (stderr
, " Method %s.%s.%s has byref valuetype argument %d\n", method
->klass
->name_space
, method
->klass
->name
, method
->name
, i
);
8117 g_assert_not_reached ();
8120 mono_mb_emit_ldloc_addr (mb
, error_var
);
8123 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8124 for (i
= 0; i
< sig
->param_count
; i
++)
8125 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
8129 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8130 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
8131 mono_mb_emit_calli (mb
, call_sig
);
8133 g_assert (piinfo
->addr
);
8134 mono_mb_emit_native_call (mb
, call_sig
, piinfo
->addr
);
8138 if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
8139 // if (ret != NULL_HANDLE) {
8140 // ret = MONO_HANDLE_RAW(ret)
8142 mono_mb_emit_byte (mb
, CEE_DUP
);
8143 int pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8144 mono_mb_emit_ldflda (mb
, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject
));
8145 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
8146 mono_mb_patch_branch (mb
, pos
);
8148 if (save_handles_to_locals
) {
8149 for (i
= 0; i
< sig
->param_count
; i
++) {
8150 int j
= i
+ sig
->hasthis
;
8151 switch (handles_locals
[j
].wrap
) {
8152 case ICALL_HANDLES_WRAP_NONE
:
8153 case ICALL_HANDLES_WRAP_OBJ
:
8154 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
8156 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
8157 /* *argI_raw = MONO_HANDLE_RAW (handleI) */
8160 mono_mb_emit_ldarg (mb
, j
);
8162 mono_mb_emit_ldloc (mb
, handles_locals
[j
].handle
);
8163 /* MONO_HANDLE_RAW(handleI) */
8164 mono_mb_emit_ldflda (mb
, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject
));
8165 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
8166 /* *argI_raw = MONO_HANDLE_RAW(handleI) */
8167 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
8170 g_assert_not_reached ();
8174 g_free (handles_locals
);
8176 mono_mb_emit_ldloc (mb
, thread_info_var
);
8177 mono_mb_emit_ldloc_addr (mb
, stack_mark_var
);
8178 mono_mb_emit_ldloc_addr (mb
, error_var
);
8179 mono_mb_emit_icall (mb
, mono_icall_end
);
8182 if (check_exceptions
)
8183 emit_thread_interrupt_checkpoint (mb
);
8184 mono_mb_emit_byte (mb
, CEE_RET
);
8186 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
8187 info
->d
.managed_to_native
.method
= method
;
8189 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, csig
);
8191 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
8200 g_assert (piinfo
->addr
);
8203 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
8204 mono_method_get_marshal_info (method
, mspecs
);
8206 mono_marshal_emit_native_wrapper (mb
->method
->klass
->image
, mb
, sig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
, FALSE
);
8208 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PINVOKE
);
8209 info
->d
.managed_to_native
.method
= method
;
8211 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
8213 res
= mono_mb_create_and_cache_full (cache
, method
, mb
, csig
, csig
->param_count
+ 16,
8218 for (i
= sig
->param_count
; i
>= 0; i
--)
8220 mono_metadata_free_marshal_spec (mspecs
[i
]);
8224 /* mono_method_print_code (res); */
8230 * mono_marshal_get_native_func_wrapper:
8231 * @image: The image to use for memory allocation and for looking up custom marshallers.
8232 * @sig: The signature of the function
8233 * @func: The native function to wrap
8235 * Returns a wrapper method around native functions, similar to the pinvoke
8239 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
8240 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
8242 MonoMethodSignature
*csig
;
8244 SignaturePointerPair key
, *new_key
;
8245 MonoMethodBuilder
*mb
;
8254 // Generic types are not safe to place in MonoImage caches.
8255 g_assert (!sig
->is_inflated
);
8257 cache
= get_cache (&image
->native_func_wrapper_cache
, signature_pointer_pair_hash
, signature_pointer_pair_equal
);
8258 if ((res
= mono_marshal_find_in_cache (cache
, &key
)))
8261 name
= g_strdup_printf ("wrapper_native_%p", func
);
8262 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8263 mb
->method
->save_lmf
= 1;
8266 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
, FALSE
);
8269 csig
= mono_metadata_signature_dup_full (image
, sig
);
8272 new_key
= g_new (SignaturePointerPair
,1);
8273 new_key
->sig
= csig
;
8274 new_key
->pointer
= func
;
8276 res
= mono_mb_create_and_cache_full (cache
, new_key
, mb
, csig
, csig
->param_count
+ 16, NULL
, &found
);
8282 mono_marshal_set_wrapper_info (res
, NULL
);
8288 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
8292 mono_marshal_get_native_func_wrapper_aot (MonoClass
*klass
)
8294 MonoMethodSignature
*sig
, *csig
;
8295 MonoMethodBuilder
*mb
;
8300 MonoMethodPInvoke mpiinfo
;
8301 MonoMethodPInvoke
*piinfo
= &mpiinfo
;
8302 MonoMarshalSpec
**mspecs
;
8303 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
8304 MonoImage
*image
= invoke
->klass
->image
;
8307 // FIXME: include UnmanagedFunctionPointerAttribute info
8310 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
8312 cache
= get_cache (&mono_method_get_wrapper_cache (invoke
)->native_func_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
8314 if ((res
= mono_marshal_find_in_cache (cache
, invoke
)))
8317 memset (&mpiinfo
, 0, sizeof (mpiinfo
));
8318 parse_unmanaged_function_pointer_attr (klass
, &mpiinfo
);
8320 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
8321 mono_method_get_marshal_info (invoke
, mspecs
);
8322 /* Freed below so don't alloc from mempool */
8323 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
8326 name
= g_strdup_printf ("wrapper_aot_native");
8327 mb
= mono_mb_new (invoke
->klass
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8328 mb
->method
->save_lmf
= 1;
8331 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, NULL
, FALSE
, TRUE
, TRUE
);
8334 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT
);
8335 info
->d
.managed_to_native
.method
= invoke
;
8337 g_assert (!sig
->hasthis
);
8338 csig
= mono_metadata_signature_dup_add_this (image
, sig
, mono_defaults
.object_class
);
8340 res
= mono_mb_create_and_cache_full (cache
, invoke
,
8341 mb
, csig
, csig
->param_count
+ 16,
8345 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
8347 mono_metadata_free_marshal_spec (mspecs
[i
]);
8355 * mono_marshal_emit_managed_wrapper:
8357 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
8358 * the delegate which wraps the managed method to be called. For closed delegates,
8359 * it could have fewer parameters than the method it wraps.
8360 * THIS_LOC is the memory location where the target of the delegate is stored.
8363 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
8366 MonoMethodSignature
*sig
, *csig
;
8372 /* we first do all conversions */
8373 for (i
= 0; i
< sig
->param_count
; i
++) {
8374 MonoType
*t
= sig
->params
[i
];
8377 case MONO_TYPE_OBJECT
:
8378 case MONO_TYPE_CLASS
:
8379 case MONO_TYPE_VALUETYPE
:
8380 case MONO_TYPE_ARRAY
:
8381 case MONO_TYPE_SZARRAY
:
8382 case MONO_TYPE_STRING
:
8383 case MONO_TYPE_BOOLEAN
:
8384 emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
8388 if (!sig
->ret
->byref
) {
8389 switch (sig
->ret
->type
) {
8390 case MONO_TYPE_STRING
:
8391 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8398 MonoMethodSignature
*sig
, *csig
;
8399 MonoExceptionClause
*clauses
, *clause_finally
, *clause_catch
;
8400 int i
, *tmp_locals
, ex_local
, e_local
, attach_cookie_local
, attach_dummy_local
;
8401 int leave_try_pos
, leave_catch_pos
, ex_m1_pos
;
8402 gboolean closed
= FALSE
;
8407 /* allocate local 0 (pointer) src_ptr */
8408 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8409 /* allocate local 1 (pointer) dst_ptr */
8410 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8411 /* allocate local 2 (boolean) delete_old */
8412 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
8414 if (!sig
->hasthis
&& sig
->param_count
!= invoke_sig
->param_count
) {
8415 /* Closed delegate */
8416 g_assert (sig
->param_count
== invoke_sig
->param_count
+ 1);
8418 /* Use a new signature without the first argument */
8419 sig
= mono_metadata_signature_dup (sig
);
8420 memmove (&sig
->params
[0], &sig
->params
[1], (sig
->param_count
- 1) * sizeof (MonoType
*));
8421 sig
->param_count
--;
8424 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
8425 /* allocate local 3 to store the return value */
8426 mono_mb_add_local (mb
, sig
->ret
);
8429 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
8430 m
->vtaddr_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8432 ex_local
= mono_mb_add_local (mb
, &mono_defaults
.uint32_class
->byval_arg
);
8433 e_local
= mono_mb_add_local (mb
, &mono_defaults
.exception_class
->byval_arg
);
8435 attach_cookie_local
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8436 attach_dummy_local
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8441 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
8442 * mono_threads_attach_coop ();
8446 * ret = method (...);
8447 * } catch (Exception e) {
8448 * ex = mono_gchandle_new (e, false);
8450 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
8451 * mono_threads_detach_coop ();
8454 * mono_marshal_ftnptr_eh_callback (ex);
8460 clauses
= g_new0 (MonoExceptionClause
, 2);
8462 clause_catch
= &clauses
[0];
8463 clause_catch
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
8464 clause_catch
->data
.catch_class
= mono_defaults
.exception_class
;
8466 clause_finally
= &clauses
[1];
8467 clause_finally
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
8469 mono_mb_emit_icon (mb
, 0);
8470 mono_mb_emit_stloc (mb
, 2);
8472 mono_mb_emit_icon (mb
, -1);
8473 mono_mb_emit_byte (mb
, CEE_CONV_U4
);
8474 mono_mb_emit_stloc (mb
, ex_local
);
8477 clause_catch
->try_offset
= clause_finally
->try_offset
= mono_mb_get_label (mb
);
8479 if (!mono_threads_is_coop_enabled ()) {
8480 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8481 mono_mb_emit_byte (mb
, CEE_MONO_JIT_ATTACH
);
8483 /* mono_threads_attach_coop (); */
8484 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8485 mono_mb_emit_byte (mb
, CEE_MONO_LDDOMAIN
);
8486 mono_mb_emit_ldloc_addr (mb
, attach_dummy_local
);
8487 mono_mb_emit_icall (mb
, mono_threads_attach_coop
);
8488 mono_mb_emit_stloc (mb
, attach_cookie_local
);
8491 /* <interrupt check> */
8492 emit_thread_interrupt_checkpoint (mb
);
8494 /* we first do all conversions */
8495 tmp_locals
= (int *)alloca (sizeof (int) * sig
->param_count
);
8496 for (i
= 0; i
< sig
->param_count
; i
++) {
8497 MonoType
*t
= sig
->params
[i
];
8500 case MONO_TYPE_OBJECT
:
8501 case MONO_TYPE_CLASS
:
8502 case MONO_TYPE_VALUETYPE
:
8503 case MONO_TYPE_ARRAY
:
8504 case MONO_TYPE_SZARRAY
:
8505 case MONO_TYPE_STRING
:
8506 case MONO_TYPE_BOOLEAN
:
8507 tmp_locals
[i
] = emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
8517 if (target_handle
) {
8518 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
8519 mono_mb_emit_icall (mb
, mono_gchandle_get_target
);
8522 g_assert_not_reached ();
8524 } else if (closed
) {
8525 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
8526 mono_mb_emit_icall (mb
, mono_gchandle_get_target
);
8529 for (i
= 0; i
< sig
->param_count
; i
++) {
8530 MonoType
*t
= sig
->params
[i
];
8532 if (tmp_locals
[i
]) {
8534 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
8536 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
8539 mono_mb_emit_ldarg (mb
, i
);
8542 /* ret = method (...) */
8543 mono_mb_emit_managed_call (mb
, method
, NULL
);
8545 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
8546 MonoClass
*klass
= mono_class_from_mono_type (sig
->ret
);
8547 mono_class_init (klass
);
8548 if (!(mono_class_is_explicit_layout (klass
) || klass
->blittable
)) {
8549 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
8550 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8551 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
8552 mono_mb_emit_stloc (mb
, m
->vtaddr_var
);
8556 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
8557 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8558 } else if (!sig
->ret
->byref
) {
8559 switch (sig
->ret
->type
) {
8560 case MONO_TYPE_VOID
:
8562 case MONO_TYPE_BOOLEAN
:
8565 case MONO_TYPE_CHAR
:
8577 case MONO_TYPE_OBJECT
:
8578 mono_mb_emit_stloc (mb
, 3);
8580 case MONO_TYPE_STRING
:
8581 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8582 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8584 case MONO_TYPE_VALUETYPE
:
8585 case MONO_TYPE_CLASS
:
8586 case MONO_TYPE_SZARRAY
:
8587 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8590 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
8591 g_assert_not_reached ();
8594 mono_mb_emit_stloc (mb
, 3);
8597 /* Convert byref arguments back */
8598 for (i
= 0; i
< sig
->param_count
; i
++) {
8599 MonoType
*t
= sig
->params
[i
];
8600 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
8602 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
8603 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8605 else if (t
->byref
) {
8607 case MONO_TYPE_CLASS
:
8608 case MONO_TYPE_VALUETYPE
:
8609 case MONO_TYPE_OBJECT
:
8610 case MONO_TYPE_STRING
:
8611 case MONO_TYPE_BOOLEAN
:
8612 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8618 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
8619 /* The [Out] information is encoded in the delegate signature */
8621 case MONO_TYPE_SZARRAY
:
8622 case MONO_TYPE_CLASS
:
8623 case MONO_TYPE_VALUETYPE
:
8624 emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8627 g_assert_not_reached ();
8632 leave_try_pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
8636 /* catch (Exception e) { */
8637 clause_catch
->try_len
= mono_mb_get_label (mb
) - clause_catch
->try_offset
;
8638 clause_catch
->handler_offset
= mono_mb_get_label (mb
);
8640 mono_mb_emit_stloc (mb
, e_local
);
8642 /* ex = mono_gchandle_new (e, false); */
8643 mono_mb_emit_ldloc (mb
, e_local
);
8644 mono_mb_emit_icon (mb
, 0);
8645 mono_mb_emit_icall (mb
, mono_gchandle_new
);
8646 mono_mb_emit_stloc (mb
, ex_local
);
8648 leave_catch_pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
8651 clause_catch
->handler_len
= mono_mb_get_pos (mb
) - clause_catch
->handler_offset
;
8654 clause_finally
->try_len
= mono_mb_get_label (mb
) - clause_finally
->try_offset
;
8655 clause_finally
->handler_offset
= mono_mb_get_label (mb
);
8657 if (!mono_threads_is_coop_enabled ()) {
8658 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8659 mono_mb_emit_byte (mb
, CEE_MONO_JIT_DETACH
);
8661 /* mono_threads_detach_coop (); */
8662 mono_mb_emit_ldloc (mb
, attach_cookie_local
);
8663 mono_mb_emit_ldloc_addr (mb
, attach_dummy_local
);
8664 mono_mb_emit_icall (mb
, mono_threads_detach_coop
);
8668 mono_mb_emit_ldloc (mb
, ex_local
);
8669 mono_mb_emit_icon (mb
, -1);
8670 mono_mb_emit_byte (mb
, CEE_CONV_U4
);
8671 ex_m1_pos
= mono_mb_emit_branch (mb
, CEE_BEQ
);
8673 /* mono_marshal_ftnptr_eh_callback (ex) */
8674 mono_mb_emit_ldloc (mb
, ex_local
);
8675 mono_mb_emit_icall (mb
, mono_marshal_ftnptr_eh_callback
);
8678 mono_mb_patch_branch (mb
, ex_m1_pos
);
8680 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
8682 /* } [endfinally] */
8683 clause_finally
->handler_len
= mono_mb_get_pos (mb
) - clause_finally
->handler_offset
;
8685 mono_mb_patch_branch (mb
, leave_try_pos
);
8686 mono_mb_patch_branch (mb
, leave_catch_pos
);
8689 if (m
->retobj_var
) {
8690 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
8691 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8692 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
8695 if (!MONO_TYPE_IS_VOID(sig
->ret
))
8696 mono_mb_emit_ldloc (mb
, 3);
8697 mono_mb_emit_byte (mb
, CEE_RET
);
8700 mono_mb_set_clauses (mb
, 2, clauses
);
8708 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
)
8710 MonoMethodSignature
*sig
;
8715 * Under windows, delegates passed to native code must use the STDCALL
8716 * calling convention.
8718 csig
->call_convention
= MONO_CALL_STDCALL
;
8721 sig
= mono_method_signature (method
);
8723 /* Change default calling convention if needed */
8724 /* Why is this a modopt ? */
8725 if (sig
->ret
&& sig
->ret
->num_mods
) {
8726 for (i
= 0; i
< sig
->ret
->num_mods
; ++i
) {
8728 MonoClass
*cmod_class
= mono_class_get_checked (method
->klass
->image
, sig
->ret
->modifiers
[i
].token
, &error
);
8729 g_assert (mono_error_ok (&error
));
8730 if ((cmod_class
->image
== mono_defaults
.corlib
) && !strcmp (cmod_class
->name_space
, "System.Runtime.CompilerServices")) {
8731 if (!strcmp (cmod_class
->name
, "CallConvCdecl"))
8732 csig
->call_convention
= MONO_CALL_C
;
8733 else if (!strcmp (cmod_class
->name
, "CallConvStdcall"))
8734 csig
->call_convention
= MONO_CALL_STDCALL
;
8735 else if (!strcmp (cmod_class
->name
, "CallConvFastcall"))
8736 csig
->call_convention
= MONO_CALL_FASTCALL
;
8737 else if (!strcmp (cmod_class
->name
, "CallConvThiscall"))
8738 csig
->call_convention
= MONO_CALL_THISCALL
;
8745 * generates IL code to call managed methods from unmanaged code
8746 * If target_handle==0, the wrapper info will be a WrapperInfo structure.
8749 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
, MonoError
*error
)
8751 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
8752 MonoMethodBuilder
*mb
;
8753 MonoMethod
*res
, *invoke
;
8754 MonoMarshalSpec
**mspecs
;
8755 MonoMethodPInvoke piinfo
;
8758 EmitMarshalContext m
;
8760 g_assert (method
!= NULL
);
8763 if (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) {
8764 mono_error_set_invalid_program (error
, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method
, TRUE
));
8769 * FIXME: Should cache the method+delegate type pair, since the same method
8770 * could be called with different delegates, thus different marshalling
8773 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
8775 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
8778 invoke
= mono_get_delegate_invoke (delegate_klass
);
8779 invoke_sig
= mono_method_signature (invoke
);
8781 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
8782 mono_method_get_marshal_info (invoke
, mspecs
);
8784 sig
= mono_method_signature (method
);
8786 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8788 /*the target gchandle must be the first entry after size and the wrapper itself.*/
8789 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
8791 /* we copy the signature, so that we can modify it */
8793 /* Need to free this later */
8794 csig
= mono_metadata_signature_dup (invoke_sig
);
8796 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, invoke_sig
);
8800 memset (&m
, 0, sizeof (m
));
8806 m
.image
= method
->klass
->image
;
8808 mono_marshal_set_callconv_from_modopt (invoke
, csig
);
8810 /* The attribute is only available in Net 2.0 */
8811 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
8812 MonoCustomAttrInfo
*cinfo
;
8813 MonoCustomAttrEntry
*attr
;
8816 * The pinvoke attributes are stored in a real custom attribute. Obtain the
8817 * contents of the attribute without constructing it, as that might not be
8818 * possible when running in cross-compiling mode.
8820 cinfo
= mono_custom_attrs_from_class_checked (delegate_klass
, error
);
8821 mono_error_assert_ok (error
);
8824 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
8825 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
8826 if (mono_class_has_parent (ctor_class
, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
8827 attr
= &cinfo
->attrs
[i
];
8833 MonoArray
*typed_args
, *named_args
;
8834 CattrNamedArg
*arginfo
;
8838 MonoBoolean set_last_error
= 0;
8841 mono_reflection_create_custom_attr_data_args (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
, &error
);
8842 g_assert (mono_error_ok (&error
));
8843 g_assert (mono_array_length (typed_args
) == 1);
8846 o
= mono_array_get (typed_args
, MonoObject
*, 0);
8847 call_conv
= *(gint32
*)mono_object_unbox (o
);
8850 for (i
= 0; i
< mono_array_length (named_args
); ++i
) {
8851 CattrNamedArg
*narg
= &arginfo
[i
];
8853 o
= mono_array_get (named_args
, MonoObject
*, i
);
8855 g_assert (narg
->field
);
8856 if (!strcmp (narg
->field
->name
, "CharSet")) {
8857 charset
= *(gint32
*)mono_object_unbox (o
);
8858 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
8859 set_last_error
= *(MonoBoolean
*)mono_object_unbox (o
);
8860 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
8861 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox (o);
8862 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
8863 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox (o);
8865 g_assert_not_reached ();
8871 memset (&piinfo
, 0, sizeof (piinfo
));
8873 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
8875 csig
->call_convention
= call_conv
- 1;
8878 if (cinfo
&& !cinfo
->cached
)
8879 mono_custom_attrs_free (cinfo
);
8882 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
8884 if (!target_handle
) {
8887 // FIXME: Associate it with the method+delegate_klass pair
8888 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
8889 info
->d
.native_to_managed
.method
= method
;
8890 info
->d
.native_to_managed
.klass
= delegate_klass
;
8892 res
= mono_mb_create_and_cache_full (cache
, method
,
8893 mb
, csig
, sig
->param_count
+ 16,
8899 res
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
8903 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
8905 mono_metadata_free_marshal_spec (mspecs
[i
]);
8908 /* mono_method_print_code (res); */
8914 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
8918 MonoMethodSignature
*sig
;
8919 MonoMethodBuilder
*mb
;
8924 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, &error
);
8926 g_error ("Could not load vtfixup token 0x%x due to %s", token
, mono_error_get_message (&error
));
8929 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
8930 MonoMethodSignature
*csig
;
8931 MonoMarshalSpec
**mspecs
;
8932 EmitMarshalContext m
;
8934 sig
= mono_method_signature (method
);
8935 g_assert (!sig
->hasthis
);
8937 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
8938 mono_method_get_marshal_info (method
, mspecs
);
8940 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8941 csig
= mono_metadata_signature_dup_full (image
, sig
);
8945 memset (&m
, 0, sizeof (m
));
8953 mono_marshal_set_callconv_from_modopt (method
, csig
);
8955 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
8957 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
8962 method
= mono_mb_create (mb
, csig
, sig
->param_count
+ 16, NULL
);
8965 for (i
= sig
->param_count
; i
>= 0; i
--)
8967 mono_metadata_free_marshal_spec (mspecs
[i
]);
8970 gpointer compiled_ptr
= mono_compile_method_checked (method
, &error
);
8971 mono_error_assert_ok (&error
);
8972 return compiled_ptr
;
8975 sig
= mono_method_signature (method
);
8976 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
8978 param_count
= sig
->param_count
+ sig
->hasthis
;
8980 for (i
= 0; i
< param_count
; i
++)
8981 mono_mb_emit_ldarg (mb
, i
);
8983 if (type
& VTFIXUP_TYPE_CALL_MOST_DERIVED
)
8984 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
8986 mono_mb_emit_op (mb
, CEE_CALL
, method
);
8987 mono_mb_emit_byte (mb
, CEE_RET
);
8992 method
= mono_mb_create (mb
, sig
, param_count
, NULL
);
8995 gpointer compiled_ptr
= mono_compile_method_checked (method
, &error
);
8996 mono_error_assert_ok (&error
);
8997 return compiled_ptr
;
9003 * The code directly following this is the cache hit, value positive branch
9005 * This function takes a new method builder with 0 locals and adds two locals
9006 * to create multiple out-branches and the fall through state of having the object
9007 * on the stack after a cache miss
9010 generate_check_cache (int obj_arg_position
, int class_arg_position
, int cache_arg_position
, // In-parameters
9011 int *null_obj
, int *cache_hit_neg
, int *cache_hit_pos
, // Out-parameters
9012 MonoMethodBuilder
*mb
)
9016 /* allocate local 0 (pointer) obj_vtable */
9017 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9018 /* allocate local 1 (pointer) cached_vtable */
9019 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9022 mono_mb_emit_ldarg (mb
, obj_arg_position
);
9023 *null_obj
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9025 /*obj_vtable = obj->vtable;*/
9026 mono_mb_emit_ldarg (mb
, obj_arg_position
);
9027 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
9028 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9029 mono_mb_emit_stloc (mb
, 0);
9031 /* cached_vtable = *cache*/
9032 mono_mb_emit_ldarg (mb
, cache_arg_position
);
9033 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9034 mono_mb_emit_stloc (mb
, 1);
9036 mono_mb_emit_ldloc (mb
, 1);
9037 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
9038 mono_mb_emit_i4 (mb
, ~0x1);
9039 mono_mb_emit_byte (mb
, CEE_CONV_I
);
9040 mono_mb_emit_byte (mb
, CEE_AND
);
9041 mono_mb_emit_ldloc (mb
, 0);
9042 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
9043 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9045 /*return (cached_vtable & 0x1) ? NULL : obj;*/
9046 mono_mb_emit_ldloc (mb
, 1);
9047 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
9048 mono_mb_emit_byte (mb
, CEE_CONV_U
);
9049 mono_mb_emit_byte (mb
, CEE_AND
);
9050 *cache_hit_neg
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
9051 *cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BR
);
9054 mono_mb_patch_branch (mb
, cache_miss_pos
);
9057 mono_mb_emit_ldarg (mb
, obj_arg_position
);
9058 mono_mb_emit_ldarg (mb
, class_arg_position
);
9059 mono_mb_emit_ldarg (mb
, cache_arg_position
);
9060 mono_mb_emit_icall (mb
, mono_marshal_isinst_with_cache
);
9063 #endif /* DISABLE_JIT */
9066 * This does the equivalent of mono_object_castclass_with_cache.
9069 mono_marshal_get_castclass_with_cache (void)
9071 static MonoMethod
*cached
;
9073 MonoMethodBuilder
*mb
;
9074 MonoMethodSignature
*sig
;
9075 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
, invalid_cast_pos
;
9078 const int obj_arg_position
= 0;
9079 const int class_arg_position
= 1;
9080 const int cache_arg_position
= 2;
9085 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
9086 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
9087 sig
->params
[obj_arg_position
] = &mono_defaults
.object_class
->byval_arg
;
9088 sig
->params
[class_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
9089 sig
->params
[cache_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
9090 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9094 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
9095 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
9096 invalid_cast_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9099 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
9100 mono_mb_emit_ldarg (mb
, obj_arg_position
);
9101 mono_mb_emit_byte (mb
, CEE_RET
);
9104 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
9105 mono_mb_patch_branch (mb
, invalid_cast_pos
);
9106 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
9109 mono_mb_patch_branch (mb
, return_null_pos
);
9110 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9111 mono_mb_emit_byte (mb
, CEE_RET
);
9112 #endif /* DISABLE_JIT */
9114 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE
);
9115 res
= mono_mb_create (mb
, sig
, 8, info
);
9118 if (InterlockedCompareExchangePointer ((volatile gpointer
*)&cached
, res
, NULL
)) {
9119 mono_free_method (res
);
9120 mono_metadata_free_method_signature (sig
);
9127 /* this is an icall */
9129 mono_marshal_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, uintptr_t *cache
)
9132 MonoObject
*isinst
= mono_object_isinst_checked (obj
, klass
, &error
);
9133 if (mono_error_set_pending_exception (&error
))
9136 if (mono_object_is_transparent_proxy (obj
))
9139 uintptr_t cache_update
= (uintptr_t)obj
->vtable
;
9141 cache_update
= cache_update
| 0x1;
9143 *cache
= cache_update
;
9149 * This does the equivalent of mono_object_isinst_with_cache.
9152 mono_marshal_get_isinst_with_cache (void)
9154 static MonoMethod
*cached
;
9156 MonoMethodBuilder
*mb
;
9157 MonoMethodSignature
*sig
;
9158 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
;
9161 const int obj_arg_position
= 0;
9162 const int class_arg_position
= 1;
9163 const int cache_arg_position
= 2;
9168 mb
= mono_mb_new (mono_defaults
.object_class
, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS
);
9169 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
9171 sig
->params
[obj_arg_position
] = &mono_defaults
.object_class
->byval_arg
;
9173 sig
->params
[class_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
9175 sig
->params
[cache_arg_position
] = &mono_defaults
.int_class
->byval_arg
;
9176 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9180 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
9181 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
9182 // Return the object gotten via the slow path.
9183 mono_mb_emit_byte (mb
, CEE_RET
);
9186 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
9187 mono_mb_patch_branch (mb
, return_null_pos
);
9188 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9189 mono_mb_emit_byte (mb
, CEE_RET
);
9192 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
9193 mono_mb_emit_ldarg (mb
, obj_arg_position
);
9194 mono_mb_emit_byte (mb
, CEE_RET
);
9197 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ISINST_WITH_CACHE
);
9198 res
= mono_mb_create (mb
, sig
, 8, info
);
9201 if (InterlockedCompareExchangePointer ((volatile gpointer
*)&cached
, res
, NULL
)) {
9202 mono_free_method (res
);
9203 mono_metadata_free_method_signature (sig
);
9211 * mono_marshal_get_struct_to_ptr:
9214 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
9217 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
9219 MonoMethodBuilder
*mb
;
9220 static MonoMethod
*stoptr
= NULL
;
9224 g_assert (klass
!= NULL
);
9226 mono_marshal_load_type_info (klass
);
9228 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
9229 if (marshal_info
->str_to_ptr
)
9230 return marshal_info
->str_to_ptr
;
9233 stoptr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "StructureToPtr", 3);
9236 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_UNKNOWN
);
9239 if (klass
->blittable
) {
9240 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9241 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9242 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9243 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9244 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9245 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9248 /* allocate local 0 (pointer) src_ptr */
9249 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9250 /* allocate local 1 (pointer) dst_ptr */
9251 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9252 /* allocate local 2 (boolean) delete_old */
9253 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
9254 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
9255 mono_mb_emit_stloc (mb
, 2);
9257 /* initialize src_ptr to point to the start of object data */
9258 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9259 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9260 mono_mb_emit_stloc (mb
, 0);
9262 /* initialize dst_ptr */
9263 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9264 mono_mb_emit_stloc (mb
, 1);
9266 emit_struct_conv (mb
, klass
, FALSE
);
9269 mono_mb_emit_byte (mb
, CEE_RET
);
9271 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR
);
9272 res
= mono_mb_create (mb
, mono_signature_no_pinvoke (stoptr
), 0, info
);
9275 mono_marshal_lock ();
9276 if (!marshal_info
->str_to_ptr
)
9277 marshal_info
->str_to_ptr
= res
;
9279 res
= marshal_info
->str_to_ptr
;
9280 mono_marshal_unlock ();
9285 * mono_marshal_get_ptr_to_struct:
9288 * generates IL code for PtrToStructure (IntPtr src, object structure)
9291 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
9293 MonoMethodBuilder
*mb
;
9294 static MonoMethodSignature
*ptostr
= NULL
;
9298 g_assert (klass
!= NULL
);
9300 mono_marshal_load_type_info (klass
);
9302 MonoMarshalType
*marshal_info
= mono_class_get_marshal_info (klass
);
9303 if (marshal_info
->ptr_to_str
)
9304 return marshal_info
->ptr_to_str
;
9307 MonoMethodSignature
*sig
;
9309 /* Create the signature corresponding to
9310 static void PtrToStructure (IntPtr ptr, object structure);
9311 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9312 sig
= mono_create_icall_signature ("void ptr object");
9313 sig
= mono_metadata_signature_dup_full (mono_defaults
.corlib
, sig
);
9315 mono_memory_barrier ();
9319 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_UNKNOWN
);
9322 if (klass
->blittable
) {
9323 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9324 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9325 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9326 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9327 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9328 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9331 /* allocate local 0 (pointer) src_ptr */
9332 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9333 /* allocate local 1 (pointer) dst_ptr */
9334 mono_mb_add_local (mb
, &klass
->this_arg
);
9336 /* initialize src_ptr to point to the start of object data */
9337 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9338 mono_mb_emit_stloc (mb
, 0);
9340 /* initialize dst_ptr */
9341 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9342 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
9343 mono_mb_emit_stloc (mb
, 1);
9345 emit_struct_conv (mb
, klass
, TRUE
);
9348 mono_mb_emit_byte (mb
, CEE_RET
);
9350 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE
);
9351 res
= mono_mb_create (mb
, ptostr
, 0, info
);
9354 mono_marshal_lock ();
9355 if (!marshal_info
->ptr_to_str
)
9356 marshal_info
->ptr_to_str
= res
;
9358 res
= marshal_info
->ptr_to_str
;
9359 mono_marshal_unlock ();
9364 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
9365 * This is used to avoid infinite recursion since it is hard to determine where to
9366 * replace a method with its synchronized wrapper, and where not.
9367 * The runtime should execute METHOD instead of the wrapper.
9370 mono_marshal_get_synchronized_inner_wrapper (MonoMethod
*method
)
9372 MonoMethodBuilder
*mb
;
9374 MonoMethodSignature
*sig
;
9376 MonoGenericContext
*ctx
= NULL
;
9377 MonoGenericContainer
*container
= NULL
;
9379 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
9380 ctx
= &((MonoMethodInflated
*)method
)->context
;
9381 method
= ((MonoMethodInflated
*)method
)->declaring
;
9382 container
= mono_method_get_generic_container (method
);
9384 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
9385 g_assert (container
);
9388 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNKNOWN
);
9390 mono_mb_emit_exception_full (mb
, "System", "ExecutionEngineException", "Shouldn't be called.");
9391 mono_mb_emit_byte (mb
, CEE_RET
);
9393 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
9395 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
);
9396 info
->d
.synchronized_inner
.method
= method
;
9397 res
= mono_mb_create (mb
, sig
, 0, info
);
9401 res
= mono_class_inflate_generic_method_checked (res
, ctx
, &error
);
9402 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
9408 * generates IL code for the synchronized wrapper: the generated method
9409 * calls METHOD while locking 'this' or the parent type.
9412 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
9414 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
9415 MonoMethodSignature
*sig
;
9416 MonoExceptionClause
*clause
;
9417 MonoMethodBuilder
*mb
;
9421 int i
, pos
, pos2
, this_local
, taken_local
, ret_local
= 0;
9422 MonoGenericContext
*ctx
= NULL
;
9423 MonoMethod
*orig_method
= NULL
;
9424 MonoGenericContainer
*container
= NULL
;
9428 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
9431 /* FIXME: Support generic methods too */
9432 if (method
->is_inflated
&& !mono_method_get_context (method
)->method_inst
) {
9433 orig_method
= method
;
9434 ctx
= &((MonoMethodInflated
*)method
)->context
;
9435 method
= ((MonoMethodInflated
*)method
)->declaring
;
9436 container
= mono_method_get_generic_container (method
);
9438 container
= mono_class_try_get_generic_container (method
->klass
); //FIXME is this a case of a try?
9439 g_assert (container
);
9446 cache
= get_cache (&((MonoMethodInflated
*)orig_method
)->owner
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
9447 res
= check_generic_wrapper_cache (cache
, orig_method
, orig_method
, method
);
9451 cache
= get_cache (&method
->klass
->image
->wrapper_caches
.synchronized_cache
, mono_aligned_addr_hash
, NULL
);
9452 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9456 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
9459 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
9461 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
9462 info
->d
.synchronized
.method
= method
;
9465 mb
->skip_visibility
= 1;
9467 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9468 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
9471 if (method
->klass
->valuetype
&& !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
9472 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
9473 mono_class_set_type_load_failure (method
->klass
, "");
9475 /* This will throw the type load exception when the wrapper is compiled */
9476 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9477 mono_mb_emit_op (mb
, CEE_ISINST
, method
->klass
);
9478 mono_mb_emit_byte (mb
, CEE_POP
);
9480 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9481 mono_mb_emit_ldloc (mb
, ret_local
);
9482 mono_mb_emit_byte (mb
, CEE_RET
);
9485 res
= mono_mb_create_and_cache_full (cache
, method
,
9486 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9494 this_local
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
9495 taken_local
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
9497 clause
= (MonoExceptionClause
*)mono_image_alloc0 (method
->klass
->image
, sizeof (MonoExceptionClause
));
9498 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
9501 mono_marshal_lock ();
9503 if (!enter_method
) {
9504 MonoMethodDesc
*desc
;
9506 desc
= mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE
);
9507 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9508 g_assert (enter_method
);
9509 mono_method_desc_free (desc
);
9511 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
9512 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9513 g_assert (exit_method
);
9514 mono_method_desc_free (desc
);
9516 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
9517 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.systemtype_class
);
9518 g_assert (gettypefromhandle_method
);
9519 mono_method_desc_free (desc
);
9522 mono_marshal_unlock ();
9525 /* Push this or the type object */
9526 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
9527 /* We have special handling for this in the JIT */
9528 int index
= mono_mb_add_data (mb
, method
->klass
);
9529 mono_mb_add_data (mb
, mono_defaults
.typehandle_class
);
9530 mono_mb_emit_byte (mb
, CEE_LDTOKEN
);
9531 mono_mb_emit_i4 (mb
, index
);
9533 mono_mb_emit_managed_call (mb
, gettypefromhandle_method
, NULL
);
9536 mono_mb_emit_ldarg (mb
, 0);
9537 mono_mb_emit_stloc (mb
, this_local
);
9539 /* Call Monitor::Enter() */
9540 mono_mb_emit_ldloc (mb
, this_local
);
9541 mono_mb_emit_ldloc_addr (mb
, taken_local
);
9542 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
9544 clause
->try_offset
= mono_mb_get_label (mb
);
9546 /* Call the method */
9548 mono_mb_emit_ldarg (mb
, 0);
9549 for (i
= 0; i
< sig
->param_count
; i
++)
9550 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
9554 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, &error
), NULL
);
9555 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
9557 mono_mb_emit_managed_call (mb
, method
, NULL
);
9560 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9561 mono_mb_emit_stloc (mb
, ret_local
);
9563 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
9565 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
9566 clause
->handler_offset
= mono_mb_get_label (mb
);
9568 /* Call Monitor::Exit() if needed */
9569 mono_mb_emit_ldloc (mb
, taken_local
);
9570 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9571 mono_mb_emit_ldloc (mb
, this_local
);
9572 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
9573 mono_mb_patch_branch (mb
, pos2
);
9574 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
9576 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
9578 mono_mb_patch_branch (mb
, pos
);
9579 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9580 mono_mb_emit_ldloc (mb
, ret_local
);
9581 mono_mb_emit_byte (mb
, CEE_RET
);
9583 mono_mb_set_clauses (mb
, 1, clause
);
9588 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9589 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
9591 res
= mono_mb_create_and_cache_full (cache
, method
,
9592 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9601 * the returned method calls 'method' unboxing the this argument
9604 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
9606 MonoMethodSignature
*sig
= mono_method_signature (method
);
9608 MonoMethodBuilder
*mb
;
9613 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
9615 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9618 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
9620 g_assert (sig
->hasthis
);
9623 mono_mb_emit_ldarg (mb
, 0);
9624 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
9625 mono_mb_emit_byte (mb
, CEE_ADD
);
9626 for (i
= 0; i
< sig
->param_count
; ++i
)
9627 mono_mb_emit_ldarg (mb
, i
+ 1);
9628 mono_mb_emit_managed_call (mb
, method
, NULL
);
9629 mono_mb_emit_byte (mb
, CEE_RET
);
9632 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
9633 info
->d
.unbox
.method
= method
;
9635 res
= mono_mb_create_and_cache_full (cache
, method
,
9636 mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
9639 /* mono_method_print_code (res); */
9645 STELEMREF_OBJECT
, /*no check at all*/
9646 STELEMREF_SEALED_CLASS
, /*check vtable->klass->element_type */
9647 STELEMREF_CLASS
, /*only the klass->parents check*/
9648 STELEMREF_INTERFACE
, /*interfaces without variant generic arguments. */
9649 STELEMREF_COMPLEX
, /*arrays, MBR or types with variant generic args - go straight to icalls*/
9650 STELEMREF_KIND_COUNT
9653 static const char *strelemref_wrapper_name
[] = {
9654 "object", "sealed_class", "class", "interface", "complex"
9658 is_monomorphic_array (MonoClass
*klass
)
9660 MonoClass
*element_class
;
9661 if (klass
->rank
!= 1)
9664 element_class
= klass
->element_class
;
9665 return mono_class_is_sealed (element_class
) || element_class
->valuetype
;
9669 get_virtual_stelemref_kind (MonoClass
*element_class
)
9671 if (element_class
== mono_defaults
.object_class
)
9672 return STELEMREF_OBJECT
;
9673 if (is_monomorphic_array (element_class
))
9674 return STELEMREF_SEALED_CLASS
;
9675 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
9676 if (MONO_CLASS_IS_INTERFACE (element_class
) && !mono_class_has_variant_generic_params (element_class
))
9677 #ifdef COMPRESSED_INTERFACE_BITMAP
9678 return STELEMREF_COMPLEX
;
9680 return STELEMREF_INTERFACE
;
9682 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
9683 if (mono_class_is_marshalbyref (element_class
) || element_class
->rank
|| mono_class_has_variant_generic_params (element_class
))
9684 return STELEMREF_COMPLEX
;
9685 if (mono_class_is_sealed (element_class
))
9686 return STELEMREF_SEALED_CLASS
;
9687 return STELEMREF_CLASS
;
9693 load_array_element_address (MonoMethodBuilder
*mb
)
9695 mono_mb_emit_ldarg (mb
, 0);
9696 mono_mb_emit_ldarg (mb
, 1);
9697 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
9701 load_array_class (MonoMethodBuilder
*mb
, int aklass
)
9703 mono_mb_emit_ldarg (mb
, 0);
9704 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
9705 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9706 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
9707 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9708 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, element_class
));
9709 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9710 mono_mb_emit_stloc (mb
, aklass
);
9714 load_value_class (MonoMethodBuilder
*mb
, int vklass
)
9716 mono_mb_emit_ldarg (mb
, 2);
9717 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
9718 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9719 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
9720 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9721 mono_mb_emit_stloc (mb
, vklass
);
9727 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
9729 char *name
= mono_type_get_full_name (array
->vtable
->klass
->element_class
);
9730 printf ("slow vstore of %s\n", name
);
9737 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
9738 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
9739 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
9740 * - Add a case for arrays of arrays.
9743 get_virtual_stelemref_wrapper (int kind
)
9745 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
9746 static MonoMethodSignature
*signature
;
9747 MonoMethodBuilder
*mb
;
9750 const char *param_names
[16];
9751 guint32 b1
, b2
, b3
, b4
;
9752 int aklass
, vklass
, vtable
, uiid
;
9753 int array_slot_addr
;
9756 if (cached_methods
[kind
])
9757 return cached_methods
[kind
];
9759 name
= g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name
[kind
]);
9760 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STELEMREF
);
9764 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
9766 /* void this::stelemref (size_t idx, void* value) */
9767 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9768 sig
->hasthis
= TRUE
;
9769 sig
->params
[0] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9770 sig
->params
[1] = &mono_defaults
.object_class
->byval_arg
;
9775 param_names
[0] = "index";
9776 param_names
[1] = "value";
9777 mono_mb_set_param_names (mb
, param_names
);
9779 /*For now simply call plain old stelemref*/
9781 case STELEMREF_OBJECT
:
9782 /* ldelema (implicit bound check) */
9783 load_array_element_address (mb
);
9785 mono_mb_emit_ldarg (mb
, 2);
9786 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9787 mono_mb_emit_byte (mb
, CEE_RET
);
9790 case STELEMREF_COMPLEX
: {
9793 <ldelema (bound check)>
9796 if (!mono_object_isinst (value, aklass))
9800 *array_slot_addr = value;
9803 throw new ArrayTypeMismatchException ();
9806 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9807 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9808 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9812 /*Use this to debug/record stores that are going thru the slow path*/
9813 MonoMethodSignature
*csig
;
9814 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
9815 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9816 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9817 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9818 csig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
9819 mono_mb_emit_ldarg (mb
, 0);
9820 mono_mb_emit_ldarg (mb
, 1);
9821 mono_mb_emit_ldarg (mb
, 2);
9822 mono_mb_emit_native_call (mb
, csig
, record_slot_vstore
);
9826 /* ldelema (implicit bound check) */
9827 load_array_element_address (mb
);
9828 mono_mb_emit_stloc (mb
, array_slot_addr
);
9830 /* if (!value) goto do_store */
9831 mono_mb_emit_ldarg (mb
, 2);
9832 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9834 /* aklass = array->vtable->klass->element_class */
9835 load_array_class (mb
, aklass
);
9836 /* vklass = value->vtable->klass */
9837 load_value_class (mb
, vklass
);
9840 mono_mb_emit_ldloc (mb
, vklass
);
9841 mono_mb_emit_ldloc (mb
, aklass
);
9842 b_fast
= mono_mb_emit_branch (mb
, CEE_BEQ
);
9844 /*if (mono_object_isinst (value, aklass)) */
9845 mono_mb_emit_ldarg (mb
, 2);
9846 mono_mb_emit_ldloc (mb
, aklass
);
9847 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
9848 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9851 mono_mb_patch_branch (mb
, b1
);
9852 mono_mb_patch_branch (mb
, b_fast
);
9853 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9854 mono_mb_emit_ldarg (mb
, 2);
9855 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9856 mono_mb_emit_byte (mb
, CEE_RET
);
9859 mono_mb_patch_branch (mb
, b2
);
9861 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9864 case STELEMREF_SEALED_CLASS
:
9866 <ldelema (bound check)>
9870 aklass = array->vtable->klass->element_class;
9871 vklass = value->vtable->klass;
9873 if (vklass != aklass)
9877 *array_slot_addr = value;
9880 throw new ArrayTypeMismatchException ();
9882 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9883 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9884 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9886 /* ldelema (implicit bound check) */
9887 load_array_element_address (mb
);
9888 mono_mb_emit_stloc (mb
, array_slot_addr
);
9890 /* if (!value) goto do_store */
9891 mono_mb_emit_ldarg (mb
, 2);
9892 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9894 /* aklass = array->vtable->klass->element_class */
9895 load_array_class (mb
, aklass
);
9897 /* vklass = value->vtable->klass */
9898 load_value_class (mb
, vklass
);
9900 /*if (vklass != aklass) goto do_exception; */
9901 mono_mb_emit_ldloc (mb
, aklass
);
9902 mono_mb_emit_ldloc (mb
, vklass
);
9903 b2
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9906 mono_mb_patch_branch (mb
, b1
);
9907 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9908 mono_mb_emit_ldarg (mb
, 2);
9909 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9910 mono_mb_emit_byte (mb
, CEE_RET
);
9913 mono_mb_patch_branch (mb
, b2
);
9914 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9917 case STELEMREF_CLASS
: {
9922 <ldelema (bound check)>
9926 aklass = array->vtable->klass->element_class;
9927 vklass = value->vtable->klass;
9929 if (vklass->idepth < aklass->idepth)
9932 if (vklass->supertypes [aklass->idepth - 1] != aklass)
9936 *array_slot_addr = value;
9940 throw new ArrayTypeMismatchException ();
9942 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9943 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9944 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9946 /* ldelema (implicit bound check) */
9947 load_array_element_address (mb
);
9948 mono_mb_emit_stloc (mb
, array_slot_addr
);
9950 /* if (!value) goto do_store */
9951 mono_mb_emit_ldarg (mb
, 2);
9952 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9954 /* aklass = array->vtable->klass->element_class */
9955 load_array_class (mb
, aklass
);
9957 /* vklass = value->vtable->klass */
9958 load_value_class (mb
, vklass
);
9961 mono_mb_emit_ldloc (mb
, vklass
);
9962 mono_mb_emit_ldloc (mb
, aklass
);
9963 b_fast
= mono_mb_emit_branch (mb
, CEE_BEQ
);
9965 /*if (mono_object_isinst (value, aklass)) */
9966 mono_mb_emit_ldarg (mb
, 2);
9967 mono_mb_emit_ldloc (mb
, aklass
);
9968 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
9969 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9971 /* if (vklass->idepth < aklass->idepth) goto failue */
9972 mono_mb_emit_ldloc (mb
, vklass
);
9973 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
9974 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9976 mono_mb_emit_ldloc (mb
, aklass
);
9977 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
9978 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9980 b3
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
9982 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
9983 mono_mb_emit_ldloc (mb
, vklass
);
9984 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, supertypes
));
9985 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9987 mono_mb_emit_ldloc (mb
, aklass
);
9988 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
9989 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9990 mono_mb_emit_icon (mb
, 1);
9991 mono_mb_emit_byte (mb
, CEE_SUB
);
9992 mono_mb_emit_icon (mb
, sizeof (void*));
9993 mono_mb_emit_byte (mb
, CEE_MUL
);
9994 mono_mb_emit_byte (mb
, CEE_ADD
);
9995 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9997 mono_mb_emit_ldloc (mb
, aklass
);
9998 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
10001 mono_mb_patch_branch (mb
, b1
);
10002 mono_mb_patch_branch (mb
, b_fast
);
10003 mono_mb_emit_ldloc (mb
, array_slot_addr
);
10004 mono_mb_emit_ldarg (mb
, 2);
10005 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
10006 mono_mb_emit_byte (mb
, CEE_RET
);
10008 /* do_exception: */
10009 mono_mb_patch_branch (mb
, b2
);
10010 mono_mb_patch_branch (mb
, b3
);
10011 mono_mb_patch_branch (mb
, b4
);
10013 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
10016 case STELEMREF_INTERFACE
:
10023 klass = array->obj.vtable->klass->element_class;
10024 vt = value->vtable;
10025 uiid = klass->interface_id;
10026 if (uiid > vt->max_interface_id)
10028 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
10031 mono_array_setref (array, index, value);
10034 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
10036 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
10037 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10038 vtable
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10039 uiid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10041 /* ldelema (implicit bound check) */
10042 load_array_element_address (mb
);
10043 mono_mb_emit_stloc (mb
, array_slot_addr
);
10045 /* if (!value) goto do_store */
10046 mono_mb_emit_ldarg (mb
, 2);
10047 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
10049 /* klass = array->vtable->klass->element_class */
10050 load_array_class (mb
, aklass
);
10052 /* vt = value->vtable */
10053 mono_mb_emit_ldarg (mb
, 2);
10054 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10055 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10056 mono_mb_emit_stloc (mb
, vtable
);
10058 /* uiid = klass->interface_id; */
10059 mono_mb_emit_ldloc (mb
, aklass
);
10060 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, interface_id
));
10061 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
10062 mono_mb_emit_stloc (mb
, uiid
);
10064 /*if (uiid > vt->max_interface_id)*/
10065 mono_mb_emit_ldloc (mb
, uiid
);
10066 mono_mb_emit_ldloc (mb
, vtable
);
10067 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
10068 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
10069 b2
= mono_mb_emit_branch (mb
, CEE_BGT_UN
);
10071 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
10073 /*vt->interface_bitmap*/
10074 mono_mb_emit_ldloc (mb
, vtable
);
10075 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, interface_bitmap
));
10076 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10079 mono_mb_emit_ldloc (mb
, uiid
);
10080 mono_mb_emit_icon (mb
, 3);
10081 mono_mb_emit_byte (mb
, CEE_SHR_UN
);
10083 /*vt->interface_bitmap [(uiid) >> 3]*/
10084 mono_mb_emit_byte (mb
, CEE_ADD
); /*interface_bitmap is a guint8 array*/
10085 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
10087 /*(1 << ((uiid)&7)))*/
10088 mono_mb_emit_icon (mb
, 1);
10089 mono_mb_emit_ldloc (mb
, uiid
);
10090 mono_mb_emit_icon (mb
, 7);
10091 mono_mb_emit_byte (mb
, CEE_AND
);
10092 mono_mb_emit_byte (mb
, CEE_SHL
);
10094 /*bitwise and the whole thing*/
10095 mono_mb_emit_byte (mb
, CEE_AND
);
10096 b3
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
10099 mono_mb_patch_branch (mb
, b1
);
10100 mono_mb_emit_ldloc (mb
, array_slot_addr
);
10101 mono_mb_emit_ldarg (mb
, 2);
10102 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
10103 mono_mb_emit_byte (mb
, CEE_RET
);
10105 /* do_exception: */
10106 mono_mb_patch_branch (mb
, b2
);
10107 mono_mb_patch_branch (mb
, b3
);
10108 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
10112 mono_mb_emit_ldarg (mb
, 0);
10113 mono_mb_emit_ldarg (mb
, 1);
10114 mono_mb_emit_ldarg (mb
, 2);
10115 mono_mb_emit_managed_call (mb
, mono_marshal_get_stelemref (), NULL
);
10116 mono_mb_emit_byte (mb
, CEE_RET
);
10119 #endif /* DISABLE_JIT */
10120 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF
);
10121 info
->d
.virtual_stelemref
.kind
= kind
;
10122 res
= mono_mb_create (mb
, signature
, 4, info
);
10123 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
10125 mono_marshal_lock ();
10126 if (!cached_methods
[kind
]) {
10127 cached_methods
[kind
] = res
;
10128 mono_marshal_unlock ();
10130 mono_marshal_unlock ();
10131 mono_free_method (res
);
10135 return cached_methods
[kind
];
10139 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
10143 g_assert (array_class
->rank
== 1);
10144 kind
= get_virtual_stelemref_kind (array_class
->element_class
);
10146 return get_virtual_stelemref_wrapper (kind
);
10150 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers
)
10155 *nwrappers
= STELEMREF_KIND_COUNT
;
10156 res
= (MonoMethod
**)g_malloc0 (STELEMREF_KIND_COUNT
* sizeof (MonoMethod
*));
10157 for (i
= 0; i
< STELEMREF_KIND_COUNT
; ++i
)
10158 res
[i
] = get_virtual_stelemref_wrapper (i
);
10163 mono_marshal_get_stelemref (void)
10165 static MonoMethod
* ret
= NULL
;
10166 MonoMethodSignature
*sig
;
10167 MonoMethodBuilder
*mb
;
10170 guint32 b1
, b2
, b3
, b4
;
10172 int aklass
, vklass
;
10173 int array_slot_addr
;
10178 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
10181 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
10183 /* void stelemref (void* array, int idx, void* value) */
10184 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10185 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
10186 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
10187 sig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
10189 #ifndef DISABLE_JIT
10190 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10191 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10192 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
10196 <ldelema (bound check)>
10200 aklass = array->vtable->klass->element_class;
10201 vklass = value->vtable->klass;
10203 if (vklass->idepth < aklass->idepth)
10206 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10210 *array_slot_addr = value;
10214 if (mono_object_isinst (value, aklass))
10217 throw new ArrayTypeMismatchException ();
10220 /* ldelema (implicit bound check) */
10221 mono_mb_emit_ldarg (mb
, 0);
10222 mono_mb_emit_ldarg (mb
, 1);
10223 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
10224 mono_mb_emit_stloc (mb
, array_slot_addr
);
10226 /* if (!value) goto do_store */
10227 mono_mb_emit_ldarg (mb
, 2);
10228 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
10230 /* aklass = array->vtable->klass->element_class */
10231 mono_mb_emit_ldarg (mb
, 0);
10232 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10233 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10234 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
10235 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10236 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, element_class
));
10237 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10238 mono_mb_emit_stloc (mb
, aklass
);
10240 /* vklass = value->vtable->klass */
10241 mono_mb_emit_ldarg (mb
, 2);
10242 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10243 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10244 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
10245 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10246 mono_mb_emit_stloc (mb
, vklass
);
10248 /* if (vklass->idepth < aklass->idepth) goto failue */
10249 mono_mb_emit_ldloc (mb
, vklass
);
10250 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
10251 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10253 mono_mb_emit_ldloc (mb
, aklass
);
10254 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
10255 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10257 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
10259 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10260 mono_mb_emit_ldloc (mb
, vklass
);
10261 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, supertypes
));
10262 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10264 mono_mb_emit_ldloc (mb
, aklass
);
10265 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoClass
, idepth
));
10266 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10267 mono_mb_emit_icon (mb
, 1);
10268 mono_mb_emit_byte (mb
, CEE_SUB
);
10269 mono_mb_emit_icon (mb
, sizeof (void*));
10270 mono_mb_emit_byte (mb
, CEE_MUL
);
10271 mono_mb_emit_byte (mb
, CEE_ADD
);
10272 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10274 mono_mb_emit_ldloc (mb
, aklass
);
10276 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
10278 copy_pos
= mono_mb_get_label (mb
);
10280 mono_mb_patch_branch (mb
, b1
);
10281 mono_mb_emit_ldloc (mb
, array_slot_addr
);
10282 mono_mb_emit_ldarg (mb
, 2);
10283 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
10285 mono_mb_emit_byte (mb
, CEE_RET
);
10288 mono_mb_patch_branch (mb
, b2
);
10289 mono_mb_patch_branch (mb
, b3
);
10291 mono_mb_emit_ldarg (mb
, 2);
10292 mono_mb_emit_ldloc (mb
, aklass
);
10293 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
10295 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
10296 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
10297 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
10299 mono_mb_emit_byte (mb
, CEE_RET
);
10301 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_NONE
);
10302 ret
= mono_mb_create (mb
, sig
, 4, info
);
10309 * mono_marshal_get_gsharedvt_in_wrapper:
10311 * This wrapper handles calls from normal code to gsharedvt code.
10314 mono_marshal_get_gsharedvt_in_wrapper (void)
10316 static MonoMethod
* ret
= NULL
;
10317 MonoMethodSignature
*sig
;
10318 MonoMethodBuilder
*mb
;
10324 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_in", MONO_WRAPPER_UNKNOWN
);
10326 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
10327 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10329 #ifndef DISABLE_JIT
10331 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
10333 mono_mb_emit_byte (mb
, CEE_RET
);
10335 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_IN
);
10336 ret
= mono_mb_create (mb
, sig
, 4, info
);
10343 * mono_marshal_get_gsharedvt_out_wrapper:
10345 * This wrapper handles calls from gsharedvt code to normal code.
10348 mono_marshal_get_gsharedvt_out_wrapper (void)
10350 static MonoMethod
* ret
= NULL
;
10351 MonoMethodSignature
*sig
;
10352 MonoMethodBuilder
*mb
;
10358 mb
= mono_mb_new (mono_defaults
.object_class
, "gsharedvt_out", MONO_WRAPPER_UNKNOWN
);
10360 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
10361 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10363 #ifndef DISABLE_JIT
10365 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
10367 mono_mb_emit_byte (mb
, CEE_RET
);
10369 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GSHAREDVT_OUT
);
10370 ret
= mono_mb_create (mb
, sig
, 4, info
);
10379 MonoMethod
*method
;
10382 /* LOCKING: vars accessed under the marshal lock */
10383 static ArrayElemAddr
*elem_addr_cache
= NULL
;
10384 static int elem_addr_cache_size
= 0;
10385 static int elem_addr_cache_next
= 0;
10388 * mono_marshal_get_array_address:
10389 * @rank: rank of the array type
10390 * @elem_size: size in bytes of an element of an array.
10392 * Returns a MonoMethod that implements the code to get the address
10393 * of an element in a multi-dimenasional array of @rank dimensions.
10394 * The returned method takes an array as the first argument and then
10395 * @rank indexes for the @rank dimensions.
10396 * If ELEM_SIZE is 0, read the array size from the array object.
10399 mono_marshal_get_array_address (int rank
, int elem_size
)
10402 MonoMethodBuilder
*mb
;
10403 MonoMethodSignature
*sig
;
10406 int i
, bounds
, ind
, realidx
;
10407 int branch_pos
, *branch_positions
;
10411 mono_marshal_lock ();
10412 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
10413 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
10414 ret
= elem_addr_cache
[i
].method
;
10418 mono_marshal_unlock ();
10422 branch_positions
= g_new0 (int, rank
);
10424 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
10426 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
10427 sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
10428 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
10429 for (i
= 0; i
< rank
; ++i
) {
10430 sig
->params
[i
+ 1] = &mono_defaults
.int32_class
->byval_arg
;
10433 name
= g_strdup_printf ("ElementAddr_%d", elem_size
);
10434 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
10437 #ifndef DISABLE_JIT
10438 bounds
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10439 ind
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10440 realidx
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10442 /* bounds = array->bounds; */
10443 mono_mb_emit_ldarg (mb
, 0);
10444 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
10445 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10446 mono_mb_emit_stloc (mb
, bounds
);
10448 /* ind is the overall element index, realidx is the partial index in a single dimension */
10449 /* ind = idx0 - bounds [0].lower_bound */
10450 mono_mb_emit_ldarg (mb
, 1);
10451 mono_mb_emit_ldloc (mb
, bounds
);
10452 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
10453 mono_mb_emit_byte (mb
, CEE_ADD
);
10454 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10455 mono_mb_emit_byte (mb
, CEE_SUB
);
10456 mono_mb_emit_stloc (mb
, ind
);
10457 /* if (ind >= bounds [0].length) goto exeception; */
10458 mono_mb_emit_ldloc (mb
, ind
);
10459 mono_mb_emit_ldloc (mb
, bounds
);
10460 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
10461 mono_mb_emit_byte (mb
, CEE_ADD
);
10462 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10463 /* note that we use unsigned comparison */
10464 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
10466 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
10467 * We could also decide to ignore the passed elem_size and get it
10468 * from the array object, to reduce the number of methods we generate:
10469 * the additional cost is 3 memory loads and a non-immediate mul.
10471 for (i
= 1; i
< rank
; ++i
) {
10472 /* realidx = idxi - bounds [i].lower_bound */
10473 mono_mb_emit_ldarg (mb
, 1 + i
);
10474 mono_mb_emit_ldloc (mb
, bounds
);
10475 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
10476 mono_mb_emit_byte (mb
, CEE_ADD
);
10477 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10478 mono_mb_emit_byte (mb
, CEE_SUB
);
10479 mono_mb_emit_stloc (mb
, realidx
);
10480 /* if (realidx >= bounds [i].length) goto exeception; */
10481 mono_mb_emit_ldloc (mb
, realidx
);
10482 mono_mb_emit_ldloc (mb
, bounds
);
10483 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
10484 mono_mb_emit_byte (mb
, CEE_ADD
);
10485 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10486 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
10487 /* ind = ind * bounds [i].length + realidx */
10488 mono_mb_emit_ldloc (mb
, ind
);
10489 mono_mb_emit_ldloc (mb
, bounds
);
10490 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
10491 mono_mb_emit_byte (mb
, CEE_ADD
);
10492 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10493 mono_mb_emit_byte (mb
, CEE_MUL
);
10494 mono_mb_emit_ldloc (mb
, realidx
);
10495 mono_mb_emit_byte (mb
, CEE_ADD
);
10496 mono_mb_emit_stloc (mb
, ind
);
10499 /* return array->vector + ind * element_size */
10500 mono_mb_emit_ldarg (mb
, 0);
10501 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
10502 mono_mb_emit_ldloc (mb
, ind
);
10504 mono_mb_emit_icon (mb
, elem_size
);
10506 /* Load arr->vtable->klass->sizes.element_class */
10507 mono_mb_emit_ldarg (mb
, 0);
10508 mono_mb_emit_byte (mb
, CEE_CONV_I
);
10509 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
10510 mono_mb_emit_byte (mb
, CEE_ADD
);
10511 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10512 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
10513 mono_mb_emit_byte (mb
, CEE_ADD
);
10514 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10515 /* sizes is an union, so this reads sizes.element_size */
10516 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoClass
, sizes
));
10517 mono_mb_emit_byte (mb
, CEE_ADD
);
10518 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10520 mono_mb_emit_byte (mb
, CEE_MUL
);
10521 mono_mb_emit_byte (mb
, CEE_ADD
);
10522 mono_mb_emit_byte (mb
, CEE_RET
);
10524 /* patch the branches to get here and throw */
10525 for (i
= 1; i
< rank
; ++i
) {
10526 mono_mb_patch_branch (mb
, branch_positions
[i
]);
10528 mono_mb_patch_branch (mb
, branch_pos
);
10529 /* throw exception */
10530 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
10532 g_free (branch_positions
);
10533 #endif /* DISABLE_JIT */
10535 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ELEMENT_ADDR
);
10536 info
->d
.element_addr
.rank
= rank
;
10537 info
->d
.element_addr
.elem_size
= elem_size
;
10538 ret
= mono_mb_create (mb
, sig
, 4, info
);
10541 /* cache the result */
10543 mono_marshal_lock ();
10544 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
10545 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
10546 /* FIXME: free ret */
10547 ret
= elem_addr_cache
[i
].method
;
10553 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
10554 int new_size
= elem_addr_cache_size
+ 4;
10555 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
10556 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
10557 g_free (elem_addr_cache
);
10558 elem_addr_cache
= new_array
;
10559 elem_addr_cache_size
= new_size
;
10561 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
10562 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
10563 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
10564 elem_addr_cache_next
++;
10566 mono_marshal_unlock ();
10571 * mono_marshal_get_array_accessor_wrapper:
10573 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
10576 mono_marshal_get_array_accessor_wrapper (MonoMethod
*method
)
10578 MonoMethodSignature
*sig
;
10579 MonoMethodBuilder
*mb
;
10583 MonoGenericContext
*ctx
= NULL
;
10584 MonoMethod
*orig_method
= NULL
;
10585 MonoGenericContainer
*container
= NULL
;
10589 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
10590 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
10591 * FIXME: Use generic methods.
10598 g_assert_not_reached ();
10600 cache
= get_cache (&method
->klass
->image
->array_accessor_cache
, mono_aligned_addr_hash
, NULL
);
10601 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
10605 sig
= mono_metadata_signature_dup_full (method
->klass
->image
, mono_method_signature (method
));
10608 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNKNOWN
);
10610 #ifndef DISABLE_JIT
10611 /* Call the method */
10613 mono_mb_emit_ldarg (mb
, 0);
10614 for (i
= 0; i
< sig
->param_count
; i
++)
10615 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
10619 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, &error
), NULL
);
10620 g_assert (mono_error_ok (&error
)); /* FIXME don't swallow the error */
10622 mono_mb_emit_managed_call (mb
, method
, NULL
);
10624 mono_mb_emit_byte (mb
, CEE_RET
);
10627 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_ARRAY_ACCESSOR
);
10628 info
->d
.array_accessor
.method
= method
;
10632 def
= mono_mb_create_and_cache_full (cache
, method
, mb
, sig
, sig
->param_count
+ 16, info
, NULL
);
10633 res
= cache_generic_wrapper (cache
, orig_method
, def
, ctx
, orig_method
);
10635 res
= mono_mb_create_and_cache_full (cache
, method
,
10636 mb
, sig
, sig
->param_count
+ 16,
10645 static inline void*
10646 mono_marshal_alloc_co_task_mem (size_t size
)
10648 if ((gulong
)size
== 0)
10649 /* This returns a valid pointer for size 0 on MS.NET */
10652 return g_try_malloc ((gulong
)size
);
10657 mono_marshal_alloc (gulong size
, MonoError
*error
)
10661 error_init (error
);
10663 res
= mono_marshal_alloc_co_task_mem (size
);
10665 mono_error_set_out_of_memory (error
, "Could not allocate %lu bytes", size
);
10670 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
10672 ves_icall_marshal_alloc (gulong size
)
10675 void *ret
= mono_marshal_alloc (size
, &error
);
10676 if (!mono_error_ok (&error
)) {
10677 mono_error_set_pending_exception (&error
);
10686 mono_marshal_free_co_task_mem (void *ptr
)
10694 mono_marshal_free (gpointer ptr
)
10696 mono_marshal_free_co_task_mem (ptr
);
10700 mono_marshal_free_array (gpointer
*ptr
, int size
)
10707 for (i
= 0; i
< size
; i
++)
10713 mono_marshal_string_to_utf16 (MonoString
*s
)
10715 return s
? mono_string_chars (s
) : NULL
;
10718 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
10720 mono_marshal_string_to_utf16_copy (MonoString
*s
)
10726 gunichar2
*res
= (gunichar2
*)mono_marshal_alloc ((mono_string_length (s
) * 2) + 2, &error
);
10727 if (!mono_error_ok (&error
)) {
10728 mono_error_set_pending_exception (&error
);
10731 memcpy (res
, mono_string_chars (s
), mono_string_length (s
) * 2);
10732 res
[mono_string_length (s
)] = 0;
10738 * mono_marshal_set_last_error:
10740 * This function is invoked to set the last error value from a P/Invoke call
10741 * which has SetLastError set.
10744 mono_marshal_set_last_error (void)
10747 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
10749 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (errno
));
10754 mono_marshal_set_last_error_windows (int error
)
10757 mono_native_tls_set_value (last_error_tls_id
, GINT_TO_POINTER (error
));
10762 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray
*src
, gint32 start_index
,
10763 gpointer dest
, gint32 length
)
10768 MONO_CHECK_ARG_NULL (src
,);
10769 MONO_CHECK_ARG_NULL (dest
,);
10771 if (src
->obj
.vtable
->klass
->rank
!= 1) {
10772 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10775 if (start_index
< 0) {
10776 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10780 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10783 if (start_index
+ length
> mono_array_length (src
)) {
10784 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10788 element_size
= mono_array_element_size (src
->obj
.vtable
->klass
);
10790 /* no references should be involved */
10791 source_addr
= mono_array_addr_with_size_fast (src
, element_size
, start_index
);
10793 memcpy (dest
, source_addr
, length
* element_size
);
10797 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src
, gint32 start_index
,
10798 MonoArray
*dest
, gint32 length
)
10803 MONO_CHECK_ARG_NULL (src
,);
10804 MONO_CHECK_ARG_NULL (dest
,);
10806 if (dest
->obj
.vtable
->klass
->rank
!= 1) {
10807 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10810 if (start_index
< 0) {
10811 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10815 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10818 if (start_index
+ length
> mono_array_length (dest
)) {
10819 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10822 element_size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
10824 /* no references should be involved */
10825 dest_addr
= mono_array_addr_with_size_fast (dest
, element_size
, start_index
);
10827 memcpy (dest_addr
, src
, length
* element_size
);
10831 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr
)
10836 return mono_string_new (mono_domain_get (), ptr
);
10840 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr
, gint32 len
)
10843 MonoString
*result
= NULL
;
10844 error_init (&error
);
10846 mono_error_set_argument_null (&error
, "ptr", "");
10848 result
= mono_string_new_len_checked (mono_domain_get (), ptr
, len
, &error
);
10849 mono_error_set_pending_exception (&error
);
10854 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16
*ptr
)
10857 MonoString
*res
= NULL
;
10858 MonoDomain
*domain
= mono_domain_get ();
10868 res
= mono_string_new_utf16_checked (domain
, ptr
, len
, &error
);
10869 if (!mono_error_ok (&error
)) {
10870 mono_error_set_pending_exception (&error
);
10877 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16
*ptr
, gint32 len
)
10880 MonoString
*res
= NULL
;
10881 MonoDomain
*domain
= mono_domain_get ();
10883 error_init (&error
);
10887 mono_error_set_argument_null (&error
, "ptr", "");
10889 res
= mono_string_new_utf16_checked (domain
, ptr
, len
, &error
);
10892 if (!mono_error_ok (&error
))
10893 mono_error_set_pending_exception (&error
);
10898 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10900 return (GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id
)));
10904 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType
*rtype
)
10910 MONO_CHECK_ARG_NULL (rtype
, 0);
10912 type
= rtype
->type
;
10913 klass
= mono_class_from_mono_type (type
);
10914 if (!mono_class_init (klass
)) {
10915 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
10919 layout
= (mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
);
10921 if (type
->type
== MONO_TYPE_PTR
|| type
->type
== MONO_TYPE_FNPTR
) {
10922 return sizeof (gpointer
);
10923 } else if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
10925 MonoException
*exc
;
10927 msg
= g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass
->name
);
10928 exc
= mono_get_exception_argument ("t", msg
);
10930 mono_set_pending_exception (exc
);
10934 return mono_class_native_size (klass
, NULL
);
10938 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject
*obj
, gpointer dst
, MonoBoolean delete_old
)
10941 MonoMethod
*method
;
10944 MONO_CHECK_ARG_NULL (obj
,);
10945 MONO_CHECK_ARG_NULL (dst
,);
10947 method
= mono_marshal_get_struct_to_ptr (obj
->vtable
->klass
);
10951 pa
[2] = &delete_old
;
10953 mono_runtime_invoke_checked (method
, NULL
, pa
, &error
);
10954 if (!mono_error_ok (&error
))
10955 mono_error_set_pending_exception (&error
);
10959 ptr_to_structure (gpointer src
, MonoObject
*dst
, MonoError
*error
)
10961 MonoMethod
*method
;
10964 error_init (error
);
10966 method
= mono_marshal_get_ptr_to_struct (dst
->vtable
->klass
);
10971 mono_runtime_invoke_checked (method
, NULL
, pa
, error
);
10975 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src
, MonoObject
*dst
)
10980 MONO_CHECK_ARG_NULL (src
,);
10981 MONO_CHECK_ARG_NULL (dst
,);
10983 t
= mono_type_get_underlying_type (mono_class_get_type (dst
->vtable
->klass
));
10985 if (t
->type
== MONO_TYPE_VALUETYPE
) {
10986 MonoException
*exc
;
10989 tmp
= g_strdup_printf ("Destination is a boxed value type.");
10990 exc
= mono_get_exception_argument ("dst", tmp
);
10993 mono_set_pending_exception (exc
);
10997 ptr_to_structure (src
, dst
, &error
);
10998 if (!mono_error_ok (&error
))
10999 mono_error_set_pending_exception (&error
);
11003 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src
, MonoReflectionType
*type
)
11007 MonoDomain
*domain
= mono_domain_get ();
11012 MONO_CHECK_ARG_NULL (type
, NULL
);
11014 klass
= mono_class_from_mono_type (type
->type
);
11015 if (!mono_class_init (klass
)) {
11016 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
11020 res
= mono_object_new_checked (domain
, klass
, &error
);
11021 if (!mono_error_ok (&error
)) {
11022 mono_error_set_pending_exception (&error
);
11026 ptr_to_structure (src
, res
, &error
);
11027 if (!mono_error_ok (&error
)) {
11028 mono_error_set_pending_exception (&error
);
11036 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType
*type
, MonoString
*field_name
)
11039 MonoMarshalType
*info
;
11042 int match_index
= -1;
11044 MONO_CHECK_ARG_NULL (type
, 0);
11045 MONO_CHECK_ARG_NULL (field_name
, 0);
11047 fname
= mono_string_to_utf8_checked (field_name
, &error
);
11048 if (mono_error_set_pending_exception (&error
))
11050 klass
= mono_class_from_mono_type (type
->type
);
11051 if (!mono_class_init (klass
)) {
11052 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
11056 while (klass
&& match_index
== -1) {
11057 MonoClassField
* field
;
11059 gpointer iter
= NULL
;
11060 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11061 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11063 if (!strcmp (fname
, mono_field_get_name (field
))) {
11070 if (match_index
== -1)
11071 klass
= klass
->parent
;
11076 if(match_index
== -1) {
11077 MonoException
* exc
;
11080 /* Get back original class instance */
11081 klass
= mono_class_from_mono_type (type
->type
);
11083 tmp
= g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass
->name
);
11084 exc
= mono_get_exception_argument ("fieldName", tmp
);
11087 mono_set_pending_exception ((MonoException
*)exc
);
11091 info
= mono_marshal_load_type_info (klass
);
11092 return info
->fields
[match_index
].offset
;
11097 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString
*string
)
11100 char *ret
= mono_string_to_utf8_checked (string
, &error
);
11101 mono_error_set_pending_exception (&error
);
11106 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString
*string
)
11108 if (string
== NULL
)
11111 gunichar2
*res
= (gunichar2
*)g_malloc ((mono_string_length (string
) + 1) * 2);
11113 memcpy (res
, mono_string_chars (string
), mono_string_length (string
) * 2);
11114 res
[mono_string_length (string
)] = 0;
11118 #endif /* !HOST_WIN32 */
11121 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
11123 MonoMarshalType
*info
;
11126 info
= mono_marshal_load_type_info (klass
);
11128 for (i
= 0; i
< info
->num_fields
; i
++) {
11129 MonoMarshalConv conv
;
11130 MonoType
*ftype
= info
->fields
[i
].field
->type
;
11133 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11136 mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
11137 klass
->unicode
, &conv
);
11139 cpos
= ptr
+ info
->fields
[i
].offset
;
11142 case MONO_MARSHAL_CONV_NONE
:
11143 if (MONO_TYPE_ISSTRUCT (ftype
)) {
11144 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
11148 case MONO_MARSHAL_CONV_STR_LPWSTR
:
11149 /* We assume this field points inside a MonoString */
11151 case MONO_MARSHAL_CONV_STR_LPTSTR
:
11152 #ifdef TARGET_WIN32
11153 /* We assume this field points inside a MonoString
11157 case MONO_MARSHAL_CONV_STR_LPSTR
:
11158 case MONO_MARSHAL_CONV_STR_BSTR
:
11159 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
11160 case MONO_MARSHAL_CONV_STR_TBSTR
:
11161 case MONO_MARSHAL_CONV_STR_UTF8STR
:
11162 mono_marshal_free (*(gpointer
*)cpos
);
11172 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionType
*type
)
11176 MONO_CHECK_ARG_NULL (src
,);
11177 MONO_CHECK_ARG_NULL (type
,);
11179 klass
= mono_class_from_mono_type (type
->type
);
11180 if (!mono_class_init (klass
)) {
11181 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
11185 mono_struct_delete_old (klass
, (char *)src
);
11189 static inline void *
11190 mono_marshal_alloc_hglobal (size_t size
)
11192 return g_try_malloc (size
);
11197 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size
)
11200 size_t s
= (size_t)size
;
11203 /* This returns a valid pointer for size 0 on MS.NET */
11206 res
= mono_marshal_alloc_hglobal (s
);
11209 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11217 static inline gpointer
11218 mono_marshal_realloc_hglobal (gpointer ptr
, size_t size
)
11220 return g_try_realloc (ptr
, size
);
11225 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, gpointer size
)
11228 size_t s
= (size_t)size
;
11231 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11235 res
= mono_marshal_realloc_hglobal (ptr
, s
);
11238 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11247 mono_marshal_free_hglobal (gpointer ptr
)
11255 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
11257 mono_marshal_free_hglobal (ptr
);
11261 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
)
11263 void *res
= mono_marshal_alloc_co_task_mem (size
);
11266 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11273 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gulong size
)
11275 void *res
= mono_marshal_alloc_co_task_mem (size
);
11278 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11285 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
11287 mono_marshal_free_co_task_mem (ptr
);
11292 static inline gpointer
11293 mono_marshal_realloc_co_task_mem (gpointer ptr
, size_t size
)
11295 return g_try_realloc (ptr
, (gulong
)size
);
11300 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
)
11302 void *res
= mono_marshal_realloc_co_task_mem (ptr
, size
);
11305 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex
);
11312 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray
*arrayobj
, int index
)
11314 return mono_array_addr_with_size_fast (arrayobj
, mono_array_element_size (arrayobj
->obj
.vtable
->klass
), index
);
11318 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionType
*type
)
11320 MonoClass
*klass
= mono_type_get_class (type
->type
);
11321 if (!mono_class_init (klass
)) {
11322 mono_set_pending_exception (mono_class_get_exception_for_failure (klass
));
11326 return mono_ftnptr_to_delegate (klass
, ftn
);
11330 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate
*delegate
)
11332 return mono_delegate_to_ftnptr (delegate
);
11336 * mono_marshal_is_loading_type_info:
11338 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
11342 mono_marshal_is_loading_type_info (MonoClass
*klass
)
11344 GSList
*loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
11346 return g_slist_find (loads_list
, klass
) != NULL
;
11350 * mono_marshal_load_type_info:
11352 * Initialize klass::marshal_info using information from metadata. This function can
11353 * recursively call itself, and the caller is responsible to avoid that by calling
11354 * mono_marshal_is_loading_type_info () beforehand.
11356 * LOCKING: Acquires the loader lock.
11359 mono_marshal_load_type_info (MonoClass
* klass
)
11362 guint32 native_size
= 0, min_align
= 1, packing
;
11363 MonoMarshalType
*info
;
11364 MonoClassField
* field
;
11367 GSList
*loads_list
;
11369 g_assert (klass
!= NULL
);
11371 info
= mono_class_get_marshal_info (klass
);
11375 if (!klass
->inited
)
11376 mono_class_init (klass
);
11378 info
= mono_class_get_marshal_info (klass
);
11383 * This function can recursively call itself, so we keep the list of classes which are
11384 * under initialization in a TLS list.
11386 g_assert (!mono_marshal_is_loading_type_info (klass
));
11387 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
11388 loads_list
= g_slist_prepend (loads_list
, klass
);
11389 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
11392 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11393 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11395 if (mono_field_is_deleted (field
))
11400 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
11402 /* The mempool is protected by the loader lock */
11403 info
= (MonoMarshalType
*)mono_image_alloc0 (klass
->image
, MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
11404 info
->num_fields
= count
;
11406 /* Try to find a size for this type in metadata */
11407 mono_metadata_packing_from_typedef (klass
->image
, klass
->type_token
, NULL
, &native_size
);
11409 if (klass
->parent
) {
11410 int parent_size
= mono_class_native_size (klass
->parent
, NULL
);
11412 /* Add parent size to real size */
11413 native_size
+= parent_size
;
11414 info
->native_size
= parent_size
;
11417 packing
= klass
->packing_size
? klass
->packing_size
: 8;
11420 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11424 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11427 if (mono_field_is_deleted (field
))
11429 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
11430 mono_metadata_field_info_with_mempool (klass
->image
, mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
11431 NULL
, NULL
, &info
->fields
[j
].mspec
);
11433 info
->fields
[j
].field
= field
;
11435 if ((mono_class_num_fields (klass
) == 1) && (klass
->instance_size
== sizeof (MonoObject
)) &&
11436 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
11437 /* This field is a hack inserted by MCS to empty structures */
11442 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
11443 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
11444 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
11445 &align
, TRUE
, klass
->unicode
);
11446 align
= klass
->packing_size
? MIN (klass
->packing_size
, align
): align
;
11447 min_align
= MAX (align
, min_align
);
11448 info
->fields
[j
].offset
= info
->native_size
;
11449 info
->fields
[j
].offset
+= align
- 1;
11450 info
->fields
[j
].offset
&= ~(align
- 1);
11451 info
->native_size
= info
->fields
[j
].offset
+ size
;
11453 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
11454 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
11455 &align
, TRUE
, klass
->unicode
);
11456 min_align
= MAX (align
, min_align
);
11457 info
->fields
[j
].offset
= field
->offset
- sizeof (MonoObject
);
11458 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
11464 if (klass
->byval_arg
.type
== MONO_TYPE_PTR
)
11465 info
->native_size
= sizeof (gpointer
);
11467 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
11468 info
->native_size
= MAX (native_size
, info
->native_size
);
11470 * If the provided Size is equal or larger than the calculated size, and there
11471 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
11473 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
11474 if (native_size
&& native_size
== info
->native_size
&& klass
->packing_size
== 0)
11477 min_align
= MIN (min_align
, packing
);
11481 if (info
->native_size
& (min_align
- 1)) {
11482 info
->native_size
+= min_align
- 1;
11483 info
->native_size
&= ~(min_align
- 1);
11486 info
->min_align
= min_align
;
11488 /* Update the class's blittable info, if the layouts don't match */
11489 if (info
->native_size
!= mono_class_value_size (klass
, NULL
))
11490 klass
->blittable
= FALSE
;
11492 /* If this is an array type, ensure that we have element info */
11493 if (klass
->rank
&& !mono_marshal_is_loading_type_info (klass
->element_class
)) {
11494 mono_marshal_load_type_info (klass
->element_class
);
11497 loads_list
= (GSList
*)mono_native_tls_get_value (load_type_info_tls_id
);
11498 loads_list
= g_slist_remove (loads_list
, klass
);
11499 mono_native_tls_set_value (load_type_info_tls_id
, loads_list
);
11501 mono_marshal_lock ();
11502 MonoMarshalType
*info2
= mono_class_get_marshal_info (klass
);
11504 /*We do double-checking locking on marshal_info */
11505 mono_memory_barrier ();
11506 mono_class_set_marshal_info (klass
, info
);
11507 ++class_marshal_info_count
;
11510 mono_marshal_unlock ();
11516 * mono_class_native_size:
11519 * Returns: the native size of an object instance (when marshaled
11520 * to unmanaged code)
11523 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
11525 MonoMarshalType
*info
= mono_class_get_marshal_info (klass
);
11527 if (mono_marshal_is_loading_type_info (klass
)) {
11532 mono_marshal_load_type_info (klass
);
11534 info
= mono_class_get_marshal_info (klass
);
11538 *align
= info
->min_align
;
11540 return info
->native_size
;
11544 * mono_type_native_stack_size:
11545 * @t: the type to return the size it uses on the stack
11547 * Returns: the number of bytes required to hold an instance of this
11548 * type on the native stack
11551 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
11555 g_assert (t
!= NULL
);
11561 *align
= sizeof (gpointer
);
11562 return sizeof (gpointer
);
11566 case MONO_TYPE_BOOLEAN
:
11567 case MONO_TYPE_CHAR
:
11578 case MONO_TYPE_STRING
:
11579 case MONO_TYPE_OBJECT
:
11580 case MONO_TYPE_CLASS
:
11581 case MONO_TYPE_SZARRAY
:
11582 case MONO_TYPE_PTR
:
11583 case MONO_TYPE_FNPTR
:
11584 case MONO_TYPE_ARRAY
:
11585 *align
= sizeof (gpointer
);
11586 return sizeof (gpointer
);
11591 *align
= MONO_ABI_ALIGNOF (double);
11595 *align
= MONO_ABI_ALIGNOF (gint64
);
11597 case MONO_TYPE_GENERICINST
:
11598 if (!mono_type_generic_inst_is_valuetype (t
)) {
11599 *align
= sizeof (gpointer
);
11600 return sizeof (gpointer
);
11603 case MONO_TYPE_TYPEDBYREF
:
11604 case MONO_TYPE_VALUETYPE
: {
11606 MonoClass
*klass
= mono_class_from_mono_type (t
);
11608 if (klass
->enumtype
)
11609 return mono_type_native_stack_size (mono_class_enum_basetype (klass
), align
);
11611 size
= mono_class_native_size (klass
, align
);
11612 *align
= *align
+ 3;
11622 g_error ("type 0x%02x unknown", t
->type
);
11628 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
11629 gboolean as_field
, gboolean unicode
)
11631 MonoMarshalNative native_type
= mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
11634 switch (native_type
) {
11635 case MONO_NATIVE_BOOLEAN
:
11638 case MONO_NATIVE_I1
:
11639 case MONO_NATIVE_U1
:
11642 case MONO_NATIVE_I2
:
11643 case MONO_NATIVE_U2
:
11644 case MONO_NATIVE_VARIANTBOOL
:
11647 case MONO_NATIVE_I4
:
11648 case MONO_NATIVE_U4
:
11649 case MONO_NATIVE_ERROR
:
11652 case MONO_NATIVE_I8
:
11653 case MONO_NATIVE_U8
:
11654 *align
= MONO_ABI_ALIGNOF (gint64
);
11656 case MONO_NATIVE_R4
:
11659 case MONO_NATIVE_R8
:
11660 *align
= MONO_ABI_ALIGNOF (double);
11662 case MONO_NATIVE_INT
:
11663 case MONO_NATIVE_UINT
:
11664 case MONO_NATIVE_LPSTR
:
11665 case MONO_NATIVE_LPWSTR
:
11666 case MONO_NATIVE_LPTSTR
:
11667 case MONO_NATIVE_BSTR
:
11668 case MONO_NATIVE_ANSIBSTR
:
11669 case MONO_NATIVE_TBSTR
:
11670 case MONO_NATIVE_UTF8STR
:
11671 case MONO_NATIVE_LPARRAY
:
11672 case MONO_NATIVE_SAFEARRAY
:
11673 case MONO_NATIVE_IUNKNOWN
:
11674 case MONO_NATIVE_IDISPATCH
:
11675 case MONO_NATIVE_INTERFACE
:
11676 case MONO_NATIVE_ASANY
:
11677 case MONO_NATIVE_FUNC
:
11678 case MONO_NATIVE_LPSTRUCT
:
11679 *align
= MONO_ABI_ALIGNOF (gpointer
);
11680 return sizeof (gpointer
);
11681 case MONO_NATIVE_STRUCT
:
11682 klass
= mono_class_from_mono_type (type
);
11683 if (klass
== mono_defaults
.object_class
&&
11684 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
11688 return mono_class_native_size (klass
, align
);
11689 case MONO_NATIVE_BYVALTSTR
: {
11690 int esize
= unicode
? 2: 1;
11693 return mspec
->data
.array_data
.num_elem
* esize
;
11695 case MONO_NATIVE_BYVALARRAY
: {
11696 // FIXME: Have to consider ArraySubType
11698 klass
= mono_class_from_mono_type (type
);
11699 if (klass
->element_class
== mono_defaults
.char_class
) {
11700 esize
= unicode
? 2 : 1;
11703 esize
= mono_class_native_size (klass
->element_class
, align
);
11706 return mspec
->data
.array_data
.num_elem
* esize
;
11708 case MONO_NATIVE_CUSTOM
:
11709 *align
= sizeof (gpointer
);
11710 return sizeof (gpointer
);
11712 case MONO_NATIVE_CURRENCY
:
11713 case MONO_NATIVE_VBBYREFSTR
:
11715 g_error ("native type %02x not implemented", native_type
);
11718 g_assert_not_reached ();
11722 /* This is a JIT icall, it sets the pending exception and return NULL on error */
11724 mono_marshal_asany (MonoObject
*o
, MonoMarshalNative string_encoding
, int param_attrs
)
11733 t
= &o
->vtable
->klass
->byval_arg
;
11737 case MONO_TYPE_PTR
:
11740 case MONO_TYPE_BOOLEAN
:
11743 case MONO_TYPE_CHAR
:
11748 return mono_object_unbox (o
);
11750 case MONO_TYPE_STRING
:
11751 switch (string_encoding
) {
11752 case MONO_NATIVE_LPWSTR
:
11753 return mono_marshal_string_to_utf16_copy ((MonoString
*)o
);
11754 case MONO_NATIVE_LPSTR
:
11755 case MONO_NATIVE_UTF8STR
:
11756 // Same code path, because in Mono, we treated strings as Utf8
11757 return mono_string_to_utf8str ((MonoString
*)o
);
11759 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11760 g_assert_not_reached ();
11763 case MONO_TYPE_CLASS
:
11764 case MONO_TYPE_VALUETYPE
: {
11765 MonoMethod
*method
;
11768 MonoBoolean delete_old
= FALSE
;
11770 klass
= t
->data
.klass
;
11772 if (mono_class_is_auto_layout (klass
))
11775 if (klass
->valuetype
&& (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
))
11776 return mono_object_unbox (o
);
11778 res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
), &error
);
11779 if (!mono_error_ok (&error
)) {
11780 mono_error_set_pending_exception (&error
);
11784 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11785 method
= mono_marshal_get_struct_to_ptr (o
->vtable
->klass
);
11789 pa
[2] = &delete_old
;
11791 mono_runtime_invoke_checked (method
, NULL
, pa
, &error
);
11792 if (!mono_error_ok (&error
)) {
11793 mono_error_set_pending_exception (&error
);
11803 mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
11807 /* This is a JIT icall, it sets the pending exception */
11809 mono_marshal_free_asany (MonoObject
*o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
)
11818 t
= &o
->vtable
->klass
->byval_arg
;
11820 case MONO_TYPE_STRING
:
11821 switch (string_encoding
) {
11822 case MONO_NATIVE_LPWSTR
:
11823 case MONO_NATIVE_LPSTR
:
11824 case MONO_NATIVE_UTF8STR
:
11825 mono_marshal_free (ptr
);
11828 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11829 g_assert_not_reached ();
11832 case MONO_TYPE_CLASS
:
11833 case MONO_TYPE_VALUETYPE
: {
11834 klass
= t
->data
.klass
;
11836 if (klass
->valuetype
&& (mono_class_is_explicit_layout (klass
) || klass
->blittable
|| klass
->enumtype
))
11839 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
11840 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (o
->vtable
->klass
);
11846 mono_runtime_invoke_checked (method
, NULL
, pa
, &error
);
11847 if (!mono_error_ok (&error
)) {
11848 mono_error_set_pending_exception (&error
);
11853 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11854 mono_struct_delete_old (klass
, (char *)ptr
);
11857 mono_marshal_free (ptr
);
11866 * mono_marshal_get_generic_array_helper:
11868 * Return a wrapper which is used to implement the implicit interfaces on arrays.
11869 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
11872 mono_marshal_get_generic_array_helper (MonoClass
*klass
, gchar
*name
, MonoMethod
*method
)
11874 MonoMethodSignature
*sig
, *csig
;
11875 MonoMethodBuilder
*mb
;
11880 mb
= mono_mb_new_no_dup_name (klass
, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
11881 mb
->method
->slot
= -1;
11883 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
11884 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
11886 sig
= mono_method_signature (method
);
11887 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
11888 csig
->generic_param_count
= 0;
11890 #ifndef DISABLE_JIT
11891 mono_mb_emit_ldarg (mb
, 0);
11892 for (i
= 0; i
< csig
->param_count
; i
++)
11893 mono_mb_emit_ldarg (mb
, i
+ 1);
11894 mono_mb_emit_managed_call (mb
, method
, NULL
);
11895 mono_mb_emit_byte (mb
, CEE_RET
);
11897 /* We can corlib internal methods */
11898 mb
->skip_visibility
= TRUE
;
11900 info
= mono_wrapper_info_create (mb
, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
);
11901 info
->d
.generic_array_helper
.method
= method
;
11902 res
= mono_mb_create (mb
, csig
, csig
->param_count
+ 16, info
);
11910 * The mono_win32_compat_* functions are implementations of inline
11911 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11912 * although not exported by kernel32.
11914 * We map the appropiate kernel32 entries to these functions using
11915 * dllmaps declared in the global etc/mono/config.
11919 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
11921 if (!dest
|| !source
)
11924 memcpy (dest
, source
, length
);
11928 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
11930 memset (dest
, fill
, length
);
11934 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
11936 if (!dest
|| !source
)
11939 memmove (dest
, source
, length
);
11943 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
11945 memset (dest
, 0, length
);
11949 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
11954 for (i
= 0; i
< len
; ++i
)
11958 g_assert (i
< len
);
11961 while (byte
&& !(byte
& 1))
11963 g_assert (byte
== 1);
11966 *bitmask
= buf
[i
];
11970 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
11972 MonoMethodBuilder
*mb
;
11973 MonoMethodSignature
*sig
, *csig
;
11974 MonoExceptionClause
*clause
;
11979 int i
, param_count
, sig_size
, pos_leave
;
11983 // FIXME: we need to store the exception into a MonoHandle
11984 g_assert (!mono_threads_is_coop_enabled ());
11986 klass
= method
->klass
;
11987 image
= method
->klass
->image
;
11989 cache
= get_cache (&mono_method_get_wrapper_cache (method
)->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
11991 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
11994 sig
= mono_method_signature (method
);
11995 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
11997 /* add "this" and exception param */
11998 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
12000 /* dup & extend signature */
12001 csig
= mono_metadata_signature_alloc (image
, param_count
);
12002 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
12003 memcpy (csig
, sig
, sig_size
);
12004 csig
->param_count
= param_count
;
12007 csig
->call_convention
= MONO_CALL_DEFAULT
;
12009 if (sig
->hasthis
) {
12011 csig
->params
[0] = &klass
->byval_arg
;
12012 /* move params up by one */
12013 for (i
= 0; i
< sig
->param_count
; i
++)
12014 csig
->params
[i
+ 1] = sig
->params
[i
];
12017 /* setup exception param as byref+[out] */
12018 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
,
12019 &mono_defaults
.exception_class
->byval_arg
);
12020 csig
->params
[param_count
- 1]->byref
= 1;
12021 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
12023 /* convert struct return to object */
12024 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
12025 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
12027 #ifndef DISABLE_JIT
12028 /* local 0 (temp for exception object) */
12029 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
12031 /* local 1 (temp for result) */
12032 if (!MONO_TYPE_IS_VOID (sig
->ret
))
12033 mono_mb_add_local (mb
, sig
->ret
);
12035 /* clear exception arg */
12036 mono_mb_emit_ldarg (mb
, param_count
- 1);
12037 mono_mb_emit_byte (mb
, CEE_LDNULL
);
12038 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
12041 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
12042 clause
->try_offset
= mono_mb_get_label (mb
);
12044 /* push method's args */
12045 for (i
= 0; i
< param_count
- 1; i
++) {
12049 mono_mb_emit_ldarg (mb
, i
);
12051 /* get the byval type of the param */
12052 klass
= mono_class_from_mono_type (csig
->params
[i
]);
12053 type
= &klass
->byval_arg
;
12055 /* unbox struct args */
12056 if (MONO_TYPE_ISSTRUCT (type
)) {
12057 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
12059 /* byref args & and the "this" arg must remain a ptr.
12060 Otherwise make a copy of the value type */
12061 if (!(csig
->params
[i
]->byref
|| (i
== 0 && sig
->hasthis
)))
12062 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
12064 csig
->params
[i
] = &mono_defaults
.object_class
->byval_arg
;
12069 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
12070 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
12072 mono_mb_emit_op (mb
, CEE_CALL
, method
);
12074 /* save result at local 1 */
12075 if (!MONO_TYPE_IS_VOID (sig
->ret
))
12076 mono_mb_emit_stloc (mb
, 1);
12078 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
12081 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
12082 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
12083 clause
->data
.catch_class
= mono_defaults
.object_class
;
12085 clause
->handler_offset
= mono_mb_get_label (mb
);
12087 /* store exception at local 0 */
12088 mono_mb_emit_stloc (mb
, 0);
12089 mono_mb_emit_ldarg (mb
, param_count
- 1);
12090 mono_mb_emit_ldloc (mb
, 0);
12091 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
12092 mono_mb_emit_branch (mb
, CEE_LEAVE
);
12094 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
12096 mono_mb_set_clauses (mb
, 1, clause
);
12098 mono_mb_patch_branch (mb
, pos_leave
);
12101 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
12102 mono_mb_emit_ldloc (mb
, 1);
12104 /* box the return value */
12105 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
12106 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
12109 mono_mb_emit_byte (mb
, CEE_RET
);
12112 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
12119 * mono_marshal_free_dynamic_wrappers:
12121 * Free wrappers of the dynamic method METHOD.
12124 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
12126 MonoImage
*image
= method
->klass
->image
;
12128 g_assert (method_is_dynamic (method
));
12130 /* This could be called during shutdown */
12131 if (marshal_mutex_initialized
)
12132 mono_marshal_lock ();
12134 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
12135 * they could be shared with other methods ?
12137 if (image
->wrapper_caches
.runtime_invoke_direct_cache
)
12138 g_hash_table_remove (image
->wrapper_caches
.runtime_invoke_direct_cache
, method
);
12139 if (image
->wrapper_caches
.delegate_abstract_invoke_cache
)
12140 g_hash_table_foreach_remove (image
->wrapper_caches
.delegate_abstract_invoke_cache
, signature_pointer_pair_matches_pointer
, method
);
12141 // FIXME: Need to clear the caches in other images as well
12142 if (image
->delegate_bound_static_invoke_cache
)
12143 g_hash_table_remove (image
->delegate_bound_static_invoke_cache
, mono_method_signature (method
));
12145 if (marshal_mutex_initialized
)
12146 mono_marshal_unlock ();
12150 mono_marshal_ftnptr_eh_callback (guint32 gchandle
)
12152 g_assert (ftnptr_eh_callback
);
12153 ftnptr_eh_callback (gchandle
);
12157 ftnptr_eh_callback_default (guint32 gchandle
)
12159 MonoException
*exc
;
12160 gpointer stackdata
;
12162 mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata
);
12164 exc
= (MonoException
*) mono_gchandle_get_target (gchandle
);
12166 mono_gchandle_free (gchandle
);
12168 mono_raise_exception (exc
);
12172 * mono_install_ftnptr_eh_callback:
12174 * Install a callback that should be called when there is a managed exception
12175 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
12176 * managed exception to a native exception, to properly unwind the native
12177 * stack; this native exception will then be converted back to a managed
12178 * exception in their managed-to-native wrapper.
12181 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback
)
12183 ftnptr_eh_callback
= callback
;
12186 static MonoThreadInfo
*
12187 mono_icall_start (HandleStackMark
*stackmark
, MonoError
*error
)
12189 MonoThreadInfo
*info
= mono_thread_info_current ();
12191 mono_stack_mark_init (info
, stackmark
);
12192 error_init (error
);
12197 mono_icall_end (MonoThreadInfo
*info
, HandleStackMark
*stackmark
, MonoError
*error
)
12199 mono_stack_mark_pop (info
, stackmark
);
12200 if (G_UNLIKELY (!is_ok (error
)))
12201 mono_error_set_pending_exception (error
);