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)
21 #include "metadata/marshal.h"
22 #include "metadata/method-builder.h"
23 #include "metadata/tabledefs.h"
24 #include "metadata/exception.h"
25 #include "metadata/appdomain.h"
26 #include "mono/metadata/debug-helpers.h"
27 #include "mono/metadata/threadpool.h"
28 #include "mono/metadata/threads.h"
29 #include "mono/metadata/monitor.h"
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/domain-internals.h"
32 #include "mono/metadata/gc-internal.h"
33 #include "mono/metadata/threads-types.h"
34 #include "mono/metadata/string-icalls.h"
35 #include "mono/metadata/attrdefs.h"
36 #include "mono/metadata/gc-internal.h"
37 #include "mono/metadata/cominterop.h"
38 #include "mono/utils/mono-counters.h"
39 #include "mono/utils/mono-tls.h"
40 #include "mono/utils/mono-memory-model.h"
44 /* #define DEBUG_RUNTIME_CODE */
46 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
50 MONO_MARSHAL_NONE, /* No marshalling needed */
51 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
52 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
53 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
54 } MonoXDomainMarshalType;
57 #include "mono/cil/opcode.def"
62 struct _MonoRemotingMethods {
64 MonoMethod *invoke_with_check;
65 MonoMethod *xdomain_invoke;
66 MonoMethod *xdomain_dispatch;
69 typedef struct _MonoRemotingMethods MonoRemotingMethods;
72 * This mutex protects the various marshalling related caches in MonoImage
73 * and a few other data structures static to this file.
74 * Note that when this lock is held it is not possible to take other runtime
75 * locks like the loader lock.
77 #define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
78 #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
79 static CRITICAL_SECTION marshal_mutex;
80 static gboolean marshal_mutex_initialized;
82 static MonoNativeTlsKey last_error_tls_id;
84 static MonoNativeTlsKey load_type_info_tls_id;
87 delegate_hash_table_add (MonoDelegate *d);
90 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
93 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, MonoMarshalNative string_encoding);
96 mono_struct_delete_old (MonoClass *klass, char *ptr);
99 mono_marshal_string_to_utf16 (MonoString *s);
102 mono_marshal_string_to_utf16_copy (MonoString *s);
105 mono_string_to_lpstr (MonoString *string_obj);
107 static MonoStringBuilder *
108 mono_string_utf8_to_builder2 (char *text);
110 static MonoStringBuilder *
111 mono_string_utf16_to_builder2 (gunichar2 *text);
114 mono_string_new_len_wrapper (const char *text, guint length);
117 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum);
120 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *eltype, guint32 elnum);
123 mono_remoting_wrapper (MonoMethod *method, gpointer *params);
125 static MonoAsyncResult *
126 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params);
129 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
132 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst);
135 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push);
138 mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image);
141 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
143 static MonoReflectionType *
144 type_from_handle (MonoType *handle);
147 mono_marshal_set_last_error_windows (int error);
149 static void init_safe_handle (void);
151 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
152 static MonoMethod *sh_dangerous_add_ref;
153 static MonoMethod *sh_dangerous_release;
159 sh_dangerous_add_ref = mono_class_get_method_from_name (
160 mono_defaults.safehandle_class, "DangerousAddRef", 1);
161 sh_dangerous_release = mono_class_get_method_from_name (
162 mono_defaults.safehandle_class, "DangerousRelease", 0);
166 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
168 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
170 mono_register_jit_icall (func, name, sig, save);
173 static MonoMethodSignature*
174 signature_dup (MonoImage *image, MonoMethodSignature *sig)
176 MonoMethodSignature *res;
179 res = mono_metadata_signature_alloc (image, sig->param_count);
180 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
181 memcpy (res, sig, sigsize);
187 mono_signature_no_pinvoke (MonoMethod *method)
189 MonoMethodSignature *sig = mono_method_signature (method);
191 sig = signature_dup (method->klass->image, sig);
192 sig->pinvoke = FALSE;
199 mono_marshal_init (void)
201 static gboolean module_initialized = FALSE;
203 if (!module_initialized) {
204 module_initialized = TRUE;
205 InitializeCriticalSection (&marshal_mutex);
206 marshal_mutex_initialized = TRUE;
207 mono_native_tls_alloc (&last_error_tls_id, NULL);
208 mono_native_tls_alloc (&load_type_info_tls_id, NULL);
210 register_icall (ves_icall_System_Threading_Thread_ResetAbort, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE);
211 register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
212 register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
213 register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
214 register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
215 register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
216 register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
217 register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
218 register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
219 register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
220 register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
221 register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
222 register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
223 register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
224 register_icall (mono_free_lparray, "mono_free_lparray", "void object ptr", FALSE);
225 register_icall (mono_byvalarray_to_array, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE);
226 register_icall (mono_array_to_byvalarray, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE);
227 register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
228 register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
229 register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
230 register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
231 register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
232 register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
233 register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
234 register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE);
235 register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
236 register_icall (mono_string_utf8_to_builder2, "mono_string_utf8_to_builder2", "object ptr", FALSE);
237 register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
238 register_icall (mono_string_utf16_to_builder2, "mono_string_utf16_to_builder2", "object ptr", FALSE);
239 register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
240 register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
241 register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
242 register_icall (g_free, "g_free", "void ptr", FALSE);
243 register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
244 register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
245 register_icall (mono_remoting_wrapper, "mono_remoting_wrapper", "object ptr ptr", FALSE);
246 register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
247 register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
248 register_icall (mono_marshal_xdomain_copy_value, "mono_marshal_xdomain_copy_value", "object object", FALSE);
249 register_icall (mono_marshal_xdomain_copy_out_value, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE);
250 register_icall (mono_marshal_set_domain_by_id, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE);
251 register_icall (mono_marshal_check_domain_image, "mono_marshal_check_domain_image", "int32 int32 ptr", FALSE);
252 register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
253 register_icall (mono_context_get, "mono_context_get", "object", FALSE);
254 register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
255 register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE);
256 register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE);
257 register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
258 register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
260 mono_cominterop_init ();
265 mono_marshal_cleanup (void)
267 mono_cominterop_cleanup ();
269 mono_native_tls_free (load_type_info_tls_id);
270 mono_native_tls_free (last_error_tls_id);
271 DeleteCriticalSection (&marshal_mutex);
272 marshal_mutex_initialized = FALSE;
275 MonoClass *byte_array_class;
276 static MonoMethod *method_rs_serialize, *method_rs_deserialize, *method_exc_fixexc, *method_rs_appdomain_target;
277 static MonoMethod *method_set_context, *method_get_context;
278 static MonoMethod *method_set_call_context, *method_needs_context_sink, *method_rs_serialize_exc;
281 mono_remoting_marshal_init (void)
285 static gboolean module_initialized = FALSE;
287 if (!module_initialized) {
288 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
289 method_rs_serialize = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
290 method_rs_deserialize = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
291 method_rs_serialize_exc = mono_class_get_method_from_name (klass, "SerializeExceptionData", -1);
293 klass = mono_defaults.real_proxy_class;
294 method_rs_appdomain_target = mono_class_get_method_from_name (klass, "GetAppDomainTarget", -1);
296 klass = mono_defaults.exception_class;
297 method_exc_fixexc = mono_class_get_method_from_name (klass, "FixRemotingException", -1);
299 klass = mono_defaults.thread_class;
300 method_get_context = mono_class_get_method_from_name (klass, "get_CurrentContext", -1);
302 klass = mono_defaults.appdomain_class;
303 method_set_context = mono_class_get_method_from_name (klass, "InternalSetContext", -1);
304 byte_array_class = mono_array_class_get (mono_defaults.byte_class, 1);
306 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "CallContext");
307 method_set_call_context = mono_class_get_method_from_name (klass, "SetCurrentCallContext", -1);
309 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
310 method_needs_context_sink = mono_class_get_method_from_name (klass, "get_NeedsContextSink", -1);
312 module_initialized = TRUE;
317 mono_delegate_to_ftnptr (MonoDelegate *delegate)
319 MonoMethod *method, *wrapper;
321 uint32_t target_handle = 0;
326 if (delegate->delegate_trampoline)
327 return delegate->delegate_trampoline;
329 klass = ((MonoObject *)delegate)->vtable->klass;
330 g_assert (klass->delegate);
332 method = delegate->method;
334 if (mono_method_signature (method)->pinvoke) {
335 const char *exc_class, *exc_arg;
338 ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
340 g_assert (exc_class);
341 mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
346 if (delegate->target) {
347 /* Produce a location which can be embedded in JITted code */
348 target_handle = mono_gchandle_new_weakref (delegate->target, FALSE);
351 wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle);
353 delegate->delegate_trampoline = mono_compile_method (wrapper);
355 // Add the delegate to the delegate hash table
356 delegate_hash_table_add (delegate);
358 /* when the object is collected, collect the dynamic method, too */
359 mono_object_register_finalizer ((MonoObject*)delegate);
361 return delegate->delegate_trampoline;
365 * this hash table maps from a delegate trampoline object to a weak reference
366 * of the delegate. As an optimizations with a non-moving GC we store the
367 * object pointer itself, otherwise we use a GC handle.
369 static GHashTable *delegate_hash_table;
372 delegate_hash_table_new (void) {
373 return g_hash_table_new (NULL, NULL);
377 delegate_hash_table_remove (MonoDelegate *d)
379 #ifdef HAVE_MOVING_COLLECTOR
382 mono_marshal_lock ();
383 if (delegate_hash_table == NULL)
384 delegate_hash_table = delegate_hash_table_new ();
385 #ifdef HAVE_MOVING_COLLECTOR
386 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
388 g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
389 mono_marshal_unlock ();
390 #ifdef HAVE_MOVING_COLLECTOR
391 mono_gchandle_free (gchandle);
396 delegate_hash_table_add (MonoDelegate *d)
398 #ifdef HAVE_MOVING_COLLECTOR
399 guint32 gchandle = mono_gchandle_new_weakref ((MonoObject*)d, FALSE);
400 guint32 old_gchandle;
402 mono_marshal_lock ();
403 if (delegate_hash_table == NULL)
404 delegate_hash_table = delegate_hash_table_new ();
405 #ifdef HAVE_MOVING_COLLECTOR
406 old_gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
407 g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, GUINT_TO_POINTER (gchandle));
409 mono_gchandle_free (old_gchandle);
411 g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d);
413 mono_marshal_unlock ();
417 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
419 #ifdef HAVE_MOVING_COLLECTOR
427 mono_marshal_lock ();
428 if (delegate_hash_table == NULL)
429 delegate_hash_table = delegate_hash_table_new ();
431 #ifdef HAVE_MOVING_COLLECTOR
432 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, ftn));
433 mono_marshal_unlock ();
435 d = (MonoDelegate*)mono_gchandle_get_target (gchandle);
439 d = g_hash_table_lookup (delegate_hash_table, ftn);
440 mono_marshal_unlock ();
443 /* This is a native function, so construct a delegate for it */
444 static MonoClass *UnmanagedFunctionPointerAttribute;
445 MonoMethodSignature *sig;
447 MonoMarshalSpec **mspecs;
448 MonoCustomAttrInfo *cinfo;
449 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
450 MonoMethod *invoke = mono_get_delegate_invoke (klass);
451 MonoMethodPInvoke piinfo;
454 memset (&piinfo, 0, sizeof (piinfo));
455 if (!UnmanagedFunctionPointerAttribute)
456 UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
458 /* The attribute is only available in Net 2.0 */
459 if (UnmanagedFunctionPointerAttribute) {
461 * The pinvoke attributes are stored in a real custom attribute so we have to
464 cinfo = mono_custom_attrs_from_class (klass);
466 attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
468 piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
471 mono_custom_attrs_free (cinfo);
475 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
476 mono_method_get_marshal_info (invoke, mspecs);
477 /* Freed below so don't alloc from mempool */
478 sig = mono_metadata_signature_dup (mono_method_signature (invoke));
481 wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn);
483 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
485 mono_metadata_free_marshal_spec (mspecs [i]);
489 d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
490 mono_delegate_ctor_with_method ((MonoObject*)d, NULL, mono_compile_method (wrapper), wrapper);
493 if (d->object.vtable->domain != mono_domain_get ())
494 mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
500 mono_delegate_free_ftnptr (MonoDelegate *delegate)
505 delegate_hash_table_remove (delegate);
507 ptr = (gpointer)InterlockedExchangePointer (&delegate->delegate_trampoline, NULL);
509 if (!delegate->target) {
510 /* The wrapper method is shared between delegates -> no need to free it */
517 ji = mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr));
520 method_data = ((MonoMethodWrapper*)ji->method)->method_data;
522 /*the target gchandle is the first entry after size and the wrapper itself.*/
523 gchandle = GPOINTER_TO_UINT (method_data [2]);
526 mono_gchandle_free (gchandle);
528 mono_runtime_free_method (mono_object_domain (delegate), ji->method);
533 mono_array_to_savearray (MonoArray *array)
538 g_assert_not_reached ();
543 mono_array_to_lparray (MonoArray *array)
545 gpointer *nativeArray = NULL;
546 int nativeArraySize = 0;
555 klass = array->obj.vtable->klass;
557 switch (klass->element_class->byval_arg.type) {
559 g_assert_not_reached ();
562 case MONO_TYPE_CLASS:
563 nativeArraySize = array->max_length;
564 nativeArray = malloc(sizeof(gpointer) * nativeArraySize);
565 for(i = 0; i < nativeArraySize; ++i)
566 nativeArray[i] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((gpointer*)array->vector)[i]);
570 case MONO_TYPE_BOOLEAN:
583 case MONO_TYPE_VALUETYPE:
587 case MONO_TYPE_GENERICINST:
588 case MONO_TYPE_OBJECT:
589 case MONO_TYPE_ARRAY:
590 case MONO_TYPE_SZARRAY:
591 case MONO_TYPE_STRING:
593 g_warning ("type 0x%x not handled", klass->element_class->byval_arg.type);
594 g_assert_not_reached ();
597 return array->vector;
601 mono_free_lparray (MonoArray *array, gpointer* nativeArray)
612 klass = array->obj.vtable->klass;
614 switch (klass->element_class->byval_arg.type) {
615 case MONO_TYPE_CLASS:
616 for(i = 0; i < array->max_length; ++i)
617 mono_marshal_free_ccw(nativeArray[i]);
625 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *elclass, guint32 elnum)
627 g_assert (arr->obj.vtable->klass->element_class == mono_defaults.char_class);
629 if (elclass == mono_defaults.byte_class) {
630 GError *error = NULL;
634 ut = g_utf8_to_utf16 (native_arr, elnum, NULL, &items_written, &error);
637 memcpy (mono_array_addr (arr, guint16, 0), ut, items_written * sizeof (guint16));
641 g_error_free (error);
644 g_assert_not_reached ();
648 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
650 g_assert (arr->obj.vtable->klass->element_class == mono_defaults.char_class);
652 if (elclass == mono_defaults.byte_class) {
654 GError *error = NULL;
656 as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
658 MonoException *exc = mono_get_exception_argument ("string", error->message);
659 g_error_free (error);
660 mono_raise_exception (exc);
663 memcpy (native_arr, as, MIN (strlen (as), elnum));
666 g_assert_not_reached ();
671 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
673 GError *error = NULL;
683 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
685 if (items_written > mono_stringbuilder_capacity (sb))
686 items_written = mono_stringbuilder_capacity (sb);
689 if (! sb->str || sb->str == sb->cached_str) {
690 MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), items_written));
691 sb->cached_str = NULL;
694 memcpy (mono_string_chars (sb->str), ut, items_written * 2);
695 sb->length = items_written;
697 g_error_free (error);
703 mono_string_utf8_to_builder2 (char *text)
706 MonoStringBuilder *sb;
707 static MonoClass *string_builder_class;
708 static MonoMethod *sb_ctor;
715 if (!string_builder_class) {
716 MonoMethodDesc *desc;
718 string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
719 g_assert (string_builder_class);
720 desc = mono_method_desc_new (":.ctor(int)", FALSE);
721 sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
723 mono_method_desc_free (desc);
728 sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
731 mono_runtime_invoke (sb_ctor, sb, args, &exc);
734 mono_string_utf8_to_builder (sb, text);
740 * FIXME: This routine does not seem to do what it seems to do
741 * the @text is never copied into the string builder
744 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
751 g_assert (mono_string_chars (sb->str) == text);
753 for (len = 0; text [len] != 0; ++len)
760 mono_string_utf16_to_builder2 (gunichar2 *text)
763 MonoStringBuilder *sb;
764 static MonoClass *string_builder_class;
765 static MonoMethod *sb_ctor;
772 if (!string_builder_class) {
773 MonoMethodDesc *desc;
775 string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
776 g_assert (string_builder_class);
777 desc = mono_method_desc_new (":.ctor(int)", FALSE);
778 sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
780 mono_method_desc_free (desc);
783 for (len = 0; text [len] != 0; ++len)
786 sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
789 mono_runtime_invoke (sb_ctor, sb, args, &exc);
793 memcpy (mono_string_chars (sb->str), text, len * 2);
799 * mono_string_builder_to_utf8:
800 * @sb: the string builder
802 * Converts to utf8 the contents of the MonoStringBuilder.
804 * Returns: a utf8 string with the contents of the StringBuilder.
806 * The return value must be released with g_free.
809 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
811 GError *error = NULL;
812 gchar *tmp, *res = NULL;
817 if ((sb->str == sb->cached_str) && (sb->str->length == 0)) {
819 * The sb could have been allocated with the default capacity and be empty.
820 * we need to alloc a buffer of the default capacity in this case.
822 MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
823 sb->cached_str = NULL;
826 tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, NULL, &error);
828 g_error_free (error);
829 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
831 res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
832 memcpy (res, tmp, sb->length + 1);
840 * mono_string_builder_to_utf16:
841 * @sb: the string builder
843 * Converts to utf16 the contents of the MonoStringBuilder.
845 * Returns: a utf16 string with the contents of the StringBuilder.
847 * The return value must not be freed.
850 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
858 * The stringbuilder might not have ownership of this string. If this is
859 * the case, we must duplicate the string, so that we don't munge immutable
862 if (sb->str == sb->cached_str) {
864 * The sb could have been allocated with the default capacity and be empty.
865 * we need to alloc a buffer of the default capacity in this case.
867 if (sb->str->length == 0)
868 MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
870 MONO_OBJECT_SETREF (sb, str, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb->str), mono_stringbuilder_capacity (sb)));
871 sb->cached_str = NULL;
875 *(mono_string_chars (sb->str)) = '\0';
877 return mono_string_chars (sb->str);
881 mono_string_to_lpstr (MonoString *s)
886 GError *error = NULL;
892 as = CoTaskMemAlloc (1);
897 tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
899 MonoException *exc = mono_get_exception_argument ("string", error->message);
900 g_error_free (error);
901 mono_raise_exception(exc);
904 as = CoTaskMemAlloc (len + 1);
905 memcpy (as, tmp, len + 1);
910 return mono_string_to_utf8 (s);
915 mono_string_to_ansibstr (MonoString *string_obj)
917 g_error ("UnmanagedMarshal.BStr is not implemented.");
922 * mono_string_to_byvalstr:
923 * @dst: Where to store the null-terminated utf8 decoded string.
924 * @src: the MonoString to copy.
925 * @size: the maximum number of bytes to copy.
927 * Copies the MonoString pointed to by @src as a utf8 string
928 * into @dst, it copies at most @size bytes into the destination.
931 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
936 g_assert (dst != NULL);
939 memset (dst, 0, size);
943 s = mono_string_to_utf8 (src);
944 len = MIN (size, strlen (s));
947 memcpy (dst, s, len);
952 * mono_string_to_byvalwstr:
953 * @dst: Where to store the null-terminated utf16 decoded string.
954 * @src: the MonoString to copy.
955 * @size: the maximum number of bytes to copy.
957 * Copies the MonoString pointed to by @src as a utf16 string into
958 * @dst, it copies at most @size bytes into the destination (including
959 * a terminating 16-bit zero terminator).
962 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
966 g_assert (dst != NULL);
970 memset (dst, 0, size * 2);
974 len = MIN (size, (mono_string_length (src)));
975 memcpy (dst, mono_string_chars (src), size * 2);
976 if (size <= mono_string_length (src))
978 *((gunichar2 *) dst + len) = 0;
982 mono_string_new_len_wrapper (const char *text, guint length)
984 return mono_string_new_len (mono_domain_get (), text, length);
988 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
991 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
992 mono_mb_emit_byte (mb, CEE_LDIND_I);
993 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
994 mono_mb_emit_byte (mb, CEE_ADD);
995 mono_mb_emit_byte (mb, CEE_LDIND_I);
996 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
997 mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
998 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
999 pos = mono_mb_emit_branch (mb, branch_code);
1004 mono_mb_emit_xdomain_check (MonoMethodBuilder *mb, int branch_code)
1007 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1008 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1009 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
1010 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1011 mono_mb_emit_icon (mb, -1);
1012 pos = mono_mb_emit_branch (mb, branch_code);
1017 mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code)
1019 static int offset = -1;
1023 mono_marshal_find_bitfield_offset (MonoClass, contextbound, &offset, &mask);
1025 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
1026 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1027 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
1028 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1029 mono_mb_emit_ldflda (mb, offset);
1030 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1031 mono_mb_emit_icon (mb, mask);
1032 mono_mb_emit_byte (mb, CEE_AND);
1033 mono_mb_emit_icon (mb, 0);
1034 return mono_mb_emit_branch (mb, branch_code);
1038 * mono_mb_emit_exception_marshal_directive:
1040 * This function assumes ownership of MSG, which should be malloc-ed.
1043 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg)
1048 s = mono_image_strdup (mb->method->klass->image, msg);
1053 mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", s);
1057 mono_type_to_ldind (MonoType *type)
1063 switch (type->type) {
1065 return CEE_LDIND_I1;
1067 case MONO_TYPE_BOOLEAN:
1068 return CEE_LDIND_U1;
1070 return CEE_LDIND_I2;
1072 case MONO_TYPE_CHAR:
1073 return CEE_LDIND_U2;
1075 return CEE_LDIND_I4;
1077 return CEE_LDIND_U4;
1081 case MONO_TYPE_FNPTR:
1083 case MONO_TYPE_CLASS:
1084 case MONO_TYPE_STRING:
1085 case MONO_TYPE_OBJECT:
1086 case MONO_TYPE_SZARRAY:
1087 case MONO_TYPE_ARRAY:
1088 return CEE_LDIND_REF;
1091 return CEE_LDIND_I8;
1093 return CEE_LDIND_R4;
1095 return CEE_LDIND_R8;
1096 case MONO_TYPE_VALUETYPE:
1097 if (type->data.klass->enumtype) {
1098 type = mono_class_enum_basetype (type->data.klass);
1102 case MONO_TYPE_TYPEDBYREF:
1104 case MONO_TYPE_GENERICINST:
1105 type = &type->data.generic_class->container_class->byval_arg;
1108 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
1114 mono_type_to_stind (MonoType *type)
1120 switch (type->type) {
1123 case MONO_TYPE_BOOLEAN:
1124 return CEE_STIND_I1;
1127 case MONO_TYPE_CHAR:
1128 return CEE_STIND_I2;
1131 return CEE_STIND_I4;
1135 case MONO_TYPE_FNPTR:
1137 case MONO_TYPE_CLASS:
1138 case MONO_TYPE_STRING:
1139 case MONO_TYPE_OBJECT:
1140 case MONO_TYPE_SZARRAY:
1141 case MONO_TYPE_ARRAY:
1142 return CEE_STIND_REF;
1145 return CEE_STIND_I8;
1147 return CEE_STIND_R4;
1149 return CEE_STIND_R8;
1150 case MONO_TYPE_VALUETYPE:
1151 if (type->data.klass->enumtype) {
1152 type = mono_class_enum_basetype (type->data.klass);
1156 case MONO_TYPE_TYPEDBYREF:
1158 case MONO_TYPE_GENERICINST:
1159 type = &type->data.generic_class->container_class->byval_arg;
1162 g_error ("unknown type 0x%02x in type_to_stind", type->type);
1168 emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1171 case MONO_MARSHAL_CONV_BOOL_I4:
1172 mono_mb_emit_ldloc (mb, 1);
1173 mono_mb_emit_ldloc (mb, 0);
1174 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1175 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1176 mono_mb_emit_byte (mb, 3);
1177 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1178 mono_mb_emit_byte (mb, CEE_BR_S);
1179 mono_mb_emit_byte (mb, 1);
1180 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1181 mono_mb_emit_byte (mb, CEE_STIND_I1);
1183 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1184 mono_mb_emit_ldloc (mb, 1);
1185 mono_mb_emit_ldloc (mb, 0);
1186 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1187 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1188 mono_mb_emit_byte (mb, 3);
1189 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1190 mono_mb_emit_byte (mb, CEE_BR_S);
1191 mono_mb_emit_byte (mb, 1);
1192 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1193 mono_mb_emit_byte (mb, CEE_STIND_I1);
1195 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1196 MonoClass *eklass = NULL;
1199 if (type->type == MONO_TYPE_SZARRAY) {
1200 eklass = type->data.klass;
1202 g_assert_not_reached ();
1205 esize = mono_class_native_size (eklass, NULL);
1207 /* create a new array */
1208 mono_mb_emit_ldloc (mb, 1);
1209 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1210 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
1211 mono_mb_emit_byte (mb, CEE_STIND_I);
1213 if (eklass->blittable) {
1214 /* copy the elements */
1215 mono_mb_emit_ldloc (mb, 1);
1216 mono_mb_emit_byte (mb, CEE_LDIND_I);
1217 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
1218 mono_mb_emit_byte (mb, CEE_ADD);
1219 mono_mb_emit_ldloc (mb, 0);
1220 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1221 mono_mb_emit_byte (mb, CEE_PREFIX1);
1222 mono_mb_emit_byte (mb, CEE_CPBLK);
1225 int array_var, src_var, dst_var, index_var;
1226 guint32 label2, label3;
1228 array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1229 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1230 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1233 mono_mb_emit_ldloc (mb, 1);
1234 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1235 mono_mb_emit_stloc (mb, array_var);
1237 /* save the old src pointer */
1238 mono_mb_emit_ldloc (mb, 0);
1239 mono_mb_emit_stloc (mb, src_var);
1240 /* save the old dst pointer */
1241 mono_mb_emit_ldloc (mb, 1);
1242 mono_mb_emit_stloc (mb, dst_var);
1244 /* Emit marshalling loop */
1245 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1246 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1247 mono_mb_emit_stloc (mb, index_var);
1250 label2 = mono_mb_get_label (mb);
1251 mono_mb_emit_ldloc (mb, index_var);
1252 mono_mb_emit_ldloc (mb, array_var);
1253 mono_mb_emit_byte (mb, CEE_LDLEN);
1254 label3 = mono_mb_emit_branch (mb, CEE_BGE);
1256 /* src is already set */
1259 mono_mb_emit_ldloc (mb, array_var);
1260 mono_mb_emit_ldloc (mb, index_var);
1261 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
1262 mono_mb_emit_stloc (mb, 1);
1264 /* Do the conversion */
1265 emit_struct_conv (mb, eklass, TRUE);
1268 mono_mb_emit_add_to_local (mb, index_var, 1);
1270 mono_mb_emit_branch_label (mb, CEE_BR, label2);
1272 mono_mb_patch_branch (mb, label3);
1274 /* restore the old src pointer */
1275 mono_mb_emit_ldloc (mb, src_var);
1276 mono_mb_emit_stloc (mb, 0);
1277 /* restore the old dst pointer */
1278 mono_mb_emit_ldloc (mb, dst_var);
1279 mono_mb_emit_stloc (mb, 1);
1283 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
1284 MonoClass *eclass = mono_defaults.char_class;
1286 /* create a new array */
1287 mono_mb_emit_ldloc (mb, 1);
1288 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1289 mono_mb_emit_op (mb, CEE_NEWARR, eclass);
1290 mono_mb_emit_byte (mb, CEE_STIND_REF);
1292 mono_mb_emit_ldloc (mb, 1);
1293 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1294 mono_mb_emit_ldloc (mb, 0);
1295 mono_mb_emit_ptr (mb, mono_defaults.byte_class);
1296 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1297 mono_mb_emit_icall (mb, mono_byvalarray_to_array);
1300 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1301 mono_mb_emit_ldloc (mb, 1);
1302 mono_mb_emit_ldloc (mb, 0);
1303 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1304 mono_mb_emit_byte (mb, CEE_STIND_REF);
1306 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1307 mono_mb_emit_ldloc (mb, 1);
1308 mono_mb_emit_ldloc (mb, 0);
1309 mono_mb_emit_icall (mb, mono_string_from_utf16);
1310 mono_mb_emit_byte (mb, CEE_STIND_REF);
1312 case MONO_MARSHAL_CONV_STR_LPTSTR:
1313 mono_mb_emit_ldloc (mb, 1);
1314 mono_mb_emit_ldloc (mb, 0);
1315 mono_mb_emit_byte (mb, CEE_LDIND_I);
1317 mono_mb_emit_icall (mb, mono_string_from_utf16);
1319 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1321 mono_mb_emit_byte (mb, CEE_STIND_REF);
1323 case MONO_MARSHAL_CONV_STR_LPSTR:
1324 mono_mb_emit_ldloc (mb, 1);
1325 mono_mb_emit_ldloc (mb, 0);
1326 mono_mb_emit_byte (mb, CEE_LDIND_I);
1327 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1328 mono_mb_emit_byte (mb, CEE_STIND_REF);
1330 case MONO_MARSHAL_CONV_STR_LPWSTR:
1331 mono_mb_emit_ldloc (mb, 1);
1332 mono_mb_emit_ldloc (mb, 0);
1333 mono_mb_emit_byte (mb, CEE_LDIND_I);
1334 mono_mb_emit_icall (mb, mono_string_from_utf16);
1335 mono_mb_emit_byte (mb, CEE_STIND_REF);
1337 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1338 MonoClass *klass = mono_class_from_mono_type (type);
1339 int src_var, dst_var;
1341 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1342 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1344 /* *dst = new object */
1345 mono_mb_emit_ldloc (mb, 1);
1346 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1347 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
1348 mono_mb_emit_byte (mb, CEE_STIND_REF);
1350 /* save the old src pointer */
1351 mono_mb_emit_ldloc (mb, 0);
1352 mono_mb_emit_stloc (mb, src_var);
1353 /* save the old dst pointer */
1354 mono_mb_emit_ldloc (mb, 1);
1355 mono_mb_emit_stloc (mb, dst_var);
1357 /* dst = pointer to newly created object data */
1358 mono_mb_emit_ldloc (mb, 1);
1359 mono_mb_emit_byte (mb, CEE_LDIND_I);
1360 mono_mb_emit_icon (mb, sizeof (MonoObject));
1361 mono_mb_emit_byte (mb, CEE_ADD);
1362 mono_mb_emit_stloc (mb, 1);
1364 emit_struct_conv (mb, klass, TRUE);
1366 /* restore the old src pointer */
1367 mono_mb_emit_ldloc (mb, src_var);
1368 mono_mb_emit_stloc (mb, 0);
1369 /* restore the old dst pointer */
1370 mono_mb_emit_ldloc (mb, dst_var);
1371 mono_mb_emit_stloc (mb, 1);
1374 case MONO_MARSHAL_CONV_DEL_FTN: {
1375 MonoClass *klass = mono_class_from_mono_type (type);
1377 mono_mb_emit_ldloc (mb, 1);
1378 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1379 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
1380 mono_mb_emit_ldloc (mb, 0);
1381 mono_mb_emit_byte (mb, CEE_LDIND_I);
1382 mono_mb_emit_icall (mb, mono_ftnptr_to_delegate);
1383 mono_mb_emit_byte (mb, CEE_STIND_REF);
1386 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1387 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
1391 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
1392 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
1393 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
1394 mono_cominterop_emit_ptr_to_object_conv (mb, type, conv, mspec);
1396 #endif /* DISABLE_COM */
1398 case MONO_MARSHAL_CONV_SAFEHANDLE: {
1400 * Passing SafeHandles as ref does not allow the unmanaged code
1401 * to change the SafeHandle value. If the value is changed,
1402 * we should issue a diagnostic exception (NotSupportedException)
1403 * that informs the user that changes to handles in unmanaged code
1406 * Since we currently have no access to the original
1407 * SafeHandle that was used during the marshalling,
1408 * for now we just ignore this, and ignore/discard any
1409 * changes that might have happened to the handle.
1414 case MONO_MARSHAL_CONV_HANDLEREF: {
1416 * Passing HandleRefs in a struct that is ref()ed does not
1417 * copy the values back to the HandleRef
1422 case MONO_MARSHAL_CONV_STR_BSTR:
1423 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1424 case MONO_MARSHAL_CONV_STR_TBSTR:
1425 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1427 char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv);
1429 mono_mb_emit_exception_marshal_directive (mb, msg);
1436 conv_to_icall (MonoMarshalConv conv)
1439 case MONO_MARSHAL_CONV_STR_LPWSTR:
1440 return mono_marshal_string_to_utf16;
1441 case MONO_MARSHAL_CONV_LPWSTR_STR:
1442 return mono_string_from_utf16;
1443 case MONO_MARSHAL_CONV_LPTSTR_STR:
1445 return mono_string_from_utf16;
1447 return mono_string_new_wrapper;
1449 case MONO_MARSHAL_CONV_LPSTR_STR:
1450 return mono_string_new_wrapper;
1451 case MONO_MARSHAL_CONV_STR_LPTSTR:
1453 return mono_marshal_string_to_utf16;
1455 return mono_string_to_lpstr;
1457 case MONO_MARSHAL_CONV_STR_LPSTR:
1458 return mono_string_to_lpstr;
1459 case MONO_MARSHAL_CONV_STR_BSTR:
1460 return mono_string_to_bstr;
1461 case MONO_MARSHAL_CONV_BSTR_STR:
1462 return mono_string_from_bstr;
1463 case MONO_MARSHAL_CONV_STR_TBSTR:
1464 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1465 return mono_string_to_ansibstr;
1466 case MONO_MARSHAL_CONV_SB_LPSTR:
1467 return mono_string_builder_to_utf8;
1468 case MONO_MARSHAL_CONV_SB_LPTSTR:
1470 return mono_string_builder_to_utf16;
1472 return mono_string_builder_to_utf8;
1474 case MONO_MARSHAL_CONV_SB_LPWSTR:
1475 return mono_string_builder_to_utf16;
1476 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1477 return mono_array_to_savearray;
1478 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1479 return mono_array_to_lparray;
1480 case MONO_MARSHAL_FREE_LPARRAY:
1481 return mono_free_lparray;
1482 case MONO_MARSHAL_CONV_DEL_FTN:
1483 return mono_delegate_to_ftnptr;
1484 case MONO_MARSHAL_CONV_FTN_DEL:
1485 return mono_ftnptr_to_delegate;
1486 case MONO_MARSHAL_CONV_LPSTR_SB:
1487 return mono_string_utf8_to_builder;
1488 case MONO_MARSHAL_CONV_LPTSTR_SB:
1490 return mono_string_utf16_to_builder;
1492 return mono_string_utf8_to_builder;
1494 case MONO_MARSHAL_CONV_LPWSTR_SB:
1495 return mono_string_utf16_to_builder;
1496 case MONO_MARSHAL_FREE_ARRAY:
1497 return mono_marshal_free_array;
1498 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1499 return mono_string_to_byvalstr;
1500 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1501 return mono_string_to_byvalwstr;
1503 g_assert_not_reached ();
1510 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1515 case MONO_MARSHAL_CONV_BOOL_I4:
1516 mono_mb_emit_ldloc (mb, 1);
1517 mono_mb_emit_ldloc (mb, 0);
1518 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1519 mono_mb_emit_byte (mb, CEE_STIND_I4);
1521 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1522 mono_mb_emit_ldloc (mb, 1);
1523 mono_mb_emit_ldloc (mb, 0);
1524 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1525 mono_mb_emit_byte (mb, CEE_NEG);
1526 mono_mb_emit_byte (mb, CEE_STIND_I2);
1528 case MONO_MARSHAL_CONV_STR_LPWSTR:
1529 case MONO_MARSHAL_CONV_STR_LPSTR:
1530 case MONO_MARSHAL_CONV_STR_LPTSTR:
1531 case MONO_MARSHAL_CONV_STR_BSTR:
1532 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1533 case MONO_MARSHAL_CONV_STR_TBSTR: {
1536 /* free space if free == true */
1537 mono_mb_emit_ldloc (mb, 2);
1538 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1539 mono_mb_emit_ldloc (mb, 1);
1540 mono_mb_emit_byte (mb, CEE_LDIND_I);
1541 mono_mb_emit_icall (mb, g_free);
1542 mono_mb_patch_short_branch (mb, pos);
1544 mono_mb_emit_ldloc (mb, 1);
1545 mono_mb_emit_ldloc (mb, 0);
1546 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1547 mono_mb_emit_icall (mb, conv_to_icall (conv));
1548 mono_mb_emit_byte (mb, CEE_STIND_I);
1551 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1552 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1553 case MONO_MARSHAL_CONV_DEL_FTN:
1554 mono_mb_emit_ldloc (mb, 1);
1555 mono_mb_emit_ldloc (mb, 0);
1556 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1557 mono_mb_emit_icall (mb, conv_to_icall (conv));
1558 mono_mb_emit_byte (mb, CEE_STIND_I);
1560 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1561 case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
1564 mono_mb_emit_ldloc (mb, 1); /* dst */
1565 mono_mb_emit_ldloc (mb, 0);
1566 mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
1567 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1568 mono_mb_emit_icall (mb, conv_to_icall (conv));
1571 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1572 MonoClass *eklass = NULL;
1575 if (type->type == MONO_TYPE_SZARRAY) {
1576 eklass = type->data.klass;
1578 g_assert_not_reached ();
1581 if (eklass->valuetype)
1582 esize = mono_class_native_size (eklass, NULL);
1584 esize = sizeof (gpointer);
1586 mono_mb_emit_ldloc (mb, 0);
1587 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1588 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
1590 if (eklass->blittable) {
1591 mono_mb_emit_ldloc (mb, 1);
1592 mono_mb_emit_ldloc (mb, 0);
1593 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1594 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
1595 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1596 mono_mb_emit_byte (mb, CEE_PREFIX1);
1597 mono_mb_emit_byte (mb, CEE_CPBLK);
1599 int array_var, src_var, dst_var, index_var;
1600 guint32 label2, label3;
1602 array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1603 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1604 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1607 mono_mb_emit_ldloc (mb, 0);
1608 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1609 mono_mb_emit_stloc (mb, array_var);
1611 /* save the old src pointer */
1612 mono_mb_emit_ldloc (mb, 0);
1613 mono_mb_emit_stloc (mb, src_var);
1614 /* save the old dst pointer */
1615 mono_mb_emit_ldloc (mb, 1);
1616 mono_mb_emit_stloc (mb, dst_var);
1618 /* Emit marshalling loop */
1619 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1620 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1621 mono_mb_emit_stloc (mb, index_var);
1624 label2 = mono_mb_get_label (mb);
1625 mono_mb_emit_ldloc (mb, index_var);
1626 mono_mb_emit_ldloc (mb, array_var);
1627 mono_mb_emit_byte (mb, CEE_LDLEN);
1628 label3 = mono_mb_emit_branch (mb, CEE_BGE);
1631 mono_mb_emit_ldloc (mb, array_var);
1632 mono_mb_emit_ldloc (mb, index_var);
1633 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
1634 mono_mb_emit_stloc (mb, 0);
1636 /* dst is already set */
1638 /* Do the conversion */
1639 emit_struct_conv (mb, eklass, FALSE);
1642 mono_mb_emit_add_to_local (mb, index_var, 1);
1644 mono_mb_emit_branch_label (mb, CEE_BR, label2);
1646 mono_mb_patch_branch (mb, label3);
1648 /* restore the old src pointer */
1649 mono_mb_emit_ldloc (mb, src_var);
1650 mono_mb_emit_stloc (mb, 0);
1651 /* restore the old dst pointer */
1652 mono_mb_emit_ldloc (mb, dst_var);
1653 mono_mb_emit_stloc (mb, 1);
1656 mono_mb_patch_branch (mb, pos);
1659 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
1660 mono_mb_emit_ldloc (mb, 0);
1661 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1662 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1664 mono_mb_emit_ldloc (mb, 1);
1665 mono_mb_emit_ldloc (mb, 0);
1666 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1667 mono_mb_emit_ptr (mb, mono_defaults.byte_class);
1668 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1669 mono_mb_emit_icall (mb, mono_array_to_byvalarray);
1670 mono_mb_patch_short_branch (mb, pos);
1673 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1674 int src_var, dst_var;
1676 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1677 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1679 mono_mb_emit_ldloc (mb, 0);
1680 mono_mb_emit_byte (mb, CEE_LDIND_I);
1681 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
1683 /* save the old src pointer */
1684 mono_mb_emit_ldloc (mb, 0);
1685 mono_mb_emit_stloc (mb, src_var);
1686 /* save the old dst pointer */
1687 mono_mb_emit_ldloc (mb, 1);
1688 mono_mb_emit_stloc (mb, dst_var);
1690 /* src = pointer to object data */
1691 mono_mb_emit_ldloc (mb, 0);
1692 mono_mb_emit_byte (mb, CEE_LDIND_I);
1693 mono_mb_emit_icon (mb, sizeof (MonoObject));
1694 mono_mb_emit_byte (mb, CEE_ADD);
1695 mono_mb_emit_stloc (mb, 0);
1697 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
1699 /* restore the old src pointer */
1700 mono_mb_emit_ldloc (mb, src_var);
1701 mono_mb_emit_stloc (mb, 0);
1702 /* restore the old dst pointer */
1703 mono_mb_emit_ldloc (mb, dst_var);
1704 mono_mb_emit_stloc (mb, 1);
1706 mono_mb_patch_branch (mb, pos);
1711 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
1712 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
1713 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
1714 mono_cominterop_emit_object_to_ptr_conv (mb, type, conv, mspec);
1716 #endif /* DISABLE_COM */
1718 case MONO_MARSHAL_CONV_SAFEHANDLE: {
1719 int dar_release_slot, pos;
1721 dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
1724 * The following is ifdefed-out, because I have no way of doing the
1725 * DangerousRelease when destroying the structure
1728 /* set release = false */
1729 mono_mb_emit_icon (mb, 0);
1730 mono_mb_emit_stloc (mb, dar_release_slot);
1731 if (!sh_dangerous_add_ref)
1732 init_safe_handle ();
1734 /* safehandle.DangerousAddRef (ref release) */
1735 mono_mb_emit_ldloc (mb, 0); /* the source */
1736 mono_mb_emit_byte (mb, CEE_LDIND_I);
1737 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
1738 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
1740 mono_mb_emit_ldloc (mb, 0);
1741 mono_mb_emit_byte (mb, CEE_LDIND_I);
1742 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
1743 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
1744 mono_mb_patch_branch (mb, pos);
1746 /* Pull the handle field from SafeHandle */
1747 mono_mb_emit_ldloc (mb, 1);
1748 mono_mb_emit_ldloc (mb, 0);
1749 mono_mb_emit_byte (mb, CEE_LDIND_I);
1750 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
1751 mono_mb_emit_byte (mb, CEE_LDIND_I);
1752 mono_mb_emit_byte (mb, CEE_STIND_I);
1756 case MONO_MARSHAL_CONV_HANDLEREF: {
1757 mono_mb_emit_ldloc (mb, 1);
1758 mono_mb_emit_ldloc (mb, 0);
1759 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
1760 mono_mb_emit_byte (mb, CEE_ADD);
1761 mono_mb_emit_byte (mb, CEE_LDIND_I);
1762 mono_mb_emit_byte (mb, CEE_STIND_I);
1767 char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
1768 MonoException *exc = mono_get_exception_not_implemented (msg);
1769 g_warning ("%s", msg);
1771 mono_raise_exception (exc);
1777 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
1778 MonoMarshalNative string_encoding)
1780 MonoMarshalType *info;
1784 emit_struct_conv(mb, klass->parent, to_object);
1786 info = mono_marshal_load_type_info (klass);
1788 if (info->native_size == 0)
1791 if (klass->blittable) {
1792 int msize = mono_class_value_size (klass, NULL);
1793 g_assert (msize == info->native_size);
1794 mono_mb_emit_ldloc (mb, 1);
1795 mono_mb_emit_ldloc (mb, 0);
1796 mono_mb_emit_icon (mb, msize);
1797 mono_mb_emit_byte (mb, CEE_PREFIX1);
1798 mono_mb_emit_byte (mb, CEE_CPBLK);
1800 mono_mb_emit_add_to_local (mb, 0, msize);
1801 mono_mb_emit_add_to_local (mb, 1, msize);
1805 if (klass != mono_defaults.safehandle_class) {
1806 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1807 char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
1808 mono_type_full_name (&klass->byval_arg));
1809 mono_mb_emit_exception_marshal_directive (mb, msg);
1814 for (i = 0; i < info->num_fields; i++) {
1815 MonoMarshalNative ntype;
1816 MonoMarshalConv conv;
1817 MonoType *ftype = info->fields [i].field->type;
1820 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
1822 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
1825 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
1828 msize = klass->instance_size - info->fields [i].field->offset;
1829 usize = info->native_size - info->fields [i].offset;
1831 msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
1832 usize = info->fields [i + 1].offset - info->fields [i].offset;
1835 if (klass != mono_defaults.safehandle_class){
1837 * FIXME: Should really check for usize==0 and msize>0, but we apply
1838 * the layout to the managed structure as well.
1841 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
1842 if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
1843 ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
1844 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
1845 "reference field at the same offset as another field.",
1846 mono_type_full_name (&klass->byval_arg));
1851 case MONO_MARSHAL_CONV_NONE: {
1854 if (ftype->byref || ftype->type == MONO_TYPE_I ||
1855 ftype->type == MONO_TYPE_U) {
1856 mono_mb_emit_ldloc (mb, 1);
1857 mono_mb_emit_ldloc (mb, 0);
1858 mono_mb_emit_byte (mb, CEE_LDIND_I);
1859 mono_mb_emit_byte (mb, CEE_STIND_I);
1870 case MONO_TYPE_BOOLEAN:
1873 case MONO_TYPE_CHAR:
1879 mono_mb_emit_ldloc (mb, 1);
1880 mono_mb_emit_ldloc (mb, 0);
1881 if (t == MONO_TYPE_CHAR && ntype == MONO_NATIVE_U1 && string_encoding != MONO_NATIVE_LPWSTR) {
1883 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1884 mono_mb_emit_byte (mb, CEE_STIND_I2);
1886 mono_mb_emit_byte (mb, CEE_LDIND_U2);
1887 mono_mb_emit_byte (mb, CEE_STIND_I1);
1890 mono_mb_emit_byte (mb, mono_type_to_ldind (ftype));
1891 mono_mb_emit_byte (mb, mono_type_to_stind (ftype));
1894 case MONO_TYPE_VALUETYPE: {
1895 int src_var, dst_var;
1897 if (ftype->data.klass->enumtype) {
1898 ftype = mono_class_enum_basetype (ftype->data.klass);
1902 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1903 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1905 /* save the old src pointer */
1906 mono_mb_emit_ldloc (mb, 0);
1907 mono_mb_emit_stloc (mb, src_var);
1908 /* save the old dst pointer */
1909 mono_mb_emit_ldloc (mb, 1);
1910 mono_mb_emit_stloc (mb, dst_var);
1912 emit_struct_conv (mb, ftype->data.klass, to_object);
1914 /* restore the old src pointer */
1915 mono_mb_emit_ldloc (mb, src_var);
1916 mono_mb_emit_stloc (mb, 0);
1917 /* restore the old dst pointer */
1918 mono_mb_emit_ldloc (mb, dst_var);
1919 mono_mb_emit_stloc (mb, 1);
1922 case MONO_TYPE_OBJECT: {
1923 mono_init_com_types ();
1925 static MonoMethod *variant_clear = NULL;
1926 static MonoMethod *get_object_for_native_variant = NULL;
1929 variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
1930 if (!get_object_for_native_variant)
1931 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
1932 mono_mb_emit_ldloc (mb, 1);
1933 mono_mb_emit_ldloc (mb, 0);
1934 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
1935 mono_mb_emit_byte (mb, CEE_STIND_REF);
1937 mono_mb_emit_ldloc (mb, 0);
1938 mono_mb_emit_managed_call (mb, variant_clear, NULL);
1941 static MonoMethod *get_native_variant_for_object = NULL;
1943 if (!get_native_variant_for_object)
1944 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
1946 mono_mb_emit_ldloc (mb, 0);
1947 mono_mb_emit_byte(mb, CEE_LDIND_REF);
1948 mono_mb_emit_ldloc (mb, 1);
1949 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
1955 g_warning ("marshaling type %02x not implemented", ftype->type);
1956 g_assert_not_reached ();
1961 int src_var, dst_var;
1963 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1964 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1966 /* save the old src pointer */
1967 mono_mb_emit_ldloc (mb, 0);
1968 mono_mb_emit_stloc (mb, src_var);
1969 /* save the old dst pointer */
1970 mono_mb_emit_ldloc (mb, 1);
1971 mono_mb_emit_stloc (mb, dst_var);
1974 emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec);
1976 emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec);
1978 /* restore the old src pointer */
1979 mono_mb_emit_ldloc (mb, src_var);
1980 mono_mb_emit_stloc (mb, 0);
1981 /* restore the old dst pointer */
1982 mono_mb_emit_ldloc (mb, dst_var);
1983 mono_mb_emit_stloc (mb, 1);
1988 mono_mb_emit_add_to_local (mb, 0, usize);
1989 mono_mb_emit_add_to_local (mb, 1, msize);
1991 mono_mb_emit_add_to_local (mb, 0, msize);
1992 mono_mb_emit_add_to_local (mb, 1, usize);
1998 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
2000 emit_struct_conv_full (mb, klass, to_object, -1);
2004 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
2006 /* Call DestroyStructure */
2007 /* FIXME: Only do this if needed */
2008 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2009 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
2010 mono_mb_emit_ldloc (mb, struct_var);
2011 mono_mb_emit_icall (mb, mono_struct_delete_old);
2015 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoint_func)
2019 mono_mb_emit_ptr (mb, (gpointer) mono_thread_interruption_request_flag ());
2020 mono_mb_emit_byte (mb, CEE_LDIND_U4);
2021 pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
2023 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2024 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
2026 mono_mb_emit_icall (mb, checkpoint_func);
2028 mono_mb_patch_branch (mb, pos_noabort);
2032 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
2034 if (strstr (mb->name, "mono_thread_interruption_checkpoint"))
2037 emit_thread_interrupt_checkpoint_call (mb, mono_thread_interruption_checkpoint);
2041 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
2043 emit_thread_interrupt_checkpoint_call (mb, mono_thread_force_interruption_checkpoint);
2047 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
2049 emit_thread_interrupt_checkpoint (mb);
2052 static MonoAsyncResult *
2053 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
2055 MonoMethodMessage *msg;
2056 MonoDelegate *async_callback;
2057 MonoMulticastDelegate *mcast_delegate;
2061 MonoMethod *method = NULL, *method2 = NULL;
2063 g_assert (delegate);
2064 mcast_delegate = (MonoMulticastDelegate *) delegate;
2065 if (mcast_delegate->prev != NULL)
2066 mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
2068 if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
2070 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
2071 if (!tp->remote_class->proxy_class->contextbound || tp->rp->context != (MonoObject *) mono_context_get ()) {
2073 /* If the target is a proxy, make a direct call. Is proxy's work
2074 // to make the call asynchronous.
2076 MonoAsyncResult *ares;
2078 MonoArray *out_args;
2079 method = delegate->method;
2081 msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
2082 ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL);
2083 MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
2084 MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
2085 MONO_OBJECT_SETREF (msg, async_result, ares);
2086 msg->call_type = CallType_BeginInvoke;
2089 mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
2091 mono_raise_exception ((MonoException *) exc);
2096 klass = delegate->object.vtable->klass;
2098 method = mono_get_delegate_invoke (klass);
2099 method2 = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
2102 g_assert (method != NULL);
2104 im = mono_get_delegate_invoke (method->klass);
2105 msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
2107 return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
2111 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
2113 int i, params_var, tmp_var;
2115 /* allocate local (pointer) *params[] */
2116 params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2117 /* allocate local (pointer) tmp */
2118 tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2120 /* alloate space on stack to store an array of pointers to the arguments */
2121 mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
2122 mono_mb_emit_byte (mb, CEE_PREFIX1);
2123 mono_mb_emit_byte (mb, CEE_LOCALLOC);
2124 mono_mb_emit_stloc (mb, params_var);
2127 mono_mb_emit_ldloc (mb, params_var);
2128 mono_mb_emit_stloc (mb, tmp_var);
2130 if (save_this && sig->hasthis) {
2131 mono_mb_emit_ldloc (mb, tmp_var);
2132 mono_mb_emit_ldarg_addr (mb, 0);
2133 mono_mb_emit_byte (mb, CEE_STIND_I);
2134 /* tmp = tmp + sizeof (gpointer) */
2135 if (sig->param_count)
2136 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
2140 for (i = 0; i < sig->param_count; i++) {
2141 mono_mb_emit_ldloc (mb, tmp_var);
2142 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
2143 mono_mb_emit_byte (mb, CEE_STIND_I);
2144 /* tmp = tmp + sizeof (gpointer) */
2145 if (i < (sig->param_count - 1))
2146 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
2153 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
2157 GString *res = g_string_new ("");
2160 g_string_append (res, prefix);
2161 g_string_append_c (res, '_');
2164 mono_type_get_desc (res, sig->ret, FALSE);
2167 g_string_append (res, "__this__");
2169 for (i = 0; i < sig->param_count; ++i) {
2170 g_string_append_c (res, '_');
2171 mono_type_get_desc (res, sig->params [i], FALSE);
2174 g_string_free (res, FALSE);
2179 * mono_marshal_get_string_encoding:
2181 * Return the string encoding which should be used for a given parameter.
2183 static MonoMarshalNative
2184 mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2186 /* First try the parameter marshal info */
2188 if (spec->native == MONO_NATIVE_LPARRAY) {
2189 if ((spec->data.array_data.elem_type != 0) && (spec->data.array_data.elem_type != MONO_NATIVE_MAX))
2190 return spec->data.array_data.elem_type;
2193 return spec->native;
2197 return MONO_NATIVE_LPSTR;
2199 /* Then try the method level marshal info */
2200 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
2201 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
2202 return MONO_NATIVE_LPSTR;
2203 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
2204 return MONO_NATIVE_LPWSTR;
2205 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
2207 return MONO_NATIVE_LPWSTR;
2209 return MONO_NATIVE_LPSTR;
2212 return MONO_NATIVE_LPSTR;
2216 static MonoMarshalConv
2217 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2219 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2222 case MONO_NATIVE_LPWSTR:
2223 return MONO_MARSHAL_CONV_STR_LPWSTR;
2224 case MONO_NATIVE_LPSTR:
2225 case MONO_NATIVE_VBBYREFSTR:
2226 return MONO_MARSHAL_CONV_STR_LPSTR;
2227 case MONO_NATIVE_LPTSTR:
2228 return MONO_MARSHAL_CONV_STR_LPTSTR;
2229 case MONO_NATIVE_BSTR:
2230 return MONO_MARSHAL_CONV_STR_BSTR;
2236 static MonoMarshalConv
2237 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2239 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2242 case MONO_NATIVE_LPWSTR:
2243 return MONO_MARSHAL_CONV_SB_LPWSTR;
2245 case MONO_NATIVE_LPSTR:
2246 return MONO_MARSHAL_CONV_SB_LPSTR;
2248 case MONO_NATIVE_LPTSTR:
2249 return MONO_MARSHAL_CONV_SB_LPTSTR;
2256 static MonoMarshalConv
2257 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
2259 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2264 case MONO_NATIVE_LPWSTR:
2266 return MONO_MARSHAL_CONV_LPWSTR_STR;
2267 case MONO_NATIVE_LPSTR:
2268 case MONO_NATIVE_VBBYREFSTR:
2269 return MONO_MARSHAL_CONV_LPSTR_STR;
2270 case MONO_NATIVE_LPTSTR:
2271 return MONO_MARSHAL_CONV_LPTSTR_STR;
2272 case MONO_NATIVE_BSTR:
2273 return MONO_MARSHAL_CONV_BSTR_STR;
2279 static MonoMarshalConv
2280 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
2282 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2287 case MONO_NATIVE_LPWSTR:
2289 * mono_string_builder_to_utf16 does not allocate a
2290 * new buffer, so no need to free it.
2293 return MONO_MARSHAL_CONV_LPWSTR_SB;
2294 case MONO_NATIVE_LPSTR:
2295 return MONO_MARSHAL_CONV_LPSTR_SB;
2297 case MONO_NATIVE_LPTSTR:
2298 return MONO_MARSHAL_CONV_LPTSTR_SB;
2306 * Return whenever a field of a native structure or an array member needs to
2310 mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2312 MonoMarshalNative encoding;
2313 MonoMarshalConv conv;
2316 case MONO_TYPE_VALUETYPE:
2317 /* FIXME: Optimize this */
2319 case MONO_TYPE_OBJECT:
2320 case MONO_TYPE_CLASS:
2321 if (t->data.klass == mono_defaults.stringbuilder_class) {
2323 conv = mono_marshal_get_ptr_to_stringbuilder_conv (piinfo, spec, &need_free);
2327 case MONO_TYPE_STRING:
2328 encoding = mono_marshal_get_string_encoding (piinfo, spec);
2329 return (encoding == MONO_NATIVE_LPWSTR) ? FALSE : TRUE;
2336 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
2339 get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
2342 mono_marshal_lock ();
2345 g_hash_table_new (hash_func, equal_func);
2346 mono_memory_barrier ();
2349 mono_marshal_unlock ();
2355 get_cache_full (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
2358 mono_marshal_lock ();
2361 g_hash_table_new_full (hash_func, equal_func, key_destroy_func, value_destroy_func);
2362 mono_memory_barrier ();
2365 mono_marshal_unlock ();
2371 mono_marshal_get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
2373 return get_cache (var, hash_func, equal_func);
2377 mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
2381 mono_marshal_lock ();
2382 res = g_hash_table_lookup (cache, key);
2383 mono_marshal_unlock ();
2387 /* Create the method from the builder and place it in the cache */
2389 mono_mb_create_and_cache (GHashTable *cache, gpointer key,
2390 MonoMethodBuilder *mb, MonoMethodSignature *sig,
2395 mono_marshal_lock ();
2396 res = g_hash_table_lookup (cache, key);
2397 mono_marshal_unlock ();
2400 newm = mono_mb_create_method (mb, sig, max_stack);
2401 mono_marshal_lock ();
2402 res = g_hash_table_lookup (cache, key);
2405 g_hash_table_insert (cache, key, res);
2406 mono_marshal_set_wrapper_info (res, key);
2407 mono_marshal_unlock ();
2409 mono_marshal_unlock ();
2410 mono_free_method (newm);
2418 static inline MonoMethod*
2419 mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type)
2421 MonoMethod *res = NULL;
2422 MonoRemotingMethods *wrps;
2424 mono_marshal_lock ();
2425 if (method->klass->image->remoting_invoke_cache)
2426 wrps = g_hash_table_lookup (method->klass->image->remoting_invoke_cache, method);
2431 switch (wrapper_type) {
2432 case MONO_WRAPPER_REMOTING_INVOKE: res = wrps->invoke; break;
2433 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = wrps->invoke_with_check; break;
2434 case MONO_WRAPPER_XDOMAIN_INVOKE: res = wrps->xdomain_invoke; break;
2435 case MONO_WRAPPER_XDOMAIN_DISPATCH: res = wrps->xdomain_dispatch; break;
2439 /* it is important to do the unlock after the load from wrps, since in
2440 * mono_remoting_mb_create_and_cache () we drop the marshal lock to be able
2441 * to take the loader lock and some other thread may set the fields.
2443 mono_marshal_unlock ();
2447 /* Create the method from the builder and place it in the cache */
2448 static inline MonoMethod*
2449 mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb,
2450 MonoMethodSignature *sig, int max_stack)
2452 MonoMethod **res = NULL;
2453 MonoRemotingMethods *wrps;
2454 GHashTable *cache = get_cache_full (&key->klass->image->remoting_invoke_cache, mono_aligned_addr_hash, NULL, NULL, g_free);
2456 mono_marshal_lock ();
2457 wrps = g_hash_table_lookup (cache, key);
2459 wrps = g_new0 (MonoRemotingMethods, 1);
2460 g_hash_table_insert (cache, key, wrps);
2463 switch (mb->method->wrapper_type) {
2464 case MONO_WRAPPER_REMOTING_INVOKE: res = &wrps->invoke; break;
2465 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = &wrps->invoke_with_check; break;
2466 case MONO_WRAPPER_XDOMAIN_INVOKE: res = &wrps->xdomain_invoke; break;
2467 case MONO_WRAPPER_XDOMAIN_DISPATCH: res = &wrps->xdomain_dispatch; break;
2468 default: g_assert_not_reached (); break;
2470 mono_marshal_unlock ();
2474 newm = mono_mb_create_method (mb, sig, max_stack);
2476 mono_marshal_lock ();
2479 mono_marshal_set_wrapper_info (*res, key);
2480 mono_marshal_unlock ();
2482 mono_marshal_unlock ();
2483 mono_free_method (newm);
2491 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
2494 int wrapper_type = wrapper->wrapper_type;
2497 if (wrapper_type == MONO_WRAPPER_NONE || wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2500 switch (wrapper_type) {
2501 case MONO_WRAPPER_REMOTING_INVOKE:
2502 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2503 case MONO_WRAPPER_XDOMAIN_INVOKE:
2504 case MONO_WRAPPER_SYNCHRONIZED:
2505 res = mono_marshal_get_wrapper_info (wrapper);
2509 case MONO_WRAPPER_MANAGED_TO_NATIVE:
2510 info = mono_marshal_get_wrapper_info (wrapper);
2511 if (info && info->subtype == WRAPPER_SUBTYPE_NONE)
2512 return info->d.managed_to_native.method;
2515 case MONO_WRAPPER_RUNTIME_INVOKE:
2516 info = mono_marshal_get_wrapper_info (wrapper);
2517 if (info && (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL))
2518 return info->d.runtime_invoke.method;
2527 * mono_marshal_get_wrapper_info:
2529 * Retrieve the pointer stored by mono_marshal_set_wrapper_info. The type of data
2530 * returned depends on the wrapper type. It is usually a method, a class, or a
2531 * WrapperInfo structure.
2534 mono_marshal_get_wrapper_info (MonoMethod *wrapper)
2536 g_assert (wrapper->wrapper_type);
2538 return mono_method_get_wrapper_data (wrapper, 1);
2542 * mono_marshal_set_wrapper_info:
2544 * Store an arbitrary pointer inside the wrapper which is retrievable by
2545 * mono_marshal_get_wrapper_info. The format of the data depends on the type of the
2546 * wrapper (method->wrapper_type).
2549 mono_marshal_set_wrapper_info (MonoMethod *method, gpointer data)
2553 if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2556 datav = ((MonoMethodWrapper *)method)->method_data;
2561 mono_wrapper_info_create (MonoMethod *wrapper, WrapperSubtype subtype)
2565 info = mono_image_alloc0 (wrapper->klass->image, sizeof (WrapperInfo));
2566 info->subtype = subtype;
2571 * get_wrapper_target_class:
2573 * Return the class where a wrapper method should be placed.
2576 get_wrapper_target_class (MonoImage *image)
2582 * - can't put all wrappers into an mscorlib class, because they reference
2583 * metadata (signature) so they should be put into the same image as the
2584 * method they wrap, so they are unloaded together.
2585 * - putting them into a class with a type initalizer could cause the
2586 * initializer to be executed which can be a problem if the wrappers are
2588 * - putting them into an inflated class can cause problems if the the
2589 * class is deleted because it references an image which is unloaded.
2590 * To avoid these problems, we put the wrappers into the <Module> class of
2594 klass = ((MonoDynamicImage*)image)->wrappers_type;
2596 klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1));
2603 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
2605 MonoMethodSignature *sig;
2606 MonoMethodBuilder *mb;
2612 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
2613 !strcmp (method->name, "BeginInvoke"));
2615 sig = mono_signature_no_pinvoke (method);
2617 cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
2618 (GHashFunc)mono_signature_hash,
2619 (GCompareFunc)mono_metadata_signature_equal);
2620 if ((res = mono_marshal_find_in_cache (cache, sig)))
2623 g_assert (sig->hasthis);
2625 name = mono_signature_to_name (sig, "begin_invoke");
2626 mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
2629 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
2631 mono_mb_emit_ldarg (mb, 0);
2632 mono_mb_emit_ldloc (mb, params_var);
2633 mono_mb_emit_icall (mb, mono_delegate_begin_invoke);
2634 mono_mb_emit_byte (mb, CEE_RET);
2636 res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
2642 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
2644 MonoDomain *domain = mono_domain_get ();
2645 MonoAsyncResult *ares;
2646 MonoMethod *method = NULL;
2647 MonoMethodSignature *sig;
2648 MonoMethodMessage *msg;
2649 MonoObject *res, *exc;
2650 MonoArray *out_args;
2653 g_assert (delegate);
2655 if (!delegate->method_info) {
2656 g_assert (delegate->method);
2657 MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, delegate->method, NULL));
2660 if (!delegate->method_info || !delegate->method_info->method)
2661 g_assert_not_reached ();
2663 klass = delegate->object.vtable->klass;
2665 method = mono_class_get_method_from_name (klass, "EndInvoke", -1);
2666 g_assert (method != NULL);
2668 sig = mono_signature_no_pinvoke (method);
2670 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
2672 ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
2674 mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
2678 if (ares->async_delegate != (MonoObject*)delegate) {
2679 mono_raise_exception (mono_get_exception_invalid_operation (
2680 "The IAsyncResult object provided does not match this delegate."));
2684 if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
2685 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
2686 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2687 mono_message_init (domain, msg, delegate->method_info, NULL);
2688 msg->call_type = CallType_EndInvoke;
2689 MONO_OBJECT_SETREF (msg, async_result, ares);
2690 res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
2692 res = mono_thread_pool_finish (ares, &out_args, &exc);
2696 if (((MonoException*)exc)->stack_trace) {
2697 char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
2699 tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
2701 MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
2704 mono_raise_exception ((MonoException*)exc);
2707 mono_method_return_message_restore (method, params, out_args);
2712 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
2714 MonoType *t = mono_type_get_underlying_type (return_type);
2716 if (return_type->byref)
2717 return_type = &mono_defaults.int_class->byval_arg;
2720 case MONO_TYPE_VOID:
2721 g_assert_not_reached ();
2724 case MONO_TYPE_STRING:
2725 case MONO_TYPE_CLASS:
2726 case MONO_TYPE_OBJECT:
2727 case MONO_TYPE_ARRAY:
2728 case MONO_TYPE_SZARRAY:
2732 case MONO_TYPE_BOOLEAN:
2735 case MONO_TYPE_CHAR:
2745 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (return_type));
2746 mono_mb_emit_byte (mb, mono_type_to_ldind (return_type));
2748 case MONO_TYPE_GENERICINST:
2749 if (!mono_type_generic_inst_is_valuetype (t))
2752 case MONO_TYPE_VALUETYPE: {
2753 MonoClass *klass = mono_class_from_mono_type (return_type);
2754 mono_mb_emit_op (mb, CEE_UNBOX, klass);
2755 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
2759 g_warning ("type 0x%x not handled", return_type->type);
2760 g_assert_not_reached ();
2763 mono_mb_emit_byte (mb, CEE_RET);
2767 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
2769 MonoMethodSignature *sig;
2770 MonoMethodBuilder *mb;
2776 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
2777 !strcmp (method->name, "EndInvoke"));
2779 sig = mono_signature_no_pinvoke (method);
2781 cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
2782 (GHashFunc)mono_signature_hash,
2783 (GCompareFunc)mono_metadata_signature_equal);
2784 if ((res = mono_marshal_find_in_cache (cache, sig)))
2787 g_assert (sig->hasthis);
2789 name = mono_signature_to_name (sig, "end_invoke");
2790 mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_END_INVOKE);
2793 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
2795 mono_mb_emit_ldarg (mb, 0);
2796 mono_mb_emit_ldloc (mb, params_var);
2797 mono_mb_emit_icall (mb, mono_delegate_end_invoke);
2799 if (sig->ret->type == MONO_TYPE_VOID) {
2800 mono_mb_emit_byte (mb, CEE_POP);
2801 mono_mb_emit_byte (mb, CEE_RET);
2803 mono_mb_emit_restore_result (mb, sig->ret);
2805 res = mono_mb_create_and_cache (cache, sig,
2806 mb, sig, sig->param_count + 16);
2813 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
2815 MonoMethodMessage *msg;
2816 MonoTransparentProxy *this;
2817 MonoObject *res, *exc;
2818 MonoArray *out_args;
2820 this = *((MonoTransparentProxy **)params [0]);
2823 g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
2825 /* skip the this pointer */
2828 if (this->remote_class->proxy_class->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
2831 MonoMethodSignature *sig = mono_method_signature (method);
2832 int count = sig->param_count;
2833 gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
2835 for (i=0; i<count; i++) {
2836 MonoClass *class = mono_class_from_mono_type (sig->params [i]);
2837 if (class->valuetype) {
2838 if (sig->params [i]->byref) {
2839 mparams[i] = *((gpointer *)params [i]);
2841 /* runtime_invoke expects a boxed instance */
2842 if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i])))
2843 mparams[i] = mono_nullable_box (params [i], class);
2845 mparams[i] = params [i];
2848 mparams[i] = *((gpointer**)params [i]);
2852 return mono_runtime_invoke (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this): this, mparams, NULL);
2855 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
2857 res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
2860 mono_raise_exception ((MonoException *)exc);
2862 mono_method_return_message_restore (method, params, out_args);
2868 mono_marshal_get_remoting_invoke (MonoMethod *method)
2870 MonoMethodSignature *sig;
2871 MonoMethodBuilder *mb;
2877 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
2880 /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
2881 if (method->klass->is_com_object || method->klass == mono_defaults.com_object_class) {
2882 MonoVTable *vtable = mono_class_vtable (mono_domain_get (), method->klass);
2883 g_assert (vtable); /*FIXME do proper error handling*/
2885 if (!vtable->remote) {
2887 return mono_cominterop_get_invoke (method);
2889 g_assert_not_reached ();
2894 sig = mono_signature_no_pinvoke (method);
2896 /* we cant remote methods without this pointer */
2900 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE)))
2903 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
2904 mb->method->save_lmf = 1;
2906 params_var = mono_mb_emit_save_args (mb, sig, TRUE);
2908 mono_mb_emit_ptr (mb, method);
2909 mono_mb_emit_ldloc (mb, params_var);
2910 mono_mb_emit_icall (mb, mono_remoting_wrapper);
2911 emit_thread_interrupt_checkpoint (mb);
2913 if (sig->ret->type == MONO_TYPE_VOID) {
2914 mono_mb_emit_byte (mb, CEE_POP);
2915 mono_mb_emit_byte (mb, CEE_RET);
2917 mono_mb_emit_restore_result (mb, sig->ret);
2920 res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
2926 /* mono_get_xdomain_marshal_type()
2927 * Returns the kind of marshalling that a type needs for cross domain calls.
2929 static MonoXDomainMarshalType
2930 mono_get_xdomain_marshal_type (MonoType *t)
2933 case MONO_TYPE_VOID:
2934 g_assert_not_reached ();
2938 case MONO_TYPE_BOOLEAN:
2941 case MONO_TYPE_CHAR:
2948 return MONO_MARSHAL_NONE;
2949 case MONO_TYPE_STRING:
2950 return MONO_MARSHAL_COPY;
2951 case MONO_TYPE_ARRAY:
2952 case MONO_TYPE_SZARRAY: {
2953 MonoClass *elem_class = mono_class_from_mono_type (t)->element_class;
2954 if (mono_get_xdomain_marshal_type (&(elem_class->byval_arg)) != MONO_MARSHAL_SERIALIZE)
2955 return MONO_MARSHAL_COPY;
2960 return MONO_MARSHAL_SERIALIZE;
2964 /* mono_marshal_xdomain_copy_value
2965 * Makes a copy of "val" suitable for the current domain.
2968 mono_marshal_xdomain_copy_value (MonoObject *val)
2971 if (val == NULL) return NULL;
2973 domain = mono_domain_get ();
2975 switch (mono_object_class (val)->byval_arg.type) {
2976 case MONO_TYPE_VOID:
2977 g_assert_not_reached ();
2981 case MONO_TYPE_BOOLEAN:
2984 case MONO_TYPE_CHAR:
2990 case MONO_TYPE_R8: {
2991 return mono_value_box (domain, mono_object_class (val), ((char*)val) + sizeof(MonoObject));
2993 case MONO_TYPE_STRING: {
2994 MonoString *str = (MonoString *) val;
2995 return (MonoObject *) mono_string_new_utf16 (domain, mono_string_chars (str), mono_string_length (str));
2997 case MONO_TYPE_ARRAY:
2998 case MONO_TYPE_SZARRAY: {
3000 MonoXDomainMarshalType mt = mono_get_xdomain_marshal_type (&(mono_object_class (val)->element_class->byval_arg));
3001 if (mt == MONO_MARSHAL_SERIALIZE) return NULL;
3002 acopy = mono_array_clone_in_domain (domain, (MonoArray *) val);
3003 if (mt == MONO_MARSHAL_COPY) {
3004 int i, len = mono_array_length (acopy);
3005 for (i = 0; i < len; i++) {
3006 MonoObject *item = mono_array_get (acopy, gpointer, i);
3007 mono_array_setref (acopy, i, mono_marshal_xdomain_copy_value (item));
3010 return (MonoObject *) acopy;
3014 if (mono_object_class (val) == mono_defaults.stringbuilder_class) {
3015 MonoStringBuilder *oldsb = (MonoStringBuilder *) val;
3016 MonoStringBuilder *newsb = (MonoStringBuilder *) mono_object_new (domain, mono_defaults.stringbuilder_class);
3017 MONO_OBJECT_SETREF (newsb, str, mono_string_new_utf16 (domain, mono_string_chars (oldsb->str), mono_string_length (oldsb->str)));
3018 newsb->length = oldsb->length;
3019 newsb->max_capacity = (gint32)0x7fffffff;
3020 return (MonoObject *) newsb;
3025 /* mono_marshal_xdomain_copy_out_value()
3026 * Copies the contents of the src instance into the dst instance. src and dst
3027 * must have the same type, and if they are arrays, the same size.
3030 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst)
3032 if (src == NULL || dst == NULL) return;
3034 g_assert (mono_object_class (src) == mono_object_class (dst));
3036 switch (mono_object_class (src)->byval_arg.type) {
3037 case MONO_TYPE_ARRAY:
3038 case MONO_TYPE_SZARRAY: {
3039 int mt = mono_get_xdomain_marshal_type (&(mono_object_class (src)->element_class->byval_arg));
3040 if (mt == MONO_MARSHAL_SERIALIZE) return;
3041 if (mt == MONO_MARSHAL_COPY) {
3042 int i, len = mono_array_length ((MonoArray *)dst);
3043 for (i = 0; i < len; i++) {
3044 MonoObject *item = mono_array_get ((MonoArray *)src, gpointer, i);
3045 mono_array_setref ((MonoArray *)dst, i, mono_marshal_xdomain_copy_value (item));
3048 mono_array_full_copy ((MonoArray *)src, (MonoArray *)dst);
3054 if (mono_object_class (src) == mono_defaults.stringbuilder_class) {
3055 MonoStringBuilder *src_sb = (MonoStringBuilder *) src;
3056 MonoStringBuilder *dst_sb = (MonoStringBuilder *) dst;
3058 MONO_OBJECT_SETREF (dst_sb, str, mono_string_new_utf16 (mono_object_domain (dst), mono_string_chars (src_sb->str), mono_string_length (src_sb->str)));
3059 dst_sb->cached_str = NULL;
3060 dst_sb->length = src_sb->length;
3065 mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder *mb, MonoClass *pclass)
3067 mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_value);
3068 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
3072 mono_marshal_emit_xdomain_copy_out_value (MonoMethodBuilder *mb, MonoClass *pclass)
3074 mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_out_value);
3077 /* mono_marshal_supports_fast_xdomain()
3078 * Returns TRUE if the method can use the fast xdomain wrapper.
3081 mono_marshal_supports_fast_xdomain (MonoMethod *method)
3083 return !method->klass->contextbound &&
3084 !((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".ctor", method->name) == 0));
3088 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push)
3090 MonoDomain *current_domain = mono_domain_get ();
3091 MonoDomain *domain = mono_domain_get_by_id (id);
3093 if (!domain || !mono_domain_set (domain, FALSE))
3094 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
3097 mono_thread_push_appdomain_ref (domain);
3099 mono_thread_pop_appdomain_ref ();
3101 return current_domain->domain_id;
3105 mono_marshal_emit_switch_domain (MonoMethodBuilder *mb)
3107 mono_mb_emit_icall (mb, mono_marshal_set_domain_by_id);
3110 /* mono_marshal_emit_load_domain_method ()
3111 * Loads into the stack a pointer to the code of the provided method for
3112 * the current domain.
3115 mono_marshal_emit_load_domain_method (MonoMethodBuilder *mb, MonoMethod *method)
3117 /* We need a pointer to the method for the running domain (not the domain
3118 * that compiles the method).
3120 mono_mb_emit_ptr (mb, method);
3121 mono_mb_emit_icall (mb, mono_compile_method);
3124 /* mono_marshal_check_domain_image ()
3125 * Returns TRUE if the image is loaded in the specified
3126 * application domain.
3129 mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image)
3134 MonoDomain *domain = mono_domain_get_by_id (domain_id);
3138 mono_domain_assemblies_lock (domain);
3139 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
3141 if (ass->image == image)
3144 mono_domain_assemblies_unlock (domain);
3149 /* mono_marshal_get_xappdomain_dispatch ()
3150 * Generates a method that dispatches a method call from another domain into
3151 * the current domain.
3154 mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, int complex_count, int complex_out_count, int ret_marshal_type)
3156 MonoMethodSignature *sig, *csig;
3157 MonoMethodBuilder *mb;
3159 int i, j, param_index, copy_locals_base;
3160 MonoClass *ret_class = NULL;
3161 int loc_array=0, loc_return=0, loc_serialized_exc=0;
3162 MonoExceptionClause *main_clause;
3164 gboolean copy_return;
3166 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_DISPATCH)))
3169 sig = mono_method_signature (method);
3170 copy_return = (sig->ret->type != MONO_TYPE_VOID && ret_marshal_type != MONO_MARSHAL_SERIALIZE);
3173 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3 + sig->param_count - complex_count);
3174 csig->params [j++] = &mono_defaults.object_class->byval_arg;
3175 csig->params [j++] = &byte_array_class->this_arg;
3176 csig->params [j++] = &byte_array_class->this_arg;
3177 for (i = 0; i < sig->param_count; i++) {
3178 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE)
3179 csig->params [j++] = sig->params [i];
3182 csig->ret = sig->ret;
3184 csig->ret = &mono_defaults.void_class->byval_arg;
3186 csig->hasthis = FALSE;
3188 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_DISPATCH);
3189 mb->method->save_lmf = 1;
3193 loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
3194 if (complex_count > 0)
3195 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3196 if (sig->ret->type != MONO_TYPE_VOID) {
3197 loc_return = mono_mb_add_local (mb, sig->ret);
3198 ret_class = mono_class_from_mono_type (sig->ret);
3203 main_clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
3204 main_clause->try_offset = mono_mb_get_label (mb);
3206 /* Clean the call context */
3208 mono_mb_emit_byte (mb, CEE_LDNULL);
3209 mono_mb_emit_managed_call (mb, method_set_call_context, NULL);
3210 mono_mb_emit_byte (mb, CEE_POP);
3212 /* Deserialize call data */
3214 mono_mb_emit_ldarg (mb, 1);
3215 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3216 mono_mb_emit_byte (mb, CEE_DUP);
3217 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3219 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3220 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3222 if (complex_count > 0)
3223 mono_mb_emit_stloc (mb, loc_array);
3225 mono_mb_emit_byte (mb, CEE_POP);
3227 mono_mb_patch_short_branch (mb, pos);
3229 /* Get the target object */
3231 mono_mb_emit_ldarg (mb, 0);
3232 mono_mb_emit_managed_call (mb, method_rs_appdomain_target, NULL);
3234 /* Load the arguments */
3236 copy_locals_base = mb->locals;
3237 param_index = 3; // Index of the first non-serialized parameter of this wrapper
3239 for (i = 0; i < sig->param_count; i++) {
3240 MonoType *pt = sig->params [i];
3241 MonoClass *pclass = mono_class_from_mono_type (pt);
3242 switch (marshal_types [i]) {
3243 case MONO_MARSHAL_SERIALIZE: {
3244 /* take the value from the serialized array */
3245 mono_mb_emit_ldloc (mb, loc_array);
3246 mono_mb_emit_icon (mb, j++);
3248 if (pclass->valuetype) {
3249 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3250 mono_mb_emit_op (mb, CEE_UNBOX, pclass);
3252 mono_mb_emit_op (mb, CEE_LDELEMA, pclass);
3255 if (pclass->valuetype) {
3256 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3257 mono_mb_emit_op (mb, CEE_UNBOX, pclass);
3258 mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
3260 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3261 if (pclass != mono_defaults.object_class) {
3262 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
3268 case MONO_MARSHAL_COPY_OUT: {
3269 /* Keep a local copy of the value since we need to copy it back after the call */
3270 int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
3271 mono_mb_emit_ldarg (mb, param_index++);
3272 mono_marshal_emit_xdomain_copy_value (mb, pclass);
3273 mono_mb_emit_byte (mb, CEE_DUP);
3274 mono_mb_emit_stloc (mb, copy_local);
3277 case MONO_MARSHAL_COPY: {
3278 mono_mb_emit_ldarg (mb, param_index);
3280 mono_mb_emit_byte (mb, CEE_DUP);
3281 mono_mb_emit_byte (mb, CEE_DUP);
3282 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3283 mono_marshal_emit_xdomain_copy_value (mb, pclass);
3284 mono_mb_emit_byte (mb, CEE_STIND_REF);
3286 mono_marshal_emit_xdomain_copy_value (mb, pclass);
3291 case MONO_MARSHAL_NONE:
3292 mono_mb_emit_ldarg (mb, param_index++);
3297 /* Make the call to the real object */
3299 emit_thread_force_interrupt_checkpoint (mb);
3301 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
3303 if (sig->ret->type != MONO_TYPE_VOID)
3304 mono_mb_emit_stloc (mb, loc_return);
3306 /* copy back MONO_MARSHAL_COPY_OUT parameters */
3310 for (i = 0; i < sig->param_count; i++) {
3311 if (marshal_types [i] == MONO_MARSHAL_SERIALIZE) continue;
3312 if (marshal_types [i] == MONO_MARSHAL_COPY_OUT) {
3313 mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
3314 mono_mb_emit_ldarg (mb, param_index);
3315 mono_marshal_emit_xdomain_copy_out_value (mb, mono_class_from_mono_type (sig->params [i]));
3320 /* Serialize the return values */
3322 if (complex_out_count > 0) {
3323 /* Reset parameters in the array that don't need to be serialized back */
3325 for (i = 0; i < sig->param_count; i++) {
3326 if (marshal_types[i] != MONO_MARSHAL_SERIALIZE) continue;
3327 if (!sig->params [i]->byref) {
3328 mono_mb_emit_ldloc (mb, loc_array);
3329 mono_mb_emit_icon (mb, j);
3330 mono_mb_emit_byte (mb, CEE_LDNULL);
3331 mono_mb_emit_byte (mb, CEE_STELEM_REF);
3336 /* Add the return value to the array */
3338 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
3339 mono_mb_emit_ldloc (mb, loc_array);
3340 mono_mb_emit_icon (mb, complex_count); /* The array has an additional slot to hold the ret value */
3341 mono_mb_emit_ldloc (mb, loc_return);
3343 g_assert (ret_class); /*FIXME properly fail here*/
3344 if (ret_class->valuetype) {
3345 mono_mb_emit_op (mb, CEE_BOX, ret_class);
3347 mono_mb_emit_byte (mb, CEE_STELEM_REF);
3352 mono_mb_emit_ldarg (mb, 1);
3353 mono_mb_emit_ldloc (mb, loc_array);
3354 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
3355 mono_mb_emit_byte (mb, CEE_STIND_REF);
3356 } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
3357 mono_mb_emit_ldarg (mb, 1);
3358 mono_mb_emit_ldloc (mb, loc_return);
3359 if (ret_class->valuetype) {
3360 mono_mb_emit_op (mb, CEE_BOX, ret_class);
3362 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
3363 mono_mb_emit_byte (mb, CEE_STIND_REF);
3365 mono_mb_emit_ldarg (mb, 1);
3366 mono_mb_emit_byte (mb, CEE_LDNULL);
3367 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
3368 mono_mb_emit_byte (mb, CEE_STIND_REF);
3371 mono_mb_emit_ldarg (mb, 2);
3372 mono_mb_emit_byte (mb, CEE_LDNULL);
3373 mono_mb_emit_byte (mb, CEE_STIND_REF);
3374 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
3376 /* Main exception catch */
3377 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
3378 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
3379 main_clause->data.catch_class = mono_defaults.object_class;
3382 main_clause->handler_offset = mono_mb_get_label (mb);
3383 mono_mb_emit_managed_call (mb, method_rs_serialize_exc, NULL);
3384 mono_mb_emit_stloc (mb, loc_serialized_exc);
3385 mono_mb_emit_ldarg (mb, 2);
3386 mono_mb_emit_ldloc (mb, loc_serialized_exc);
3387 mono_mb_emit_byte (mb, CEE_STIND_REF);
3388 mono_mb_emit_branch (mb, CEE_LEAVE);
3389 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
3392 mono_mb_patch_branch (mb, pos_leave);
3395 mono_mb_emit_ldloc (mb, loc_return);
3397 mono_mb_emit_byte (mb, CEE_RET);
3399 mono_mb_set_clauses (mb, 1, main_clause);
3401 res = mono_remoting_mb_create_and_cache (method, mb, csig, csig->param_count + 16);
3407 /* mono_marshal_get_xappdomain_invoke ()
3408 * Generates a fast remoting wrapper for cross app domain calls.
3411 mono_marshal_get_xappdomain_invoke (MonoMethod *method)
3413 MonoMethodSignature *sig;
3414 MonoMethodBuilder *mb;
3416 int i, j, complex_count, complex_out_count, copy_locals_base;
3418 MonoClass *ret_class = NULL;
3419 MonoMethod *xdomain_method;
3420 int ret_marshal_type = MONO_MARSHAL_NONE;
3421 int loc_array=0, loc_serialized_data=-1, loc_real_proxy;
3422 int loc_old_domainid, loc_domainid, loc_return=0, loc_serialized_exc=0, loc_context;
3423 int pos, pos_dispatch, pos_noex;
3424 gboolean copy_return = FALSE;
3428 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
3431 /* we cant remote methods without this pointer */
3432 if (!mono_method_signature (method)->hasthis)
3435 if (!mono_marshal_supports_fast_xdomain (method))
3436 return mono_marshal_get_remoting_invoke (method);
3438 mono_remoting_marshal_init ();
3440 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE)))
3443 sig = mono_signature_no_pinvoke (method);
3445 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE);
3446 mb->method->save_lmf = 1;
3448 /* Count the number of parameters that need to be serialized */
3450 marshal_types = alloca (sizeof (int) * sig->param_count);
3451 complex_count = complex_out_count = 0;
3452 for (i = 0; i < sig->param_count; i++) {
3453 MonoType *ptype = sig->params[i];
3454 int mt = mono_get_xdomain_marshal_type (ptype);
3456 /* If the [Out] attribute is applied to a parameter that can be internally copied,
3457 * the copy will be made by reusing the original object instance
3459 if ((ptype->attrs & PARAM_ATTRIBUTE_OUT) != 0 && mt == MONO_MARSHAL_COPY && !ptype->byref)
3460 mt = MONO_MARSHAL_COPY_OUT;
3461 else if (mt == MONO_MARSHAL_SERIALIZE) {
3463 if (ptype->byref) complex_out_count++;
3465 marshal_types [i] = mt;
3468 if (sig->ret->type != MONO_TYPE_VOID) {
3469 ret_marshal_type = mono_get_xdomain_marshal_type (sig->ret);
3470 ret_class = mono_class_from_mono_type (sig->ret);
3471 copy_return = ret_marshal_type != MONO_MARSHAL_SERIALIZE;
3476 if (complex_count > 0)
3477 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3478 loc_serialized_data = mono_mb_add_local (mb, &byte_array_class->byval_arg);
3479 loc_real_proxy = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3481 loc_return = mono_mb_add_local (mb, sig->ret);
3482 loc_old_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
3483 loc_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
3484 loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
3485 loc_context = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3487 /* Save thread domain data */
3489 mono_mb_emit_icall (mb, mono_context_get);
3490 mono_mb_emit_byte (mb, CEE_DUP);
3491 mono_mb_emit_stloc (mb, loc_context);
3493 /* If the thread is not running in the default context, it needs to go
3494 * through the whole remoting sink, since the context is going to change
3496 mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL);
3497 pos = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3499 /* Another case in which the fast path can't be used: when the target domain
3500 * has a different image for the same assembly.
3503 /* Get the target domain id */
3505 mono_mb_emit_ldarg (mb, 0);
3506 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
3507 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3508 mono_mb_emit_byte (mb, CEE_DUP);
3509 mono_mb_emit_stloc (mb, loc_real_proxy);
3511 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
3512 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3513 mono_mb_emit_stloc (mb, loc_domainid);
3515 /* Check if the target domain has the same image for the required assembly */
3517 mono_mb_emit_ldloc (mb, loc_domainid);
3518 mono_mb_emit_ptr (mb, method->klass->image);
3519 mono_mb_emit_icall (mb, mono_marshal_check_domain_image);
3520 pos_dispatch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3522 /* Use the whole remoting sink to dispatch this message */
3524 mono_mb_patch_short_branch (mb, pos);
3526 mono_mb_emit_ldarg (mb, 0);
3527 for (i = 0; i < sig->param_count; i++)
3528 mono_mb_emit_ldarg (mb, i + 1);
3530 mono_mb_emit_managed_call (mb, mono_marshal_get_remoting_invoke (method), NULL);
3531 mono_mb_emit_byte (mb, CEE_RET);
3532 mono_mb_patch_short_branch (mb, pos_dispatch);
3534 /* Create the array that will hold the parameters to be serialized */
3536 if (complex_count > 0) {
3537 mono_mb_emit_icon (mb, (ret_marshal_type == MONO_MARSHAL_SERIALIZE && complex_out_count > 0) ? complex_count + 1 : complex_count); /* +1 for the return type */
3538 mono_mb_emit_op (mb, CEE_NEWARR, mono_defaults.object_class);
3541 for (i = 0; i < sig->param_count; i++) {
3543 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
3544 pclass = mono_class_from_mono_type (sig->params[i]);
3545 mono_mb_emit_byte (mb, CEE_DUP);
3546 mono_mb_emit_icon (mb, j);
3547 mono_mb_emit_ldarg (mb, i + 1); /* 0=this */
3548 if (sig->params[i]->byref) {
3549 if (pclass->valuetype)
3550 mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
3552 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3554 if (pclass->valuetype)
3555 mono_mb_emit_op (mb, CEE_BOX, pclass);
3556 mono_mb_emit_byte (mb, CEE_STELEM_REF);
3559 mono_mb_emit_stloc (mb, loc_array);
3561 /* Serialize parameters */
3563 mono_mb_emit_ldloc (mb, loc_array);
3564 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
3565 mono_mb_emit_stloc (mb, loc_serialized_data);
3567 mono_mb_emit_byte (mb, CEE_LDNULL);
3568 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
3569 mono_mb_emit_stloc (mb, loc_serialized_data);
3574 mono_mb_emit_ldloc (mb, loc_domainid);
3575 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3576 mono_marshal_emit_switch_domain (mb);
3577 mono_mb_emit_stloc (mb, loc_old_domainid);
3579 /* Load the arguments */
3581 mono_mb_emit_ldloc (mb, loc_real_proxy);
3582 mono_mb_emit_ldloc_addr (mb, loc_serialized_data);
3583 mono_mb_emit_ldloc_addr (mb, loc_serialized_exc);
3585 copy_locals_base = mb->locals;
3586 for (i = 0; i < sig->param_count; i++) {
3587 switch (marshal_types [i]) {
3588 case MONO_MARSHAL_SERIALIZE:
3590 case MONO_MARSHAL_COPY: {
3591 mono_mb_emit_ldarg (mb, i+1);
3592 if (sig->params [i]->byref) {
3593 /* make a local copy of the byref parameter. The real parameter
3594 * will be updated after the xdomain call
3596 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
3597 int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
3598 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3599 mono_mb_emit_stloc (mb, copy_local);
3600 mono_mb_emit_ldloc_addr (mb, copy_local);
3604 case MONO_MARSHAL_COPY_OUT:
3605 case MONO_MARSHAL_NONE:
3606 mono_mb_emit_ldarg (mb, i+1);
3611 /* Make the call to the invoke wrapper in the target domain */
3613 xdomain_method = mono_marshal_get_xappdomain_dispatch (method, marshal_types, complex_count, complex_out_count, ret_marshal_type);
3614 mono_marshal_emit_load_domain_method (mb, xdomain_method);
3615 mono_mb_emit_calli (mb, mono_method_signature (xdomain_method));
3618 mono_mb_emit_stloc (mb, loc_return);
3622 mono_mb_emit_ldloc (mb, loc_old_domainid);
3623 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3624 mono_marshal_emit_switch_domain (mb);
3625 mono_mb_emit_byte (mb, CEE_POP);
3627 /* Restore thread domain data */
3629 mono_mb_emit_ldloc (mb, loc_context);
3630 mono_mb_emit_icall (mb, mono_context_set);
3632 /* if (loc_serialized_exc != null) ... */
3634 mono_mb_emit_ldloc (mb, loc_serialized_exc);
3635 pos_noex = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3637 mono_mb_emit_ldloc (mb, loc_serialized_exc);
3638 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3639 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3640 mono_mb_emit_op (mb, CEE_CASTCLASS, mono_defaults.exception_class);
3641 mono_mb_emit_managed_call (mb, method_exc_fixexc, NULL);
3642 mono_mb_emit_byte (mb, CEE_THROW);
3643 mono_mb_patch_short_branch (mb, pos_noex);
3645 /* copy back non-serialized output parameters */
3648 for (i = 0; i < sig->param_count; i++) {
3649 if (!sig->params [i]->byref || marshal_types [i] != MONO_MARSHAL_COPY) continue;
3650 mono_mb_emit_ldarg (mb, i + 1);
3651 mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
3652 mono_marshal_emit_xdomain_copy_value (mb, mono_class_from_mono_type (sig->params [i]));
3653 mono_mb_emit_byte (mb, CEE_STIND_REF);
3656 /* Deserialize out parameters */
3658 if (complex_out_count > 0) {
3659 mono_mb_emit_ldloc (mb, loc_serialized_data);
3660 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3661 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3662 mono_mb_emit_stloc (mb, loc_array);
3664 /* Copy back output parameters and return type */
3667 for (i = 0; i < sig->param_count; i++) {
3668 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
3669 if (sig->params[i]->byref) {
3670 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
3671 mono_mb_emit_ldarg (mb, i + 1);
3672 mono_mb_emit_ldloc (mb, loc_array);
3673 mono_mb_emit_icon (mb, j);
3674 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3675 if (pclass->valuetype) {
3676 mono_mb_emit_op (mb, CEE_UNBOX, pclass);
3677 mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
3678 mono_mb_emit_op (mb, CEE_STOBJ, pclass);
3680 if (pclass != mono_defaults.object_class)
3681 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
3682 mono_mb_emit_byte (mb, CEE_STIND_REF);
3688 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
3689 mono_mb_emit_ldloc (mb, loc_array);
3690 mono_mb_emit_icon (mb, complex_count);
3691 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3692 if (ret_class->valuetype) {
3693 mono_mb_emit_op (mb, CEE_UNBOX, ret_class);
3694 mono_mb_emit_op (mb, CEE_LDOBJ, ret_class);
3697 } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
3698 mono_mb_emit_ldloc (mb, loc_serialized_data);
3699 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3700 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3701 if (ret_class->valuetype) {
3702 mono_mb_emit_op (mb, CEE_UNBOX, ret_class);
3703 mono_mb_emit_op (mb, CEE_LDOBJ, ret_class);
3704 } else if (ret_class != mono_defaults.object_class) {
3705 mono_mb_emit_op (mb, CEE_CASTCLASS, ret_class);
3708 mono_mb_emit_ldloc (mb, loc_serialized_data);
3709 mono_mb_emit_byte (mb, CEE_DUP);
3710 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3711 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3713 mono_mb_patch_short_branch (mb, pos);
3714 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3715 mono_mb_emit_byte (mb, CEE_POP);
3719 mono_mb_emit_ldloc (mb, loc_return);
3720 if (ret_marshal_type == MONO_MARSHAL_COPY)
3721 mono_marshal_emit_xdomain_copy_value (mb, ret_class);
3724 mono_mb_emit_byte (mb, CEE_RET);
3726 res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
3733 mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTarget target_type)
3735 if (target_type == MONO_REMOTING_TARGET_APPDOMAIN) {
3736 return mono_marshal_get_xappdomain_invoke (method);
3737 } else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) {
3739 return mono_cominterop_get_invoke (method);
3741 g_assert_not_reached ();
3744 return mono_marshal_get_remoting_invoke (method);
3750 G_GNUC_UNUSED static gpointer
3751 mono_marshal_load_remoting_wrapper (MonoRealProxy *rp, MonoMethod *method)
3753 if (rp->target_domain_id != -1)
3754 return mono_compile_method (mono_marshal_get_xappdomain_invoke (method));
3756 return mono_compile_method (mono_marshal_get_remoting_invoke (method));
3760 mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
3762 MonoMethodSignature *sig;
3763 MonoMethodBuilder *mb;
3764 MonoMethod *res, *native;
3765 int i, pos, pos_rem;
3769 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
3772 /* we cant remote methods without this pointer */
3773 g_assert (mono_method_signature (method)->hasthis);
3775 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
3778 sig = mono_signature_no_pinvoke (method);
3780 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
3782 for (i = 0; i <= sig->param_count; i++)
3783 mono_mb_emit_ldarg (mb, i);
3785 mono_mb_emit_ldarg (mb, 0);
3786 pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3788 if (mono_marshal_supports_fast_xdomain (method)) {
3789 mono_mb_emit_ldarg (mb, 0);
3790 pos_rem = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
3792 /* wrapper for cross app domain calls */
3793 native = mono_marshal_get_xappdomain_invoke (method);
3794 mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
3795 mono_mb_emit_byte (mb, CEE_RET);
3797 mono_mb_patch_branch (mb, pos_rem);
3799 /* wrapper for normal remote calls */
3800 native = mono_marshal_get_remoting_invoke (method);
3801 mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
3802 mono_mb_emit_byte (mb, CEE_RET);
3805 mono_mb_patch_branch (mb, pos);
3806 mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
3807 mono_mb_emit_byte (mb, CEE_RET);
3809 res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
3817 MonoMethodSignature *sig;
3819 } SignatureMethodPair;
3822 signature_method_pair_hash (gconstpointer data)
3824 SignatureMethodPair *pair = (SignatureMethodPair*)data;
3826 return mono_signature_hash (pair->sig) ^ mono_aligned_addr_hash (pair->method);
3830 signature_method_pair_equal (SignatureMethodPair *pair1, SignatureMethodPair *pair2)
3832 return mono_metadata_signature_equal (pair1->sig, pair2->sig) && (pair1->method == pair2->method);
3836 signature_method_pair_matches_method (gpointer key, gpointer value, gpointer user_data)
3838 SignatureMethodPair *pair = (SignatureMethodPair*)key;
3839 MonoMethod *method = (MonoMethod*)user_data;
3841 return pair->method == method;
3845 free_signature_method_pair (SignatureMethodPair *pair)
3851 * the returned method invokes all methods in a multicast delegate.
3854 mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
3856 MonoMethodSignature *sig, *static_sig, *invoke_sig;
3858 MonoMethodBuilder *mb;
3859 MonoMethod *res, *newm;
3861 SignatureMethodPair key;
3862 SignatureMethodPair *new_key;
3863 int local_prev, local_target;
3866 MonoMethod *target_method = NULL;
3867 MonoClass *target_class = NULL;
3868 gboolean callvirt = FALSE;
3869 gboolean closed_over_null = FALSE;
3870 gboolean static_method_with_first_arg_bound = FALSE;
3873 * If the delegate target is null, and the target method is not static, a virtual
3874 * call is made to that method with the first delegate argument as this. This is
3875 * a non-documented .NET feature.
3877 if (del && !del->target && del->method && mono_method_signature (del->method)->hasthis) {
3879 target_method = del->method;
3880 if (target_method->is_inflated) {
3881 MonoType *target_type;
3883 g_assert (method->signature->hasthis);
3884 target_type = mono_class_inflate_generic_type (method->signature->params [0],
3885 mono_method_get_context (method));
3886 target_class = mono_class_from_mono_type (target_type);
3888 target_class = del->method->klass;
3892 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
3893 !strcmp (method->name, "Invoke"));
3895 invoke_sig = sig = mono_signature_no_pinvoke (method);
3898 closed_over_null = sig->param_count == mono_method_signature (del->method)->param_count;
3900 if (del && del->method && mono_method_signature (del->method)->param_count == sig->param_count + 1 && (del->method->flags & METHOD_ATTRIBUTE_STATIC)) {
3901 invoke_sig = mono_method_signature (del->method);
3902 target_method = del->method;
3903 static_method_with_first_arg_bound = TRUE;
3906 if (callvirt || static_method_with_first_arg_bound) {
3907 GHashTable **cache_ptr;
3908 if (static_method_with_first_arg_bound)
3909 cache_ptr = &method->klass->image->delegate_bound_static_invoke_cache;
3911 cache_ptr = &method->klass->image->delegate_abstract_invoke_cache;
3913 /* We need to cache the signature+method pair */
3914 mono_marshal_lock ();
3916 *cache_ptr = g_hash_table_new_full (signature_method_pair_hash, (GEqualFunc)signature_method_pair_equal, (GDestroyNotify)free_signature_method_pair, NULL);
3918 key.sig = invoke_sig;
3919 key.method = target_method;
3920 res = g_hash_table_lookup (cache, &key);
3921 mono_marshal_unlock ();
3925 cache = get_cache (&method->klass->image->delegate_invoke_cache,
3926 (GHashFunc)mono_signature_hash,
3927 (GCompareFunc)mono_metadata_signature_equal);
3928 if ((res = mono_marshal_find_in_cache (cache, sig)))
3932 static_sig = signature_dup (method->klass->image, sig);
3933 static_sig->hasthis = 0;
3934 if (!static_method_with_first_arg_bound)
3935 invoke_sig = static_sig;
3937 name = mono_signature_to_name (sig, "invoke");
3938 mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_INVOKE);
3941 /* allocate local 0 (object) */
3942 local_target = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3943 local_prev = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3945 g_assert (sig->hasthis);
3949 * prev.Invoke( args .. );
3950 * return this.<target>( args .. );
3953 /* this wrapper can be used in unmanaged-managed transitions */
3954 emit_thread_interrupt_checkpoint (mb);
3956 /* get this->prev */
3957 mono_mb_emit_ldarg (mb, 0);
3958 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
3959 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3960 mono_mb_emit_stloc (mb, local_prev);
3961 mono_mb_emit_ldloc (mb, local_prev);
3963 /* if prev != null */
3964 pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3968 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3969 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
3971 mono_mb_emit_ldloc (mb, local_prev);
3972 for (i = 0; i < sig->param_count; i++)
3973 mono_mb_emit_ldarg (mb, i + 1);
3974 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
3975 if (sig->ret->type != MONO_TYPE_VOID)
3976 mono_mb_emit_byte (mb, CEE_POP);
3978 /* continued or prev == null */
3979 mono_mb_patch_branch (mb, pos0);
3981 /* get this->target */
3982 mono_mb_emit_ldarg (mb, 0);
3983 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, target));
3984 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3985 mono_mb_emit_stloc (mb, local_target);
3987 /*static methods with bound first arg can have null target and still be bound*/
3988 if (!static_method_with_first_arg_bound) {
3989 /* if target != null */
3990 mono_mb_emit_ldloc (mb, local_target);
3991 pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3993 /* then call this->method_ptr nonstatic */
3996 mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
3998 mono_mb_emit_ldloc (mb, local_target);
3999 for (i = 0; i < sig->param_count; ++i)
4000 mono_mb_emit_ldarg (mb, i + 1);
4001 mono_mb_emit_ldarg (mb, 0);
4002 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4003 mono_mb_emit_byte (mb, CEE_LDIND_I );
4004 mono_mb_emit_op (mb, CEE_CALLI, sig);
4006 mono_mb_emit_byte (mb, CEE_RET);
4009 /* else [target == null] call this->method_ptr static */
4010 mono_mb_patch_branch (mb, pos0);
4014 if (!closed_over_null) {
4015 mono_mb_emit_ldarg (mb, 1);
4016 mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
4017 for (i = 1; i < sig->param_count; ++i)
4018 mono_mb_emit_ldarg (mb, i + 1);
4019 mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
4021 mono_mb_emit_byte (mb, CEE_LDNULL);
4022 for (i = 0; i < sig->param_count; ++i)
4023 mono_mb_emit_ldarg (mb, i + 1);
4024 mono_mb_emit_op (mb, CEE_CALL, target_method);
4027 if (static_method_with_first_arg_bound) {
4028 mono_mb_emit_ldloc (mb, local_target);
4029 if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
4030 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
4032 for (i = 0; i < sig->param_count; ++i)
4033 mono_mb_emit_ldarg (mb, i + 1);
4034 mono_mb_emit_ldarg (mb, 0);
4035 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4036 mono_mb_emit_byte (mb, CEE_LDIND_I );
4037 mono_mb_emit_op (mb, CEE_CALLI, invoke_sig);
4040 mono_mb_emit_byte (mb, CEE_RET);
4042 if (static_method_with_first_arg_bound || callvirt) {
4043 // From mono_mb_create_and_cache
4044 mb->skip_visibility = 1;
4045 newm = mono_mb_create_method (mb, sig, sig->param_count + 16);
4046 /*We perform double checked locking, so must fence before publishing*/
4047 mono_memory_barrier ();
4048 mono_marshal_lock ();
4049 res = g_hash_table_lookup (cache, &key);
4052 new_key = g_new0 (SignatureMethodPair, 1);
4054 if (static_method_with_first_arg_bound)
4055 new_key->sig = signature_dup (del->method->klass->image, key.sig);
4056 g_hash_table_insert (cache, new_key, res);
4057 mono_marshal_set_wrapper_info (res, new_key);
4058 mono_marshal_unlock ();
4060 mono_marshal_unlock ();
4061 mono_free_method (newm);
4064 mb->skip_visibility = 1;
4065 res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
4073 * signature_dup_add_this:
4075 * Make a copy of @sig, adding an explicit this argument.
4077 static MonoMethodSignature*
4078 signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass)
4080 MonoMethodSignature *res;
4083 res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1);
4084 memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
4085 res->param_count = sig->param_count + 1;
4086 res->hasthis = FALSE;
4087 for (i = sig->param_count - 1; i >= 0; i --)
4088 res->params [i + 1] = sig->params [i];
4089 res->params [0] = klass->valuetype ? &klass->this_arg : &klass->byval_arg;
4095 MonoMethodSignature *ctor_sig;
4096 MonoMethodSignature *sig;
4099 /* protected by the marshal lock, contains CtorSigPair pointers */
4100 static GSList *strsig_list = NULL;
4102 static MonoMethodSignature *
4103 lookup_string_ctor_signature (MonoMethodSignature *sig)
4105 MonoMethodSignature *callsig;
4109 mono_marshal_lock ();
4111 for (item = strsig_list; item; item = item->next) {
4113 /* mono_metadata_signature_equal () is safe to call with the marshal lock
4114 * because it is lock-free.
4116 if (mono_metadata_signature_equal (sig, cs->ctor_sig)) {
4121 mono_marshal_unlock ();
4125 static MonoMethodSignature *
4126 add_string_ctor_signature (MonoMethod *method)
4128 MonoMethodSignature *callsig;
4131 callsig = signature_dup (method->klass->image, mono_method_signature (method));
4132 callsig->ret = &mono_defaults.string_class->byval_arg;
4133 cs = g_new (CtorSigPair, 1);
4135 cs->ctor_sig = mono_method_signature (method);
4137 mono_marshal_lock ();
4138 strsig_list = g_slist_prepend (strsig_list, cs);
4139 mono_marshal_unlock ();
4144 * mono_marshal_get_string_ctor_signature:
4146 * Return the modified signature used by string ctors (they return the newly created
4149 MonoMethodSignature*
4150 mono_marshal_get_string_ctor_signature (MonoMethod *method)
4152 MonoMethodSignature *sig = lookup_string_ctor_signature (mono_method_signature (method));
4154 sig = add_string_ctor_signature (method);
4160 get_runtime_invoke_type (MonoType *t, gboolean ret)
4163 /* Can't share this with 'I' as that needs another indirection */
4166 if (MONO_TYPE_IS_REFERENCE (t))
4167 return &mono_defaults.object_class->byval_arg;
4170 /* The result needs to be boxed */
4176 return &mono_defaults.sbyte_class->byval_arg;
4178 return &mono_defaults.int16_class->byval_arg;
4180 return &mono_defaults.int32_class->byval_arg;
4182 return &mono_defaults.int64_class->byval_arg;
4183 case MONO_TYPE_BOOLEAN:
4184 return &mono_defaults.sbyte_class->byval_arg;
4185 case MONO_TYPE_CHAR:
4186 return &mono_defaults.int16_class->byval_arg;
4189 return &mono_defaults.int_class->byval_arg;
4190 case MONO_TYPE_VALUETYPE:
4191 if (t->data.klass->enumtype) {
4192 t = mono_class_enum_basetype (t->data.klass);
4202 * mono_marshal_get_runtime_invoke_sig:
4204 * Return a common signature used for sharing runtime invoke wrappers.
4206 static MonoMethodSignature*
4207 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig)
4209 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
4212 res->ret = get_runtime_invoke_type (sig->ret, TRUE);
4213 for (i = 0; i < res->param_count; ++i)
4214 res->params [i] = get_runtime_invoke_type (sig->params [i], FALSE);
4220 runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
4222 /* Can't share wrappers which return a vtype since it needs to be boxed */
4223 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))
4226 return mono_metadata_signature_equal (sig1, sig2);
4232 * Emit the call to the wrapper method from a runtime invoke wrapper.
4235 emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method,
4236 MonoMethodSignature *sig, MonoMethodSignature *callsig,
4238 gboolean virtual, gboolean need_direct_wrapper)
4240 static MonoString *string_dummy = NULL;
4242 int *tmp_nullable_locals;
4243 gboolean void_ret = FALSE;
4245 /* to make it work with our special string constructors */
4246 if (!string_dummy) {
4247 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy);
4248 string_dummy = mono_string_new_wrapper ("dummy");
4252 g_assert (sig->hasthis);
4253 g_assert (method->flags & METHOD_ATTRIBUTE_VIRTUAL);
4257 if (method->string_ctor) {
4258 mono_mb_emit_ptr (mb, string_dummy);
4260 mono_mb_emit_ldarg (mb, 0);
4264 tmp_nullable_locals = g_new0 (int, sig->param_count);
4266 for (i = 0; i < sig->param_count; i++) {
4267 MonoType *t = sig->params [i];
4270 mono_mb_emit_ldarg (mb, 1);
4272 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
4273 mono_mb_emit_byte (mb, CEE_ADD);
4277 mono_mb_emit_byte (mb, CEE_LDIND_I);
4278 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
4279 * So to make this work we unbox it to a local variablee and push a reference to that.
4281 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
4282 tmp_nullable_locals [i] = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg);
4284 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t));
4285 mono_mb_emit_stloc (mb, tmp_nullable_locals [i]);
4286 mono_mb_emit_ldloc_addr (mb, tmp_nullable_locals [i]);
4291 /*FIXME 'this doesn't handle generic enums. Shouldn't we?*/
4292 type = sig->params [i]->type;
4296 case MONO_TYPE_BOOLEAN:
4300 case MONO_TYPE_CHAR:
4309 mono_mb_emit_byte (mb, CEE_LDIND_I);
4310 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
4312 case MONO_TYPE_STRING:
4313 case MONO_TYPE_CLASS:
4314 case MONO_TYPE_ARRAY:
4316 case MONO_TYPE_SZARRAY:
4317 case MONO_TYPE_OBJECT:
4318 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
4320 case MONO_TYPE_GENERICINST:
4321 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
4322 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
4327 case MONO_TYPE_VALUETYPE:
4328 if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) {
4329 type = mono_class_enum_basetype (t->data.klass)->type;
4332 mono_mb_emit_byte (mb, CEE_LDIND_I);
4333 if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4334 /* Need to convert a boxed vtype to an mp to a Nullable struct */
4335 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (sig->params [i]));
4336 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
4338 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
4342 g_assert_not_reached ();
4347 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
4348 } else if (need_direct_wrapper) {
4349 mono_mb_emit_op (mb, CEE_CALL, method);
4351 mono_mb_emit_ldarg (mb, 3);
4352 mono_mb_emit_calli (mb, callsig);
4355 if (sig->ret->byref) {
4357 g_assert_not_reached ();
4360 switch (sig->ret->type) {
4361 case MONO_TYPE_VOID:
4362 if (!method->string_ctor)
4365 case MONO_TYPE_BOOLEAN:
4366 case MONO_TYPE_CHAR:
4379 case MONO_TYPE_VALUETYPE:
4380 case MONO_TYPE_TYPEDBYREF:
4381 case MONO_TYPE_GENERICINST:
4382 /* box value types */
4383 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
4385 case MONO_TYPE_STRING:
4386 case MONO_TYPE_CLASS:
4387 case MONO_TYPE_ARRAY:
4388 case MONO_TYPE_SZARRAY:
4389 case MONO_TYPE_OBJECT:
4393 /* The result is an IntPtr */
4394 mono_mb_emit_op (mb, CEE_BOX, mono_defaults.int_class);
4397 g_assert_not_reached ();
4401 mono_mb_emit_stloc (mb, loc_res);
4403 /* Convert back nullable-byref arguments */
4404 for (i = 0; i < sig->param_count; i++) {
4405 MonoType *t = sig->params [i];
4408 * Box the result and put it back into the array, the caller will have
4409 * to obtain it from there.
4411 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
4412 mono_mb_emit_ldarg (mb, 1);
4413 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
4414 mono_mb_emit_byte (mb, CEE_ADD);
4416 mono_mb_emit_ldloc (mb, tmp_nullable_locals [i]);
4417 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
4419 mono_mb_emit_byte (mb, CEE_STIND_REF);
4423 g_free (tmp_nullable_locals);
4427 emit_runtime_invoke_body (MonoMethodBuilder *mb, MonoClass *target_klass, MonoMethod *method,
4428 MonoMethodSignature *sig, MonoMethodSignature *callsig,
4429 gboolean virtual, gboolean need_direct_wrapper)
4432 MonoExceptionClause *clause;
4433 int loc_res, loc_exc;
4435 /* The wrapper looks like this:
4441 * } catch (Exception e) {
4449 /* allocate local 0 (object) tmp */
4450 loc_res = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4451 /* allocate local 1 (object) exc */
4452 loc_exc = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4454 /* *exc is assumed to be initialized to NULL by the caller */
4456 mono_mb_emit_byte (mb, CEE_LDARG_2);
4457 labels [0] = mono_mb_emit_branch (mb, CEE_BRFALSE);
4462 labels [1] = mono_mb_get_label (mb);
4463 emit_thread_force_interrupt_checkpoint (mb);
4464 emit_invoke_call (mb, method, sig, callsig, loc_res, virtual, need_direct_wrapper);
4466 labels [2] = mono_mb_emit_branch (mb, CEE_LEAVE);
4468 /* Add a try clause around the call */
4469 clause = mono_image_alloc0 (target_klass->image, sizeof (MonoExceptionClause));
4470 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
4471 clause->data.catch_class = mono_defaults.exception_class;
4472 clause->try_offset = labels [1];
4473 clause->try_len = mono_mb_get_label (mb) - labels [1];
4475 clause->handler_offset = mono_mb_get_label (mb);
4478 mono_mb_emit_stloc (mb, loc_exc);
4479 mono_mb_emit_byte (mb, CEE_LDARG_2);
4480 mono_mb_emit_ldloc (mb, loc_exc);
4481 mono_mb_emit_byte (mb, CEE_STIND_REF);
4483 mono_mb_emit_branch (mb, CEE_LEAVE);
4485 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
4487 mono_mb_set_clauses (mb, 1, clause);
4489 mono_mb_patch_branch (mb, labels [2]);
4490 mono_mb_emit_ldloc (mb, loc_res);
4491 mono_mb_emit_byte (mb, CEE_RET);
4496 mono_mb_patch_branch (mb, labels [0]);
4497 emit_thread_force_interrupt_checkpoint (mb);
4498 emit_invoke_call (mb, method, sig, callsig, loc_res, virtual, need_direct_wrapper);
4500 mono_mb_emit_ldloc (mb, 0);
4501 mono_mb_emit_byte (mb, CEE_RET);
4505 * generates IL code for the runtime invoke function
4506 * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
4508 * we also catch exceptions if exc != null
4509 * If VIRTUAL is TRUE, then METHOD is invoked virtually on THIS. This is useful since
4510 * it means that the compiled code for METHOD does not have to be looked up
4511 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
4512 * its METHOD argument.
4515 mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual)
4517 MonoMethodSignature *sig, *csig, *callsig;
4518 MonoMethodBuilder *mb;
4519 GHashTable *cache = NULL;
4520 MonoClass *target_klass;
4521 MonoMethod *res = NULL;
4522 static MonoMethodSignature *cctor_signature = NULL;
4523 static MonoMethodSignature *finalize_signature = NULL;
4525 const char *param_names [16];
4526 gboolean need_direct_wrapper = FALSE;
4531 if (!cctor_signature) {
4532 cctor_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4533 cctor_signature->ret = &mono_defaults.void_class->byval_arg;
4535 if (!finalize_signature) {
4536 finalize_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4537 finalize_signature->ret = &mono_defaults.void_class->byval_arg;
4538 finalize_signature->hasthis = 1;
4542 need_direct_wrapper = TRUE;
4545 * Use a separate cache indexed by methods to speed things up and to avoid the
4546 * boundless mempool growth caused by the signature_dup stuff below.
4549 cache = get_cache (&method->klass->image->runtime_invoke_vcall_cache, mono_aligned_addr_hash, NULL);
4551 cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
4552 res = mono_marshal_find_in_cache (cache, method);
4556 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
4557 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
4559 * Array Get/Set/Address methods. The JIT implements them using inline code
4560 * so we need to create an invoke wrapper which calls the method directly.
4562 need_direct_wrapper = TRUE;
4565 if (method->string_ctor) {
4566 callsig = lookup_string_ctor_signature (mono_method_signature (method));
4568 callsig = add_string_ctor_signature (method);
4569 /* Can't share this as we push a string as this */
4570 need_direct_wrapper = TRUE;
4572 if (method->klass->valuetype && mono_method_signature (method)->hasthis) {
4574 * Valuetype methods receive a managed pointer as the this argument.
4575 * Create a new signature to reflect this.
4577 callsig = signature_dup_add_this (mono_method_signature (method), method->klass);
4578 /* Can't share this as it would be shared with static methods taking an IntPtr argument */
4579 need_direct_wrapper = TRUE;
4581 if (method->dynamic)
4582 callsig = signature_dup (method->klass->image, mono_method_signature (method));
4584 callsig = mono_method_signature (method);
4588 target_klass = get_wrapper_target_class (method->klass->image);
4590 /* Try to share wrappers for non-corlib methods with simple signatures */
4591 if (mono_metadata_signature_equal (callsig, cctor_signature)) {
4592 callsig = cctor_signature;
4593 target_klass = mono_defaults.object_class;
4594 } else if (mono_metadata_signature_equal (callsig, finalize_signature)) {
4595 callsig = finalize_signature;
4596 target_klass = mono_defaults.object_class;
4599 if (need_direct_wrapper) {
4600 /* Already searched at the start */
4602 MonoMethodSignature *tmp_sig;
4604 callsig = mono_marshal_get_runtime_invoke_sig (callsig);
4606 cache = get_cache (&target_klass->image->runtime_invoke_cache,
4607 (GHashFunc)mono_signature_hash,
4608 (GCompareFunc)runtime_invoke_signature_equal);
4610 /* from mono_marshal_find_in_cache */
4611 mono_marshal_lock ();
4612 res = g_hash_table_lookup (cache, callsig);
4613 mono_marshal_unlock ();
4620 /* Make a copy of the signature from the image mempool */
4622 callsig = mono_metadata_signature_dup_full (target_klass->image, callsig);
4626 sig = mono_method_signature (method);
4628 csig = mono_metadata_signature_alloc (target_klass->image, 4);
4630 csig->ret = &mono_defaults.object_class->byval_arg;
4631 if (method->klass->valuetype && mono_method_signature (method)->hasthis)
4632 csig->params [0] = callsig->params [0];
4634 csig->params [0] = &mono_defaults.object_class->byval_arg;
4635 csig->params [1] = &mono_defaults.int_class->byval_arg;
4636 csig->params [2] = &mono_defaults.int_class->byval_arg;
4637 csig->params [3] = &mono_defaults.int_class->byval_arg;
4640 /* This is called from runtime code so it has to be cdecl */
4641 csig->call_convention = MONO_CALL_C;
4644 name = mono_signature_to_name (callsig, virtual ? "runtime_invoke_virtual" : "runtime_invoke");
4645 mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE);
4648 param_names [0] = "this";
4649 param_names [1] = "params";
4650 param_names [2] = "exc";
4651 param_names [3] = "method";
4652 mono_mb_set_param_names (mb, param_names);
4654 emit_runtime_invoke_body (mb, target_klass, method, sig, callsig, virtual, need_direct_wrapper);
4656 if (need_direct_wrapper) {
4657 mb->skip_visibility = 1;
4658 res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16);
4659 info = mono_wrapper_info_create (res, virtual ? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL : WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT);
4660 info->d.runtime_invoke.method = method;
4661 mono_marshal_set_wrapper_info (res, info);
4663 /* taken from mono_mb_create_and_cache */
4664 mono_marshal_lock ();
4665 res = g_hash_table_lookup (cache, callsig);
4666 mono_marshal_unlock ();
4668 /* Somebody may have created it before us */
4671 newm = mono_mb_create_method (mb, csig, sig->param_count + 16);
4673 mono_marshal_lock ();
4674 res = g_hash_table_lookup (cache, callsig);
4677 g_hash_table_insert (cache, callsig, res);
4678 /* Can't insert it into wrapper_hash since the key is a signature */
4679 g_hash_table_insert (method->klass->image->runtime_invoke_direct_cache, method, res);
4681 mono_free_method (newm);
4683 mono_marshal_unlock ();
4686 /* end mono_mb_create_and_cache */
4695 * mono_marshal_get_runtime_invoke_dynamic:
4697 * Return a method which can be used to invoke managed methods from native code
4699 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
4700 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
4701 * ARGS should point to an architecture specific structure containing
4702 * the arguments and space for the return value.
4703 * The other arguments are the same as for runtime_invoke (), except that
4704 * ARGS should contain the this argument too.
4705 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
4706 * is only one copy of it, which is useful in full-aot.
4707 * The wrapper info for the wrapper is a WrapperInfo structure.
4710 mono_marshal_get_runtime_invoke_dynamic (void)
4712 static MonoMethod *method;
4713 MonoMethodSignature *csig;
4714 MonoExceptionClause *clause;
4715 MonoMethodBuilder *mb;
4723 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
4725 csig->ret = &mono_defaults.void_class->byval_arg;
4726 csig->params [0] = &mono_defaults.int_class->byval_arg;
4727 csig->params [1] = &mono_defaults.int_class->byval_arg;
4728 csig->params [2] = &mono_defaults.int_class->byval_arg;
4729 csig->params [3] = &mono_defaults.int_class->byval_arg;
4731 name = g_strdup ("runtime_invoke_dynamic");
4732 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_RUNTIME_INVOKE);
4735 /* allocate local 0 (object) tmp */
4736 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4737 /* allocate local 1 (object) exc */
4738 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4740 /* cond set *exc to null */
4741 mono_mb_emit_byte (mb, CEE_LDARG_1);
4742 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
4743 mono_mb_emit_byte (mb, 3);
4744 mono_mb_emit_byte (mb, CEE_LDARG_1);
4745 mono_mb_emit_byte (mb, CEE_LDNULL);
4746 mono_mb_emit_byte (mb, CEE_STIND_REF);
4748 emit_thread_force_interrupt_checkpoint (mb);
4750 mono_mb_emit_byte (mb, CEE_LDARG_0);
4751 mono_mb_emit_byte (mb, CEE_LDARG_2);
4752 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4753 mono_mb_emit_byte (mb, CEE_MONO_DYN_CALL);
4755 pos = mono_mb_emit_branch (mb, CEE_LEAVE);
4757 clause = mono_image_alloc0 (mono_defaults.corlib, sizeof (MonoExceptionClause));
4758 clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
4759 clause->try_len = mono_mb_get_label (mb);
4762 clause->data.filter_offset = mono_mb_get_label (mb);
4764 mono_mb_emit_byte (mb, CEE_POP);
4765 mono_mb_emit_byte (mb, CEE_LDARG_1);
4766 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4767 mono_mb_emit_byte (mb, CEE_PREFIX1);
4768 mono_mb_emit_byte (mb, CEE_CGT_UN);
4769 mono_mb_emit_byte (mb, CEE_PREFIX1);
4770 mono_mb_emit_byte (mb, CEE_ENDFILTER);
4772 clause->handler_offset = mono_mb_get_label (mb);
4775 /* store exception */
4776 mono_mb_emit_stloc (mb, 1);
4778 mono_mb_emit_byte (mb, CEE_LDARG_1);
4779 mono_mb_emit_ldloc (mb, 1);
4780 mono_mb_emit_byte (mb, CEE_STIND_REF);
4782 mono_mb_emit_byte (mb, CEE_LDNULL);
4783 mono_mb_emit_stloc (mb, 0);
4785 /* Check for the abort exception */
4786 mono_mb_emit_ldloc (mb, 1);
4787 mono_mb_emit_op (mb, CEE_ISINST, mono_defaults.threadabortexception_class);
4788 posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
4790 /* Delay the abort exception */
4791 mono_mb_emit_icall (mb, ves_icall_System_Threading_Thread_ResetAbort);
4793 mono_mb_patch_short_branch (mb, posna);
4794 mono_mb_emit_branch (mb, CEE_LEAVE);
4796 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
4798 mono_mb_set_clauses (mb, 1, clause);
4801 mono_mb_patch_branch (mb, pos);
4802 //mono_mb_emit_ldloc (mb, 0);
4803 mono_mb_emit_byte (mb, CEE_RET);
4805 mono_loader_lock ();
4806 /* double-checked locking */
4808 method = mono_mb_create_method (mb, csig, 16);
4809 info = mono_wrapper_info_create (method, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC);
4810 mono_marshal_set_wrapper_info (method, info);
4812 mono_loader_unlock ();
4820 mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
4822 char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
4823 klass->name_space, klass->name);
4825 mono_mb_emit_exception_marshal_directive (mb, msg);
4829 * mono_marshal_get_ldfld_remote_wrapper:
4830 * @klass: The return type
4832 * This method generates a wrapper for calling mono_load_remote_field_new.
4833 * The return type is ignored for now, as mono_load_remote_field_new () always
4834 * returns an object. In the future, to optimize some codepaths, we might
4835 * call a different function that takes a pointer to a valuetype, instead.
4838 mono_marshal_get_ldfld_remote_wrapper (MonoClass *klass)
4840 MonoMethodSignature *sig, *csig;
4841 MonoMethodBuilder *mb;
4843 static MonoMethod* cached = NULL;
4845 mono_marshal_lock ();
4847 mono_marshal_unlock ();
4850 mono_marshal_unlock ();
4852 mb = mono_mb_new_no_dup_name (mono_defaults.object_class, "__mono_load_remote_field_new_wrapper", MONO_WRAPPER_LDFLD_REMOTE);
4854 mb->method->save_lmf = 1;
4856 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4857 sig->params [0] = &mono_defaults.object_class->byval_arg;
4858 sig->params [1] = &mono_defaults.int_class->byval_arg;
4859 sig->params [2] = &mono_defaults.int_class->byval_arg;
4860 sig->ret = &mono_defaults.object_class->byval_arg;
4862 mono_mb_emit_ldarg (mb, 0);
4863 mono_mb_emit_ldarg (mb, 1);
4864 mono_mb_emit_ldarg (mb, 2);
4866 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4867 csig->params [0] = &mono_defaults.object_class->byval_arg;
4868 csig->params [1] = &mono_defaults.int_class->byval_arg;
4869 csig->params [2] = &mono_defaults.int_class->byval_arg;
4870 csig->ret = &mono_defaults.object_class->byval_arg;
4873 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
4874 emit_thread_interrupt_checkpoint (mb);
4876 mono_mb_emit_byte (mb, CEE_RET);
4878 mono_marshal_lock ();
4880 mono_marshal_unlock ();
4883 newm = mono_mb_create_method (mb, sig, 4);
4884 mono_marshal_lock ();
4889 mono_marshal_unlock ();
4891 mono_marshal_unlock ();
4892 mono_free_method (newm);
4901 * mono_marshal_get_ldfld_wrapper:
4902 * @type: the type of the field
4904 * This method generates a function which can be use to load a field with type
4905 * @type from an object. The generated function has the following signature:
4906 * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
4909 mono_marshal_get_ldfld_wrapper (MonoType *type)
4911 MonoMethodSignature *sig;
4912 MonoMethodBuilder *mb;
4917 int t, pos0, pos1 = 0;
4919 type = mono_type_get_underlying_type (type);
4924 if (type->type == MONO_TYPE_SZARRAY) {
4925 klass = mono_defaults.array_class;
4926 } else if (type->type == MONO_TYPE_VALUETYPE) {
4927 klass = type->data.klass;
4928 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
4929 klass = mono_defaults.object_class;
4930 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
4931 klass = mono_defaults.int_class;
4932 } else if (t == MONO_TYPE_GENERICINST) {
4933 if (mono_type_generic_inst_is_valuetype (type))
4934 klass = mono_class_from_mono_type (type);
4936 klass = mono_defaults.object_class;
4938 klass = mono_class_from_mono_type (type);
4941 klass = mono_defaults.int_class;
4944 cache = get_cache (&klass->image->ldfld_wrapper_cache, mono_aligned_addr_hash, NULL);
4945 if ((res = mono_marshal_find_in_cache (cache, klass)))
4948 /* we add the %p pointer value of klass because class names are not unique */
4949 name = g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name);
4950 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
4953 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
4954 sig->params [0] = &mono_defaults.object_class->byval_arg;
4955 sig->params [1] = &mono_defaults.int_class->byval_arg;
4956 sig->params [2] = &mono_defaults.int_class->byval_arg;
4957 sig->params [3] = &mono_defaults.int_class->byval_arg;
4958 sig->ret = &klass->byval_arg;
4960 mono_mb_emit_ldarg (mb, 0);
4961 pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
4963 mono_mb_emit_ldarg (mb, 0);
4964 mono_mb_emit_ldarg (mb, 1);
4965 mono_mb_emit_ldarg (mb, 2);
4967 mono_mb_emit_managed_call (mb, mono_marshal_get_ldfld_remote_wrapper (klass), NULL);
4970 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4971 csig->params [0] = &mono_defaults.object_class->byval_arg;
4972 csig->params [1] = &mono_defaults.int_class->byval_arg;
4973 csig->params [2] = &mono_defaults.int_class->byval_arg;
4974 csig->ret = &klass->this_arg;
4977 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
4978 emit_thread_interrupt_checkpoint (mb);
4981 if (klass->valuetype) {
4982 mono_mb_emit_op (mb, CEE_UNBOX, klass);
4983 pos1 = mono_mb_emit_branch (mb, CEE_BR);
4985 mono_mb_emit_byte (mb, CEE_RET);
4989 mono_mb_patch_branch (mb, pos0);
4991 mono_mb_emit_ldarg (mb, 0);
4992 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4993 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4994 mono_mb_emit_ldarg (mb, 3);
4995 mono_mb_emit_byte (mb, CEE_ADD);
4997 if (klass->valuetype)
4998 mono_mb_patch_branch (mb, pos1);
5003 case MONO_TYPE_BOOLEAN:
5004 case MONO_TYPE_CHAR:
5013 case MONO_TYPE_ARRAY:
5014 case MONO_TYPE_SZARRAY:
5015 case MONO_TYPE_OBJECT:
5016 case MONO_TYPE_CLASS:
5017 case MONO_TYPE_STRING:
5021 case MONO_TYPE_FNPTR:
5022 mono_mb_emit_byte (mb, mono_type_to_ldind (type));
5024 case MONO_TYPE_VALUETYPE:
5025 g_assert (!klass->enumtype);
5026 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
5028 case MONO_TYPE_GENERICINST:
5029 if (mono_type_generic_inst_is_valuetype (type)) {
5030 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
5032 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5036 g_warning ("type %x not implemented", type->type);
5037 g_assert_not_reached ();
5040 mono_mb_emit_byte (mb, CEE_RET);
5042 res = mono_mb_create_and_cache (cache, klass,
5043 mb, sig, sig->param_count + 16);
5050 * mono_marshal_get_ldflda_wrapper:
5051 * @type: the type of the field
5053 * This method generates a function which can be used to load a field address
5054 * from an object. The generated function has the following signature:
5055 * gpointer ldflda_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset);
5058 mono_marshal_get_ldflda_wrapper (MonoType *type)
5060 MonoMethodSignature *sig;
5061 MonoMethodBuilder *mb;
5066 int t, pos0, pos1, pos2, pos3;
5068 type = mono_type_get_underlying_type (type);
5072 if (type->type == MONO_TYPE_SZARRAY) {
5073 klass = mono_defaults.array_class;
5074 } else if (type->type == MONO_TYPE_VALUETYPE) {
5075 klass = type->data.klass;
5076 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
5077 t == MONO_TYPE_CLASS) {
5078 klass = mono_defaults.object_class;
5079 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
5080 klass = mono_defaults.int_class;
5081 } else if (t == MONO_TYPE_GENERICINST) {
5082 if (mono_type_generic_inst_is_valuetype (type))
5083 klass = mono_class_from_mono_type (type);
5085 klass = mono_defaults.object_class;
5087 klass = mono_class_from_mono_type (type);
5090 klass = mono_defaults.int_class;
5093 cache = get_cache (&klass->image->ldflda_wrapper_cache, mono_aligned_addr_hash, NULL);
5094 if ((res = mono_marshal_find_in_cache (cache, klass)))
5097 /* we add the %p pointer value of klass because class names are not unique */
5098 name = g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass, klass->name_space, klass->name);
5099 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLDA);
5102 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5103 sig->params [0] = &mono_defaults.object_class->byval_arg;
5104 sig->params [1] = &mono_defaults.int_class->byval_arg;
5105 sig->params [2] = &mono_defaults.int_class->byval_arg;
5106 sig->params [3] = &mono_defaults.int_class->byval_arg;
5107 sig->ret = &mono_defaults.int_class->byval_arg;
5109 /* if typeof (this) != transparent_proxy goto pos0 */
5110 mono_mb_emit_ldarg (mb, 0);
5111 pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
5113 /* if same_appdomain goto pos1 */
5114 mono_mb_emit_ldarg (mb, 0);
5115 pos1 = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
5117 mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain.");
5119 /* same app domain */
5120 mono_mb_patch_branch (mb, pos1);
5122 /* if typeof (this) != contextbound goto pos2 */
5123 mono_mb_emit_ldarg (mb, 0);
5124 pos2 = mono_mb_emit_contextbound_check (mb, CEE_BEQ);
5126 /* if this->rp->context == mono_context_get goto pos3 */
5127 mono_mb_emit_ldarg (mb, 0);
5128 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
5129 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5130 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, context));
5131 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5132 mono_mb_emit_icall (mb, mono_context_get);
5133 pos3 = mono_mb_emit_branch (mb, CEE_BEQ);
5135 mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another context.");
5137 mono_mb_patch_branch (mb, pos2);
5138 mono_mb_patch_branch (mb, pos3);
5140 /* return the address of the field from this->rp->unwrapped_server */
5141 mono_mb_emit_ldarg (mb, 0);
5142 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
5143 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5144 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, unwrapped_server));
5145 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5146 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5147 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5148 mono_mb_emit_ldarg (mb, 3);
5149 mono_mb_emit_byte (mb, CEE_ADD);
5150 mono_mb_emit_byte (mb, CEE_RET);
5152 /* not a proxy: return the address of the field directly */
5153 mono_mb_patch_branch (mb, pos0);
5155 mono_mb_emit_ldarg (mb, 0);
5156 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5157 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5158 mono_mb_emit_ldarg (mb, 3);
5159 mono_mb_emit_byte (mb, CEE_ADD);
5161 mono_mb_emit_byte (mb, CEE_RET);
5163 res = mono_mb_create_and_cache (cache, klass,
5164 mb, sig, sig->param_count + 16);
5171 * mono_marshal_get_stfld_remote_wrapper:
5172 * klass: The type of the field
5174 * This function generates a wrapper for calling mono_store_remote_field_new
5175 * with the appropriate signature.
5176 * Similarly to mono_marshal_get_ldfld_remote_wrapper () this doesn't depend on the
5177 * klass argument anymore.
5180 mono_marshal_get_stfld_remote_wrapper (MonoClass *klass)
5182 MonoMethodSignature *sig, *csig;
5183 MonoMethodBuilder *mb;
5185 static MonoMethod *cached = NULL;
5187 mono_marshal_lock ();
5189 mono_marshal_unlock ();
5192 mono_marshal_unlock ();
5194 mb = mono_mb_new_no_dup_name (mono_defaults.object_class, "__mono_store_remote_field_new_wrapper", MONO_WRAPPER_STFLD_REMOTE);
5196 mb->method->save_lmf = 1;
5198 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5199 sig->params [0] = &mono_defaults.object_class->byval_arg;
5200 sig->params [1] = &mono_defaults.int_class->byval_arg;
5201 sig->params [2] = &mono_defaults.int_class->byval_arg;
5202 sig->params [3] = &mono_defaults.object_class->byval_arg;
5203 sig->ret = &mono_defaults.void_class->byval_arg;
5205 mono_mb_emit_ldarg (mb, 0);
5206 mono_mb_emit_ldarg (mb, 1);
5207 mono_mb_emit_ldarg (mb, 2);
5208 mono_mb_emit_ldarg (mb, 3);
5210 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5211 csig->params [0] = &mono_defaults.object_class->byval_arg;
5212 csig->params [1] = &mono_defaults.int_class->byval_arg;
5213 csig->params [2] = &mono_defaults.int_class->byval_arg;
5214 csig->params [3] = &mono_defaults.object_class->byval_arg;
5215 csig->ret = &mono_defaults.void_class->byval_arg;
5218 mono_mb_emit_native_call (mb, csig, mono_store_remote_field_new);
5219 emit_thread_interrupt_checkpoint (mb);
5221 mono_mb_emit_byte (mb, CEE_RET);
5223 mono_marshal_lock ();
5225 mono_marshal_unlock ();
5228 newm = mono_mb_create_method (mb, sig, 6);
5229 mono_marshal_lock ();
5234 mono_marshal_unlock ();
5236 mono_marshal_unlock ();
5237 mono_free_method (newm);
5246 * mono_marshal_get_stfld_wrapper:
5247 * @type: the type of the field
5249 * This method generates a function which can be use to store a field with type
5250 * @type. The generated function has the following signature:
5251 * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
5254 mono_marshal_get_stfld_wrapper (MonoType *type)
5256 MonoMethodSignature *sig;
5257 MonoMethodBuilder *mb;
5264 type = mono_type_get_underlying_type (type);
5268 if (type->type == MONO_TYPE_SZARRAY) {
5269 klass = mono_defaults.array_class;
5270 } else if (type->type == MONO_TYPE_VALUETYPE) {
5271 klass = type->data.klass;
5272 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
5273 klass = mono_defaults.object_class;
5274 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
5275 klass = mono_defaults.int_class;
5276 } else if (t == MONO_TYPE_GENERICINST) {
5277 if (mono_type_generic_inst_is_valuetype (type))
5278 klass = mono_class_from_mono_type (type);
5280 klass = mono_defaults.object_class;
5282 klass = mono_class_from_mono_type (type);
5285 klass = mono_defaults.int_class;
5288 cache = get_cache (&klass->image->stfld_wrapper_cache, mono_aligned_addr_hash, NULL);
5289 if ((res = mono_marshal_find_in_cache (cache, klass)))
5292 /* we add the %p pointer value of klass because class names are not unique */
5293 name = g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name);
5294 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
5297 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
5298 sig->params [0] = &mono_defaults.object_class->byval_arg;
5299 sig->params [1] = &mono_defaults.int_class->byval_arg;
5300 sig->params [2] = &mono_defaults.int_class->byval_arg;
5301 sig->params [3] = &mono_defaults.int_class->byval_arg;
5302 sig->params [4] = &klass->byval_arg;
5303 sig->ret = &mono_defaults.void_class->byval_arg;
5305 mono_mb_emit_ldarg (mb, 0);
5306 pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
5308 mono_mb_emit_ldarg (mb, 0);
5309 mono_mb_emit_ldarg (mb, 1);
5310 mono_mb_emit_ldarg (mb, 2);
5311 mono_mb_emit_ldarg (mb, 4);
5312 if (klass->valuetype)
5313 mono_mb_emit_op (mb, CEE_BOX, klass);
5315 mono_mb_emit_managed_call (mb, mono_marshal_get_stfld_remote_wrapper (klass), NULL);
5317 mono_mb_emit_byte (mb, CEE_RET);
5319 mono_mb_patch_branch (mb, pos);
5321 mono_mb_emit_ldarg (mb, 0);
5322 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5323 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5324 mono_mb_emit_ldarg (mb, 3);
5325 mono_mb_emit_byte (mb, CEE_ADD);
5326 mono_mb_emit_ldarg (mb, 4);
5331 case MONO_TYPE_BOOLEAN:
5332 case MONO_TYPE_CHAR:
5341 case MONO_TYPE_ARRAY:
5342 case MONO_TYPE_SZARRAY:
5343 case MONO_TYPE_OBJECT:
5344 case MONO_TYPE_CLASS:
5345 case MONO_TYPE_STRING:
5349 case MONO_TYPE_FNPTR:
5350 mono_mb_emit_byte (mb, mono_type_to_stind (type));
5352 case MONO_TYPE_VALUETYPE:
5353 g_assert (!klass->enumtype);
5354 mono_mb_emit_op (mb, CEE_STOBJ, klass);
5356 case MONO_TYPE_GENERICINST:
5357 mono_mb_emit_op (mb, CEE_STOBJ, klass);
5360 g_warning ("type %x not implemented", type->type);
5361 g_assert_not_reached ();
5364 mono_mb_emit_byte (mb, CEE_RET);
5366 res = mono_mb_create_and_cache (cache, klass,
5367 mb, sig, sig->param_count + 16);
5374 * generates IL code for the icall wrapper (the generated method
5375 * calls the unmanaged code in func)
5376 * The wrapper info for the wrapper is a WrapperInfo structure.
5379 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
5381 MonoMethodSignature *csig, *csig2;
5382 MonoMethodBuilder *mb;
5387 g_assert (sig->pinvoke);
5389 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
5391 mb->method->save_lmf = 1;
5393 /* Add an explicit this argument */
5395 csig2 = signature_dup_add_this (sig, mono_defaults.object_class);
5397 csig2 = signature_dup (mono_defaults.corlib, sig);
5400 mono_mb_emit_byte (mb, CEE_LDARG_0);
5402 for (i = 0; i < sig->param_count; i++)
5403 mono_mb_emit_ldarg (mb, i + sig->hasthis);
5405 mono_mb_emit_native_call (mb, csig2, (gpointer) func);
5406 if (check_exceptions)
5407 emit_thread_interrupt_checkpoint (mb);
5408 mono_mb_emit_byte (mb, CEE_RET);
5410 csig = signature_dup (mono_defaults.corlib, sig);
5412 if (csig->call_convention == MONO_CALL_VARARG)
5413 csig->call_convention = 0;
5415 res = mono_mb_create_method (mb, csig, csig->param_count + 16);
5418 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_ICALL_WRAPPER);
5419 mono_marshal_set_wrapper_info (res, info);
5425 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
5426 MonoMarshalSpec *spec,
5427 int conv_arg, MonoType **conv_arg_type,
5428 MarshalAction action)
5432 static MonoClass *ICustomMarshaler = NULL;
5433 static MonoMethod *cleanup_native, *cleanup_managed;
5434 static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
5435 MonoMethod *get_instance = NULL;
5436 MonoMethodBuilder *mb = m->mb;
5437 char *exception_msg = NULL;
5441 if (!ICustomMarshaler) {
5442 ICustomMarshaler = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
5443 if (!ICustomMarshaler) {
5444 exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
5445 goto handle_exception;
5448 cleanup_native = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpNativeData", 1);
5449 g_assert (cleanup_native);
5450 cleanup_managed = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpManagedData", 1);
5451 g_assert (cleanup_managed);
5452 marshal_managed_to_native = mono_class_get_method_from_name (ICustomMarshaler, "MarshalManagedToNative", 1);
5453 g_assert (marshal_managed_to_native);
5454 marshal_native_to_managed = mono_class_get_method_from_name (ICustomMarshaler, "MarshalNativeToManaged", 1);
5455 g_assert (marshal_native_to_managed);
5458 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
5459 g_assert (mtype != NULL);
5460 mklass = mono_class_from_mono_type (mtype);
5461 g_assert (mklass != NULL);
5463 if (!mono_class_is_assignable_from (ICustomMarshaler, mklass))
5464 exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass->name);
5466 get_instance = mono_class_get_method_from_name_flags (mklass, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC);
5468 MonoMethodSignature *get_sig = mono_method_signature (get_instance);
5469 if ((get_sig->ret->type != MONO_TYPE_CLASS) ||
5470 (mono_class_from_mono_type (get_sig->ret) != ICustomMarshaler) ||
5471 (get_sig->params [0]->type != MONO_TYPE_STRING))
5472 get_instance = NULL;
5476 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);
5479 /* Throw exception and emit compensation code if neccesary */
5480 if (exception_msg) {
5482 case MARSHAL_ACTION_CONV_IN:
5483 case MARSHAL_ACTION_CONV_RESULT:
5484 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5485 if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT))
5486 mono_mb_emit_byte (mb, CEE_POP);
5488 mono_mb_emit_exception_full (mb, "System", "ApplicationException", exception_msg);
5489 g_free (exception_msg);
5492 case MARSHAL_ACTION_PUSH:
5493 mono_mb_emit_byte (mb, CEE_LDNULL);
5501 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
5502 /* FIXME: MS.NET throws an exception if GetInstance returns null */
5505 case MARSHAL_ACTION_CONV_IN:
5507 case MONO_TYPE_CLASS:
5508 case MONO_TYPE_OBJECT:
5509 case MONO_TYPE_STRING:
5510 case MONO_TYPE_ARRAY:
5511 case MONO_TYPE_SZARRAY:
5512 case MONO_TYPE_VALUETYPE:
5516 g_warning ("custom marshalling of type %x is currently not supported", t->type);
5517 g_assert_not_reached ();
5521 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5523 mono_mb_emit_byte (mb, CEE_LDNULL);
5524 mono_mb_emit_stloc (mb, conv_arg);
5526 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
5529 /* Minic MS.NET behavior */
5530 if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
5533 /* Check for null */
5534 mono_mb_emit_ldarg (mb, argnum);
5536 mono_mb_emit_byte (mb, CEE_LDIND_I);
5537 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5539 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5541 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5543 mono_mb_emit_ldarg (mb, argnum);
5545 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5547 if (t->type == MONO_TYPE_VALUETYPE) {
5549 * Since we can't determine the type of the argument, we
5550 * will assume the unmanaged function takes a pointer.
5552 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5554 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
5557 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5558 mono_mb_emit_stloc (mb, conv_arg);
5560 mono_mb_patch_branch (mb, pos2);
5563 case MARSHAL_ACTION_CONV_OUT:
5564 /* Check for null */
5565 mono_mb_emit_ldloc (mb, conv_arg);
5566 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5569 mono_mb_emit_ldarg (mb, argnum);
5571 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5573 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5575 mono_mb_emit_ldloc (mb, conv_arg);
5576 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5577 mono_mb_emit_byte (mb, CEE_STIND_REF);
5578 } else if (t->attrs & PARAM_ATTRIBUTE_OUT) {
5579 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5581 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5583 mono_mb_emit_ldloc (mb, conv_arg);
5584 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5586 /* We have nowhere to store the result */
5587 mono_mb_emit_byte (mb, CEE_POP);
5590 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5592 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5594 mono_mb_emit_ldloc (mb, conv_arg);
5596 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
5598 mono_mb_patch_branch (mb, pos2);
5601 case MARSHAL_ACTION_PUSH:
5603 mono_mb_emit_ldloc_addr (mb, conv_arg);
5605 mono_mb_emit_ldloc (mb, conv_arg);
5608 case MARSHAL_ACTION_CONV_RESULT:
5609 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5611 mono_mb_emit_stloc (mb, 3);
5613 mono_mb_emit_ldloc (mb, 3);
5614 mono_mb_emit_stloc (mb, loc1);
5616 /* Check for null */
5617 mono_mb_emit_ldloc (mb, 3);
5618 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5620 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5622 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5623 mono_mb_emit_byte (mb, CEE_DUP);
5625 mono_mb_emit_ldloc (mb, 3);
5626 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5627 mono_mb_emit_stloc (mb, 3);
5629 mono_mb_emit_ldloc (mb, loc1);
5630 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
5632 mono_mb_patch_branch (mb, pos2);
5635 case MARSHAL_ACTION_MANAGED_CONV_IN:
5636 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5638 mono_mb_emit_byte (mb, CEE_LDNULL);
5639 mono_mb_emit_stloc (mb, conv_arg);
5641 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
5644 /* Check for null */
5645 mono_mb_emit_ldarg (mb, argnum);
5647 mono_mb_emit_byte (mb, CEE_LDIND_I);
5648 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5650 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5651 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5653 mono_mb_emit_ldarg (mb, argnum);
5655 mono_mb_emit_byte (mb, CEE_LDIND_I);
5657 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5658 mono_mb_emit_stloc (mb, conv_arg);
5660 mono_mb_patch_branch (mb, pos2);
5663 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5664 g_assert (!t->byref);
5666 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5668 mono_mb_emit_stloc (mb, 3);
5670 mono_mb_emit_ldloc (mb, 3);
5671 mono_mb_emit_stloc (mb, loc1);
5673 /* Check for null */
5674 mono_mb_emit_ldloc (mb, 3);
5675 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5677 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5678 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5679 mono_mb_emit_byte (mb, CEE_DUP);
5681 mono_mb_emit_ldloc (mb, 3);
5682 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5683 mono_mb_emit_stloc (mb, 3);
5685 mono_mb_emit_ldloc (mb, loc1);
5686 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
5688 mono_mb_patch_branch (mb, pos2);
5691 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5693 /* Check for null */
5694 mono_mb_emit_ldloc (mb, conv_arg);
5695 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5698 mono_mb_emit_ldarg (mb, argnum);
5700 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5702 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5704 mono_mb_emit_ldloc (mb, conv_arg);
5705 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5706 mono_mb_emit_byte (mb, CEE_STIND_I);
5709 /* Call CleanUpManagedData */
5710 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5712 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5714 mono_mb_emit_ldloc (mb, conv_arg);
5715 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
5717 mono_mb_patch_branch (mb, pos2);
5721 g_assert_not_reached ();
5728 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
5729 MonoMarshalSpec *spec,
5730 int conv_arg, MonoType **conv_arg_type,
5731 MarshalAction action)
5733 MonoMethodBuilder *mb = m->mb;
5736 case MARSHAL_ACTION_CONV_IN: {
5737 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
5739 g_assert (t->type == MONO_TYPE_OBJECT);
5740 g_assert (!t->byref);
5742 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5743 mono_mb_emit_ldarg (mb, argnum);
5744 mono_mb_emit_icon (mb, encoding);
5745 mono_mb_emit_icon (mb, t->attrs);
5746 mono_mb_emit_icall (mb, mono_marshal_asany);
5747 mono_mb_emit_stloc (mb, conv_arg);
5751 case MARSHAL_ACTION_PUSH:
5752 mono_mb_emit_ldloc (mb, conv_arg);
5755 case MARSHAL_ACTION_CONV_OUT: {
5756 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
5758 mono_mb_emit_ldarg (mb, argnum);
5759 mono_mb_emit_ldloc (mb, conv_arg);
5760 mono_mb_emit_icon (mb, encoding);
5761 mono_mb_emit_icon (mb, t->attrs);
5762 mono_mb_emit_icall (mb, mono_marshal_free_asany);
5767 g_assert_not_reached ();
5774 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
5775 MonoMarshalSpec *spec,
5776 int conv_arg, MonoType **conv_arg_type,
5777 MarshalAction action)
5779 MonoMethodBuilder *mb = m->mb;
5780 MonoClass *klass, *date_time_class;
5783 klass = mono_class_from_mono_type (t);
5785 date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime");
5788 case MARSHAL_ACTION_CONV_IN:
5789 if (klass == date_time_class) {
5790 /* Convert it to an OLE DATE type */
5791 static MonoMethod *to_oadate;
5794 to_oadate = mono_class_get_method_from_name (date_time_class, "ToOADate", 0);
5795 g_assert (to_oadate);
5797 conv_arg = mono_mb_add_local (mb, &mono_defaults.double_class->byval_arg);
5800 mono_mb_emit_ldarg (mb, argnum);
5801 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5804 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
5806 m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.double_class->byval_arg;
5808 mono_mb_emit_ldarg_addr (mb, argnum);
5809 mono_mb_emit_managed_call (mb, to_oadate, NULL);
5810 mono_mb_emit_stloc (mb, conv_arg);
5814 mono_mb_patch_branch (mb, pos);
5818 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5819 klass->blittable || klass->enumtype)
5822 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5824 /* store the address of the source into local variable 0 */
5826 mono_mb_emit_ldarg (mb, argnum);
5828 mono_mb_emit_ldarg_addr (mb, argnum);
5830 mono_mb_emit_stloc (mb, 0);
5832 /* allocate space for the native struct and
5833 * store the address into local variable 1 (dest) */
5834 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5835 mono_mb_emit_byte (mb, CEE_PREFIX1);
5836 mono_mb_emit_byte (mb, CEE_LOCALLOC);
5837 mono_mb_emit_stloc (mb, conv_arg);
5840 mono_mb_emit_ldloc (mb, 0);
5841 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5844 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
5846 mono_mb_emit_ldloc (mb, conv_arg);
5847 mono_mb_emit_stloc (mb, 1);
5849 /* emit valuetype conversion code */
5850 emit_struct_conv (mb, klass, FALSE);
5854 mono_mb_patch_branch (mb, pos);
5857 case MARSHAL_ACTION_PUSH:
5858 if (spec && spec->native == MONO_NATIVE_LPSTRUCT) {
5860 g_assert (!t->byref);
5862 /* Have to change the signature since the vtype is passed byref */
5863 m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
5865 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5866 klass->blittable || klass->enumtype)
5867 mono_mb_emit_ldarg_addr (mb, argnum);
5869 mono_mb_emit_ldloc (mb, conv_arg);
5873 if (klass == date_time_class) {
5875 mono_mb_emit_ldloc_addr (mb, conv_arg);
5877 mono_mb_emit_ldloc (mb, conv_arg);
5881 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5882 klass->blittable || klass->enumtype) {
5883 mono_mb_emit_ldarg (mb, argnum);
5886 mono_mb_emit_ldloc (mb, conv_arg);
5888 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5889 mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass);
5893 case MARSHAL_ACTION_CONV_OUT:
5894 if (klass == date_time_class) {
5895 /* Convert from an OLE DATE type */
5896 static MonoMethod *from_oadate;
5901 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
5903 from_oadate = mono_class_get_method_from_name (date_time_class, "FromOADate", 1);
5904 g_assert (from_oadate);
5906 mono_mb_emit_ldarg (mb, argnum);
5907 mono_mb_emit_ldloc (mb, conv_arg);
5908 mono_mb_emit_managed_call (mb, from_oadate, NULL);
5909 mono_mb_emit_op (mb, CEE_STOBJ, date_time_class);
5914 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5915 klass->blittable || klass->enumtype)
5919 /* dst = argument */
5920 mono_mb_emit_ldarg (mb, argnum);
5921 mono_mb_emit_stloc (mb, 1);
5923 mono_mb_emit_ldloc (mb, 1);
5924 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5926 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
5927 /* src = tmp_locals [i] */
5928 mono_mb_emit_ldloc (mb, conv_arg);
5929 mono_mb_emit_stloc (mb, 0);
5931 /* emit valuetype conversion code */
5932 emit_struct_conv (mb, klass, TRUE);
5936 emit_struct_free (mb, klass, conv_arg);
5939 mono_mb_patch_branch (mb, pos);
5942 case MARSHAL_ACTION_CONV_RESULT:
5943 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5945 mono_mb_emit_stloc (mb, 3);
5949 /* load pointer to returned value type */
5950 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5951 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
5952 /* store the address of the source into local variable 0 */
5953 mono_mb_emit_stloc (mb, 0);
5955 mono_mb_emit_ldloc_addr (mb, 3);
5956 mono_mb_emit_stloc (mb, 1);
5958 /* emit valuetype conversion code */
5959 emit_struct_conv (mb, klass, TRUE);
5962 case MARSHAL_ACTION_MANAGED_CONV_IN:
5963 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5964 klass->blittable || klass->enumtype) {
5969 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
5971 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5975 mono_mb_emit_ldarg (mb, argnum);
5977 mono_mb_emit_ldarg_addr (mb, argnum);
5978 mono_mb_emit_stloc (mb, 0);
5981 mono_mb_emit_ldloc (mb, 0);
5982 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5985 mono_mb_emit_ldloc_addr (mb, conv_arg);
5986 mono_mb_emit_stloc (mb, 1);
5988 /* emit valuetype conversion code */
5989 emit_struct_conv (mb, klass, TRUE);
5992 mono_mb_patch_branch (mb, pos);
5995 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5996 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5997 klass->blittable || klass->enumtype) {
6001 /* Check for null */
6002 mono_mb_emit_ldarg (mb, argnum);
6003 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6006 mono_mb_emit_ldloc_addr (mb, conv_arg);
6007 mono_mb_emit_stloc (mb, 0);
6010 mono_mb_emit_ldarg (mb, argnum);
6011 mono_mb_emit_stloc (mb, 1);
6013 /* emit valuetype conversion code */
6014 emit_struct_conv (mb, klass, FALSE);
6016 mono_mb_patch_branch (mb, pos2);
6019 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6020 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6021 klass->blittable || klass->enumtype) {
6022 mono_mb_emit_stloc (mb, 3);
6027 /* load pointer to returned value type */
6028 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6029 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
6031 /* store the address of the source into local variable 0 */
6032 mono_mb_emit_stloc (mb, 0);
6033 /* allocate space for the native struct and
6034 * store the address into dst_ptr */
6035 m->retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6036 m->retobj_class = klass;
6037 g_assert (m->retobj_var);
6038 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6039 mono_mb_emit_byte (mb, CEE_CONV_I);
6040 mono_mb_emit_icall (mb, mono_marshal_alloc);
6041 mono_mb_emit_stloc (mb, 1);
6042 mono_mb_emit_ldloc (mb, 1);
6043 mono_mb_emit_stloc (mb, m->retobj_var);
6045 /* emit valuetype conversion code */
6046 emit_struct_conv (mb, klass, FALSE);
6050 g_assert_not_reached ();
6057 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
6058 MonoMarshalSpec *spec,
6059 int conv_arg, MonoType **conv_arg_type,
6060 MarshalAction action)
6062 MonoMethodBuilder *mb = m->mb;
6063 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6064 MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
6068 case MARSHAL_ACTION_CONV_IN:
6069 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6070 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6073 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6076 mono_mb_emit_ldarg (mb, argnum);
6077 mono_mb_emit_byte (mb, CEE_LDIND_I);
6079 mono_mb_emit_ldarg (mb, argnum);
6083 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6084 MonoException *exc = mono_get_exception_not_implemented (msg);
6085 g_warning ("%s", msg);
6087 mono_raise_exception (exc);
6090 mono_mb_emit_icall (mb, conv_to_icall (conv));
6092 mono_mb_emit_stloc (mb, conv_arg);
6095 case MARSHAL_ACTION_CONV_OUT:
6096 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6098 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6099 mono_mb_emit_exception_marshal_directive (mb, msg);
6103 if (encoding == MONO_NATIVE_VBBYREFSTR) {
6104 static MonoMethod *m;
6107 m = mono_class_get_method_from_name_flags (mono_defaults.string_class, "get_Length", -1, 0);
6112 * Have to allocate a new string with the same length as the original, and
6113 * copy the contents of the buffer pointed to by CONV_ARG into it.
6115 g_assert (t->byref);
6116 mono_mb_emit_ldarg (mb, argnum);
6117 mono_mb_emit_ldloc (mb, conv_arg);
6118 mono_mb_emit_ldarg (mb, argnum);
6119 mono_mb_emit_byte (mb, CEE_LDIND_I);
6120 mono_mb_emit_managed_call (mb, m, NULL);
6121 mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
6122 mono_mb_emit_byte (mb, CEE_STIND_REF);
6123 } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6124 mono_mb_emit_ldarg (mb, argnum);
6125 mono_mb_emit_ldloc (mb, conv_arg);
6126 mono_mb_emit_icall (mb, conv_to_icall (conv));
6127 mono_mb_emit_byte (mb, CEE_STIND_REF);
6130 if (need_free || (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
6131 mono_mb_emit_ldloc (mb, conv_arg);
6132 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
6133 mono_mb_emit_icall (mb, mono_free_bstr);
6135 mono_mb_emit_icall (mb, mono_marshal_free);
6139 case MARSHAL_ACTION_PUSH:
6140 if (t->byref && encoding != MONO_NATIVE_VBBYREFSTR)
6141 mono_mb_emit_ldloc_addr (mb, conv_arg);
6143 mono_mb_emit_ldloc (mb, conv_arg);
6146 case MARSHAL_ACTION_CONV_RESULT:
6147 mono_mb_emit_stloc (mb, 0);
6149 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6151 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6152 mono_mb_emit_exception_marshal_directive (mb, msg);
6156 mono_mb_emit_ldloc (mb, 0);
6157 mono_mb_emit_icall (mb, conv_to_icall (conv));
6158 mono_mb_emit_stloc (mb, 3);
6160 /* free the string */
6161 mono_mb_emit_ldloc (mb, 0);
6162 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
6163 mono_mb_emit_icall (mb, mono_free_bstr);
6165 mono_mb_emit_icall (mb, mono_marshal_free);
6168 case MARSHAL_ACTION_MANAGED_CONV_IN:
6169 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6171 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6174 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6178 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6180 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6181 mono_mb_emit_exception_marshal_directive (mb, msg);
6185 mono_mb_emit_ldarg (mb, argnum);
6187 mono_mb_emit_byte (mb, CEE_LDIND_I);
6188 mono_mb_emit_icall (mb, conv_to_icall (conv));
6189 mono_mb_emit_stloc (mb, conv_arg);
6192 case MARSHAL_ACTION_MANAGED_CONV_OUT:
6195 mono_mb_emit_ldarg (mb, argnum);
6196 mono_mb_emit_ldloc (mb, conv_arg);
6197 mono_mb_emit_icall (mb, conv_to_icall (conv));
6198 mono_mb_emit_byte (mb, CEE_STIND_I);
6203 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6204 if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
6205 /* We need to make a copy so the caller is able to free it */
6206 mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
6208 mono_mb_emit_icall (mb, conv_to_icall (conv));
6209 mono_mb_emit_stloc (mb, 3);
6213 g_assert_not_reached ();
6220 emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t,
6221 MonoMarshalSpec *spec, int conv_arg,
6222 MonoType **conv_arg_type, MarshalAction action)
6224 MonoMethodBuilder *mb = m->mb;
6227 case MARSHAL_ACTION_CONV_IN: {
6228 MonoType *intptr_type;
6229 int dar_release_slot, pos;
6231 intptr_type = &mono_defaults.int_class->byval_arg;
6232 conv_arg = mono_mb_add_local (mb, intptr_type);
6233 *conv_arg_type = intptr_type;
6235 if (!sh_dangerous_add_ref)
6236 init_safe_handle ();
6238 mono_mb_emit_ldarg (mb, argnum);
6239 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6240 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
6242 mono_mb_patch_branch (mb, pos);
6245 * My tests in show that ref SafeHandles are not really
6246 * passed as ref objects. Instead a NULL is passed as the
6249 mono_mb_emit_icon (mb, 0);
6250 mono_mb_emit_stloc (mb, conv_arg);
6254 /* Create local to hold the ref parameter to DangerousAddRef */
6255 dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
6257 /* set release = false; */
6258 mono_mb_emit_icon (mb, 0);
6259 mono_mb_emit_stloc (mb, dar_release_slot);
6261 /* safehandle.DangerousAddRef (ref release) */
6262 mono_mb_emit_ldarg (mb, argnum);
6263 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
6264 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
6266 /* Pull the handle field from SafeHandle */
6267 mono_mb_emit_ldarg (mb, argnum);
6268 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6269 mono_mb_emit_byte (mb, CEE_LDIND_I);
6270 mono_mb_emit_stloc (mb, conv_arg);
6275 case MARSHAL_ACTION_PUSH:
6277 mono_mb_emit_ldloc_addr (mb, conv_arg);
6279 mono_mb_emit_ldloc (mb, conv_arg);
6282 case MARSHAL_ACTION_CONV_OUT: {
6283 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
6284 int dar_release_slot = conv_arg + 1;
6287 if (!sh_dangerous_release)
6288 init_safe_handle ();
6294 * My tests indicate that ref SafeHandles parameters are not actually
6295 * passed by ref, but instead a new Handle is created regardless of
6296 * whether a change happens in the unmanaged side.
6298 * Also, the Handle is created before calling into unmanaged code,
6299 * but we do not support that mechanism (getting to the original
6300 * handle) and it makes no difference where we create this
6302 ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
6304 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
6307 /* refval = new SafeHandleDerived ()*/
6308 mono_mb_emit_ldarg (mb, argnum);
6309 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
6310 mono_mb_emit_byte (mb, CEE_STIND_REF);
6312 /* refval.handle = returned_handle */
6313 mono_mb_emit_ldarg (mb, argnum);
6314 mono_mb_emit_byte (mb, CEE_LDIND_REF);
6315 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6316 mono_mb_emit_ldloc (mb, conv_arg);
6317 mono_mb_emit_byte (mb, CEE_STIND_I);
6319 mono_mb_emit_ldloc (mb, dar_release_slot);
6320 label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
6321 mono_mb_emit_ldarg (mb, argnum);
6322 mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
6323 mono_mb_patch_branch (mb, label_next);
6328 case MARSHAL_ACTION_CONV_RESULT: {
6329 MonoMethod *ctor = NULL;
6330 int intptr_handle_slot;
6332 if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
6333 mono_mb_emit_byte (mb, CEE_POP);
6334 mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
6338 ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
6340 mono_mb_emit_byte (mb, CEE_POP);
6341 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
6344 /* Store the IntPtr results into a local */
6345 intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6346 mono_mb_emit_stloc (mb, intptr_handle_slot);
6348 /* Create return value */
6349 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
6350 mono_mb_emit_stloc (mb, 3);
6352 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
6353 mono_mb_emit_ldloc (mb, 3);
6354 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6355 mono_mb_emit_ldloc (mb, intptr_handle_slot);
6356 mono_mb_emit_byte (mb, CEE_STIND_I);
6360 case MARSHAL_ACTION_MANAGED_CONV_IN:
6361 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6364 case MARSHAL_ACTION_MANAGED_CONV_OUT:
6365 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6368 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6369 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6372 printf ("Unhandled case for MarshalAction: %d\n", action);
6379 emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t,
6380 MonoMarshalSpec *spec, int conv_arg,
6381 MonoType **conv_arg_type, MarshalAction action)
6383 MonoMethodBuilder *mb = m->mb;
6386 case MARSHAL_ACTION_CONV_IN: {
6387 MonoType *intptr_type;
6389 intptr_type = &mono_defaults.int_class->byval_arg;
6390 conv_arg = mono_mb_add_local (mb, intptr_type);
6391 *conv_arg_type = intptr_type;
6394 char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
6395 mono_mb_emit_exception_marshal_directive (mb, msg);
6398 mono_mb_emit_ldarg_addr (mb, argnum);
6399 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
6400 mono_mb_emit_byte (mb, CEE_ADD);
6401 mono_mb_emit_byte (mb, CEE_LDIND_I);
6402 mono_mb_emit_stloc (mb, conv_arg);
6406 case MARSHAL_ACTION_PUSH:
6407 mono_mb_emit_ldloc (mb, conv_arg);
6410 case MARSHAL_ACTION_CONV_OUT: {
6411 /* no resource release required */
6415 case MARSHAL_ACTION_CONV_RESULT: {
6416 char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
6417 mono_mb_emit_exception_marshal_directive (mb, msg);
6421 case MARSHAL_ACTION_MANAGED_CONV_IN:
6422 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6425 case MARSHAL_ACTION_MANAGED_CONV_OUT:
6426 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6429 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6430 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6433 fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
6440 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
6441 MonoMarshalSpec *spec,
6442 int conv_arg, MonoType **conv_arg_type,
6443 MarshalAction action)
6445 MonoMethodBuilder *mb = m->mb;
6446 MonoClass *klass = mono_class_from_mono_type (t);
6450 case MARSHAL_ACTION_CONV_IN:
6451 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6452 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6454 m->orig_conv_args [argnum] = 0;
6456 if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
6457 char *msg = g_strdup_printf ("Marshalling of type object is not implemented");
6458 mono_mb_emit_exception_marshal_directive (mb, msg);
6462 if (klass->delegate) {
6464 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6465 char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented.");
6466 mono_mb_emit_exception_marshal_directive (mb, msg);
6468 mono_mb_emit_byte (mb, CEE_LDNULL);
6469 mono_mb_emit_stloc (mb, conv_arg);
6471 mono_mb_emit_ldarg (mb, argnum);
6472 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
6473 mono_mb_emit_stloc (mb, conv_arg);
6475 } else if (klass == mono_defaults.stringbuilder_class) {
6476 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6477 MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
6480 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6481 char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
6482 mono_mb_emit_exception_marshal_directive (mb, msg);
6487 mono_mb_emit_ldarg (mb, argnum);
6490 mono_mb_emit_icall (mb, conv_to_icall (conv));
6492 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
6493 MonoException *exc = mono_get_exception_not_implemented (msg);
6494 g_warning ("%s", msg);
6496 mono_raise_exception (exc);
6499 mono_mb_emit_stloc (mb, conv_arg);
6500 } else if (klass->blittable) {
6501 mono_mb_emit_byte (mb, CEE_LDNULL);
6502 mono_mb_emit_stloc (mb, conv_arg);
6504 mono_mb_emit_ldarg (mb, argnum);
6505 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6507 mono_mb_emit_ldarg (mb, argnum);
6508 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6509 mono_mb_emit_stloc (mb, conv_arg);
6511 mono_mb_patch_branch (mb, pos);
6514 mono_mb_emit_byte (mb, CEE_LDNULL);
6515 mono_mb_emit_stloc (mb, conv_arg);
6518 /* we dont need any conversions for out parameters */
6519 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6522 mono_mb_emit_ldarg (mb, argnum);
6523 mono_mb_emit_byte (mb, CEE_LDIND_I);
6526 mono_mb_emit_ldarg (mb, argnum);
6527 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6528 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
6531 /* store the address of the source into local variable 0 */
6532 mono_mb_emit_stloc (mb, 0);
6533 mono_mb_emit_ldloc (mb, 0);
6534 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6536 /* allocate space for the native struct and store the address */
6537 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6538 mono_mb_emit_byte (mb, CEE_PREFIX1);
6539 mono_mb_emit_byte (mb, CEE_LOCALLOC);
6540 mono_mb_emit_stloc (mb, conv_arg);
6543 /* Need to store the original buffer so we can free it later */
6544 m->orig_conv_args [argnum] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6545 mono_mb_emit_ldloc (mb, conv_arg);
6546 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
6549 /* set the src_ptr */
6550 mono_mb_emit_ldloc (mb, 0);
6551 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6552 mono_mb_emit_stloc (mb, 0);
6555 mono_mb_emit_ldloc (mb, conv_arg);
6556 mono_mb_emit_stloc (mb, 1);
6558 /* emit valuetype conversion code */
6559 emit_struct_conv (mb, klass, FALSE);
6561 mono_mb_patch_branch (mb, pos);
6565 case MARSHAL_ACTION_CONV_OUT:
6566 if (klass == mono_defaults.stringbuilder_class) {
6568 MonoMarshalNative encoding;
6569 MonoMarshalConv conv;
6571 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6572 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
6574 g_assert (encoding != -1);
6577 g_assert ((t->attrs & PARAM_ATTRIBUTE_OUT));
6581 mono_mb_emit_ldarg (mb, argnum);
6582 mono_mb_emit_ldloc (mb, conv_arg);
6585 case MONO_NATIVE_LPWSTR:
6586 mono_mb_emit_icall (mb, mono_string_utf16_to_builder2);
6588 case MONO_NATIVE_LPSTR:
6589 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
6592 g_assert_not_reached ();
6595 mono_mb_emit_byte (mb, CEE_STIND_REF);
6597 mono_mb_emit_ldarg (mb, argnum);
6598 mono_mb_emit_ldloc (mb, conv_arg);
6600 mono_mb_emit_icall (mb, conv_to_icall (conv));
6604 mono_mb_emit_ldloc (mb, conv_arg);
6605 mono_mb_emit_icall (mb, mono_marshal_free);
6610 if (klass->delegate) {
6612 mono_mb_emit_ldarg (mb, argnum);
6613 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6614 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6615 mono_mb_emit_ldloc (mb, conv_arg);
6616 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6617 mono_mb_emit_byte (mb, CEE_STIND_REF);
6622 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6623 /* allocate a new object */
6624 mono_mb_emit_ldarg (mb, argnum);
6625 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6626 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
6627 mono_mb_emit_byte (mb, CEE_STIND_REF);
6630 /* dst = *argument */
6631 mono_mb_emit_ldarg (mb, argnum);
6634 mono_mb_emit_byte (mb, CEE_LDIND_I);
6636 mono_mb_emit_stloc (mb, 1);
6638 mono_mb_emit_ldloc (mb, 1);
6639 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6641 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6642 mono_mb_emit_ldloc (mb, 1);
6643 mono_mb_emit_icon (mb, sizeof (MonoObject));
6644 mono_mb_emit_byte (mb, CEE_ADD);
6645 mono_mb_emit_stloc (mb, 1);
6647 /* src = tmp_locals [i] */
6648 mono_mb_emit_ldloc (mb, conv_arg);
6649 mono_mb_emit_stloc (mb, 0);
6651 /* emit valuetype conversion code */
6652 emit_struct_conv (mb, klass, TRUE);
6654 /* Free the structure returned by the native code */
6655 emit_struct_free (mb, klass, conv_arg);
6657 if (m->orig_conv_args [argnum]) {
6659 * If the native function changed the pointer, then free
6660 * the original structure plus the new pointer.
6662 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
6663 mono_mb_emit_ldloc (mb, conv_arg);
6664 pos2 = mono_mb_emit_branch (mb, CEE_BEQ);
6666 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6667 g_assert (m->orig_conv_args [argnum]);
6669 emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
6672 mono_mb_emit_ldloc (mb, conv_arg);
6673 mono_mb_emit_icall (mb, mono_marshal_free);
6675 mono_mb_patch_branch (mb, pos2);
6679 /* Free the original structure passed to native code */
6680 emit_struct_free (mb, klass, conv_arg);
6682 mono_mb_patch_branch (mb, pos);
6685 case MARSHAL_ACTION_PUSH:
6687 mono_mb_emit_ldloc_addr (mb, conv_arg);
6689 mono_mb_emit_ldloc (mb, conv_arg);
6692 case MARSHAL_ACTION_CONV_RESULT:
6693 if (klass->delegate) {
6694 g_assert (!t->byref);
6695 mono_mb_emit_stloc (mb, 0);
6696 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6697 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6698 mono_mb_emit_ldloc (mb, 0);
6699 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6700 mono_mb_emit_stloc (mb, 3);
6703 mono_mb_emit_stloc (mb, 0);
6705 /* Make a copy since emit_conv modifies local 0 */
6706 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6707 mono_mb_emit_ldloc (mb, 0);
6708 mono_mb_emit_stloc (mb, loc);
6710 mono_mb_emit_byte (mb, CEE_LDNULL);
6711 mono_mb_emit_stloc (mb, 3);
6713 mono_mb_emit_ldloc (mb, 0);
6714 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6716 /* allocate result object */
6718 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6719 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
6720 mono_mb_emit_stloc (mb, 3);
6724 mono_mb_emit_ldloc (mb, 3);
6725 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6726 mono_mb_emit_stloc (mb, 1);
6728 /* emit conversion code */
6729 emit_struct_conv (mb, klass, TRUE);
6731 emit_struct_free (mb, klass, loc);
6733 /* Free the pointer allocated by unmanaged code */
6734 mono_mb_emit_ldloc (mb, loc);
6735 mono_mb_emit_icall (mb, mono_marshal_free);
6736 mono_mb_patch_branch (mb, pos);
6740 case MARSHAL_ACTION_MANAGED_CONV_IN:
6741 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
6743 if (klass->delegate) {
6744 g_assert (!t->byref);
6745 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6746 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6747 mono_mb_emit_ldarg (mb, argnum);
6748 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6749 mono_mb_emit_stloc (mb, conv_arg);
6753 if (klass == mono_defaults.stringbuilder_class) {
6754 MonoMarshalNative encoding;
6756 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6759 g_assert (encoding == MONO_NATIVE_LPSTR);
6761 g_assert (!t->byref);
6762 g_assert (encoding != -1);
6764 mono_mb_emit_ldarg (mb, argnum);
6765 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
6766 mono_mb_emit_stloc (mb, conv_arg);
6770 /* The class can not have an automatic layout */
6771 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
6772 mono_mb_emit_auto_layout_exception (mb, klass);
6776 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
6777 mono_mb_emit_byte (mb, CEE_LDNULL);
6778 mono_mb_emit_stloc (mb, conv_arg);
6783 mono_mb_emit_ldarg (mb, argnum);
6787 /* Check for NULL and raise an exception */
6788 pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
6790 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
6792 mono_mb_patch_branch (mb, pos2);
6793 mono_mb_emit_ldarg (mb, argnum);
6794 mono_mb_emit_byte (mb, CEE_LDIND_I);
6797 mono_mb_emit_stloc (mb, 0);
6799 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6800 mono_mb_emit_stloc (mb, conv_arg);
6802 mono_mb_emit_ldloc (mb, 0);
6803 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6805 /* Create and set dst */
6806 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6807 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
6808 mono_mb_emit_stloc (mb, conv_arg);
6809 mono_mb_emit_ldloc (mb, conv_arg);
6810 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6811 mono_mb_emit_stloc (mb, 1);
6813 /* emit valuetype conversion code */
6814 emit_struct_conv (mb, klass, TRUE);
6816 mono_mb_patch_branch (mb, pos);
6819 case MARSHAL_ACTION_MANAGED_CONV_OUT:
6821 /* Check for null */
6822 mono_mb_emit_ldloc (mb, conv_arg);
6823 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6824 mono_mb_emit_ldarg (mb, argnum);
6825 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6826 mono_mb_emit_byte (mb, CEE_STIND_REF);
6827 pos2 = mono_mb_emit_branch (mb, CEE_BR);
6829 mono_mb_patch_branch (mb, pos);
6832 mono_mb_emit_ldloc (mb, conv_arg);
6833 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6834 mono_mb_emit_stloc (mb, 0);
6836 /* Allocate and set dest */
6837 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6838 mono_mb_emit_byte (mb, CEE_CONV_I);
6839 mono_mb_emit_icall (mb, mono_marshal_alloc);
6840 mono_mb_emit_stloc (mb, 1);
6842 /* Update argument pointer */
6843 mono_mb_emit_ldarg (mb, argnum);
6844 mono_mb_emit_ldloc (mb, 1);
6845 mono_mb_emit_byte (mb, CEE_STIND_I);
6847 /* emit valuetype conversion code */
6848 emit_struct_conv (mb, klass, FALSE);
6850 mono_mb_patch_branch (mb, pos2);
6852 /* byval [Out] marshalling */
6854 /* FIXME: Handle null */
6857 mono_mb_emit_ldloc (mb, conv_arg);
6858 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6859 mono_mb_emit_stloc (mb, 0);
6862 mono_mb_emit_ldarg (mb, argnum);
6863 mono_mb_emit_stloc (mb, 1);
6865 /* emit valuetype conversion code */
6866 emit_struct_conv (mb, klass, FALSE);
6870 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6871 if (klass->delegate) {
6872 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
6873 mono_mb_emit_stloc (mb, 3);
6877 /* The class can not have an automatic layout */
6878 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
6879 mono_mb_emit_auto_layout_exception (mb, klass);
6883 mono_mb_emit_stloc (mb, 0);
6884 /* Check for null */
6885 mono_mb_emit_ldloc (mb, 0);
6886 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6887 mono_mb_emit_byte (mb, CEE_LDNULL);
6888 mono_mb_emit_stloc (mb, 3);
6889 pos2 = mono_mb_emit_branch (mb, CEE_BR);
6891 mono_mb_patch_branch (mb, pos);
6894 mono_mb_emit_ldloc (mb, 0);
6895 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6896 mono_mb_emit_stloc (mb, 0);
6898 /* Allocate and set dest */
6899 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6900 mono_mb_emit_byte (mb, CEE_CONV_I);
6901 mono_mb_emit_icall (mb, mono_marshal_alloc);
6902 mono_mb_emit_byte (mb, CEE_DUP);
6903 mono_mb_emit_stloc (mb, 1);
6904 mono_mb_emit_stloc (mb, 3);
6906 emit_struct_conv (mb, klass, FALSE);
6908 mono_mb_patch_branch (mb, pos2);
6912 g_assert_not_reached ();
6919 emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
6920 MonoMarshalSpec *spec,
6921 int conv_arg, MonoType **conv_arg_type,
6922 MarshalAction action)
6924 MonoMethodBuilder *mb = m->mb;
6925 static MonoMethod *get_object_for_native_variant = NULL;
6926 static MonoMethod *get_native_variant_for_object = NULL;
6928 mono_init_com_types ();
6930 if (!get_object_for_native_variant)
6931 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
6932 g_assert (get_object_for_native_variant);
6934 if (!get_native_variant_for_object)
6935 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
6936 g_assert (get_native_variant_for_object);
6939 case MARSHAL_ACTION_CONV_IN: {
6940 conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
6943 *conv_arg_type = &mono_defaults.variant_class->this_arg;
6945 *conv_arg_type = &mono_defaults.variant_class->byval_arg;
6947 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
6950 mono_mb_emit_ldarg (mb, argnum);
6952 mono_mb_emit_byte(mb, CEE_LDIND_REF);
6953 mono_mb_emit_ldloc_addr (mb, conv_arg);
6954 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
6958 case MARSHAL_ACTION_CONV_OUT: {
6959 static MonoMethod *variant_clear = NULL;
6962 variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
6963 g_assert (variant_clear);
6966 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
6967 mono_mb_emit_ldarg (mb, argnum);
6968 mono_mb_emit_ldloc_addr (mb, conv_arg);
6969 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
6970 mono_mb_emit_byte (mb, CEE_STIND_REF);
6973 mono_mb_emit_ldloc_addr (mb, conv_arg);
6974 mono_mb_emit_managed_call (mb, variant_clear, NULL);
6978 case MARSHAL_ACTION_PUSH:
6980 mono_mb_emit_ldloc_addr (mb, conv_arg);
6982 mono_mb_emit_ldloc (mb, conv_arg);
6985 case MARSHAL_ACTION_CONV_RESULT: {
6986 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
6987 mono_mb_emit_exception_marshal_directive (mb, msg);
6991 case MARSHAL_ACTION_MANAGED_CONV_IN: {
6992 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6995 *conv_arg_type = &mono_defaults.variant_class->this_arg;
6997 *conv_arg_type = &mono_defaults.variant_class->byval_arg;
6999 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
7003 mono_mb_emit_ldarg (mb, argnum);
7005 mono_mb_emit_ldarg_addr (mb, argnum);
7006 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
7007 mono_mb_emit_stloc (mb, conv_arg);
7011 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7012 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
7013 mono_mb_emit_ldloc (mb, conv_arg);
7014 mono_mb_emit_ldarg (mb, argnum);
7015 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
7020 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7021 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
7022 mono_mb_emit_exception_marshal_directive (mb, msg);
7027 g_assert_not_reached ();
7034 mono_pinvoke_is_unicode (MonoMethodPInvoke *piinfo)
7036 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
7037 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
7039 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
7041 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
7052 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
7053 MonoMarshalSpec *spec,
7054 int conv_arg, MonoType **conv_arg_type,
7055 MarshalAction action)
7057 MonoMethodBuilder *mb = m->mb;
7058 MonoClass *klass = mono_class_from_mono_type (t);
7059 gboolean need_convert, need_free;
7060 MonoMarshalNative encoding;
7062 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
7065 case MARSHAL_ACTION_CONV_IN:
7066 *conv_arg_type = &mono_defaults.object_class->byval_arg;
7067 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7069 if (klass->element_class->blittable) {
7070 mono_mb_emit_ldarg (mb, argnum);
7072 mono_mb_emit_byte (mb, CEE_LDIND_I);
7073 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
7074 mono_mb_emit_stloc (mb, conv_arg);
7077 guint32 label1, label2, label3;
7078 int index_var, src_var, dest_ptr, esize;
7079 MonoMarshalConv conv;
7080 gboolean is_string = FALSE;
7082 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7084 eklass = klass->element_class;
7086 if (eklass == mono_defaults.string_class) {
7088 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7090 else if (eklass == mono_defaults.stringbuilder_class) {
7092 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
7097 src_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7098 mono_mb_emit_ldarg (mb, argnum);
7100 mono_mb_emit_byte (mb, CEE_LDIND_I);
7101 mono_mb_emit_stloc (mb, src_var);
7104 mono_mb_emit_ldloc (mb, src_var);
7105 mono_mb_emit_stloc (mb, conv_arg);
7106 mono_mb_emit_ldloc (mb, src_var);
7107 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7111 char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
7112 MonoException *exc = mono_get_exception_not_implemented (msg);
7113 g_warning ("%s", msg);
7115 mono_raise_exception (exc);
7120 esize = sizeof (gpointer);
7121 else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
7122 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
7124 esize = mono_class_native_size (eklass, NULL);
7126 /* allocate space for the native struct and store the address */
7127 mono_mb_emit_icon (mb, esize);
7128 mono_mb_emit_ldloc (mb, src_var);
7129 mono_mb_emit_byte (mb, CEE_LDLEN);
7131 if (eklass == mono_defaults.string_class) {
7132 /* Make the array bigger for the terminating null */
7133 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7134 mono_mb_emit_byte (mb, CEE_ADD);
7136 mono_mb_emit_byte (mb, CEE_MUL);
7137 mono_mb_emit_byte (mb, CEE_PREFIX1);
7138 mono_mb_emit_byte (mb, CEE_LOCALLOC);
7139 mono_mb_emit_stloc (mb, conv_arg);
7141 mono_mb_emit_ldloc (mb, conv_arg);
7142 mono_mb_emit_stloc (mb, dest_ptr);
7144 /* Emit marshalling loop */
7145 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7146 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7147 mono_mb_emit_stloc (mb, index_var);
7148 label2 = mono_mb_get_label (mb);
7149 mono_mb_emit_ldloc (mb, index_var);
7150 mono_mb_emit_ldloc (mb, src_var);
7151 mono_mb_emit_byte (mb, CEE_LDLEN);
7152 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7154 /* Emit marshalling code */
7157 mono_mb_emit_ldloc (mb, dest_ptr);
7158 mono_mb_emit_ldloc (mb, src_var);
7159 mono_mb_emit_ldloc (mb, index_var);
7160 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7161 mono_mb_emit_icall (mb, conv_to_icall (conv));
7162 mono_mb_emit_byte (mb, CEE_STIND_I);
7164 /* set the src_ptr */
7165 mono_mb_emit_ldloc (mb, src_var);
7166 mono_mb_emit_ldloc (mb, index_var);
7167 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
7168 mono_mb_emit_stloc (mb, 0);
7171 mono_mb_emit_ldloc (mb, dest_ptr);
7172 mono_mb_emit_stloc (mb, 1);
7174 /* emit valuetype conversion code */
7175 emit_struct_conv_full (mb, eklass, FALSE, eklass == mono_defaults.char_class ? encoding : -1);
7178 mono_mb_emit_add_to_local (mb, index_var, 1);
7179 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
7181 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7183 mono_mb_patch_branch (mb, label3);
7185 if (eklass == mono_defaults.string_class) {
7186 /* Null terminate */
7187 mono_mb_emit_ldloc (mb, dest_ptr);
7188 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7189 mono_mb_emit_byte (mb, CEE_STIND_REF);
7192 mono_mb_patch_branch (mb, label1);
7197 case MARSHAL_ACTION_CONV_OUT:
7198 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
7199 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);
7200 need_free = mono_marshal_need_free (&klass->element_class->byval_arg,
7203 if (need_convert || need_free) {
7204 /* FIXME: Optimize blittable case */
7206 guint32 label1, label2, label3;
7207 int index_var, src_ptr, loc, esize;
7209 eklass = klass->element_class;
7210 if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
7211 esize = sizeof (gpointer);
7212 else if (eklass == mono_defaults.char_class)
7213 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
7215 esize = mono_class_native_size (eklass, NULL);
7216 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7217 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7220 mono_mb_emit_ldarg (mb, argnum);
7222 mono_mb_emit_byte (mb, CEE_LDIND_I);
7223 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7225 mono_mb_emit_ldloc (mb, conv_arg);
7226 mono_mb_emit_stloc (mb, src_ptr);
7228 /* Emit marshalling loop */
7229 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7230 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7231 mono_mb_emit_stloc (mb, index_var);
7232 label2 = mono_mb_get_label (mb);
7233 mono_mb_emit_ldloc (mb, index_var);
7234 mono_mb_emit_ldarg (mb, argnum);
7236 mono_mb_emit_byte (mb, CEE_LDIND_REF);
7237 mono_mb_emit_byte (mb, CEE_LDLEN);
7238 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7240 /* Emit marshalling code */
7242 if (eklass == mono_defaults.stringbuilder_class) {
7243 gboolean need_free2;
7244 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
7246 g_assert (conv != -1);
7249 mono_mb_emit_ldarg (mb, argnum);
7251 mono_mb_emit_byte (mb, CEE_LDIND_I);
7252 mono_mb_emit_ldloc (mb, index_var);
7253 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7256 mono_mb_emit_ldloc (mb, src_ptr);
7257 mono_mb_emit_byte (mb, CEE_LDIND_I);
7259 mono_mb_emit_icall (mb, conv_to_icall (conv));
7263 mono_mb_emit_ldloc (mb, src_ptr);
7264 mono_mb_emit_byte (mb, CEE_LDIND_I);
7266 mono_mb_emit_icall (mb, mono_marshal_free);
7269 else if (eklass == mono_defaults.string_class) {
7272 mono_mb_emit_ldloc (mb, src_ptr);
7273 mono_mb_emit_byte (mb, CEE_LDIND_I);
7275 mono_mb_emit_icall (mb, mono_marshal_free);
7280 /* set the src_ptr */
7281 mono_mb_emit_ldloc (mb, src_ptr);
7282 mono_mb_emit_stloc (mb, 0);
7285 mono_mb_emit_ldarg (mb, argnum);
7287 mono_mb_emit_byte (mb, CEE_LDIND_REF);
7288 mono_mb_emit_ldloc (mb, index_var);
7289 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
7290 mono_mb_emit_stloc (mb, 1);
7292 /* emit valuetype conversion code */
7293 emit_struct_conv_full (mb, eklass, TRUE, eklass == mono_defaults.char_class ? encoding : -1);
7297 mono_mb_emit_ldloc (mb, src_ptr);
7298 mono_mb_emit_stloc (mb, loc);
7299 mono_mb_emit_ldloc (mb, loc);
7301 emit_struct_free (mb, eklass, loc);
7305 mono_mb_emit_add_to_local (mb, index_var, 1);
7306 mono_mb_emit_add_to_local (mb, src_ptr, esize);
7308 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7310 mono_mb_patch_branch (mb, label1);
7311 mono_mb_patch_branch (mb, label3);
7314 if (klass->element_class->blittable) {
7315 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
7317 mono_mb_emit_ldarg (mb, argnum);
7318 mono_mb_emit_ldloc (mb, conv_arg);
7319 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
7324 case MARSHAL_ACTION_PUSH:
7326 mono_mb_emit_ldloc_addr (mb, conv_arg);
7328 mono_mb_emit_ldloc (mb, conv_arg);
7331 case MARSHAL_ACTION_CONV_RESULT:
7332 /* fixme: we need conversions here */
7333 mono_mb_emit_stloc (mb, 3);
7336 case MARSHAL_ACTION_MANAGED_CONV_IN: {
7338 guint32 label1, label2, label3;
7339 int index_var, src_ptr, loc, esize, param_num, num_elem;
7340 MonoMarshalConv conv;
7341 gboolean is_string = FALSE;
7343 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7344 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7347 char *msg = g_strdup ("Byref array marshalling to managed code is not implemented.");
7348 mono_mb_emit_exception_marshal_directive (mb, msg);
7352 char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
7353 mono_mb_emit_exception_marshal_directive (mb, msg);
7356 if (spec->native != MONO_NATIVE_LPARRAY) {
7357 char *msg = g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
7358 mono_mb_emit_exception_marshal_directive (mb, msg);
7362 /* FIXME: t is from the method which is wrapped, not the delegate type */
7363 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
7365 param_num = spec->data.array_data.param_num;
7366 num_elem = spec->data.array_data.num_elem;
7367 if (spec->data.array_data.elem_mult == 0)
7368 /* param_num is not specified */
7371 if (param_num == -1) {
7372 if (num_elem <= 0) {
7373 char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
7374 mono_mb_emit_exception_marshal_directive (mb, msg);
7379 /* FIXME: Optimize blittable case */
7381 eklass = klass->element_class;
7382 if (eklass == mono_defaults.string_class) {
7384 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
7386 else if (eklass == mono_defaults.stringbuilder_class) {
7388 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
7393 mono_marshal_load_type_info (eklass);
7396 esize = sizeof (gpointer);
7398 esize = mono_class_native_size (eklass, NULL);
7399 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7400 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7402 mono_mb_emit_byte (mb, CEE_LDNULL);
7403 mono_mb_emit_stloc (mb, conv_arg);
7405 /* Check param index */
7406 if (param_num != -1) {
7407 if (param_num >= m->sig->param_count) {
7408 char *msg = g_strdup ("Array size control parameter index is out of range.");
7409 mono_mb_emit_exception_marshal_directive (mb, msg);
7412 switch (m->sig->params [param_num]->type) {
7425 char *msg = g_strdup ("Array size control parameter must be an integral type.");
7426 mono_mb_emit_exception_marshal_directive (mb, msg);
7433 mono_mb_emit_ldarg (mb, argnum);
7434 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7436 mono_mb_emit_ldarg (mb, argnum);
7437 mono_mb_emit_stloc (mb, src_ptr);
7439 /* Create managed array */
7441 * The LPArray marshalling spec says that sometimes param_num starts
7442 * from 1, sometimes it starts from 0. But MS seems to allways start
7446 if (param_num == -1) {
7447 mono_mb_emit_icon (mb, num_elem);
7449 mono_mb_emit_ldarg (mb, param_num);
7451 mono_mb_emit_icon (mb, num_elem);
7452 mono_mb_emit_byte (mb, CEE_ADD);
7454 mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
7457 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
7458 mono_mb_emit_stloc (mb, conv_arg);
7460 if (eklass->blittable) {
7461 mono_mb_emit_ldloc (mb, conv_arg);
7462 mono_mb_emit_byte (mb, CEE_CONV_I);
7463 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
7464 mono_mb_emit_byte (mb, CEE_ADD);
7465 mono_mb_emit_ldarg (mb, argnum);
7466 mono_mb_emit_ldloc (mb, conv_arg);
7467 mono_mb_emit_byte (mb, CEE_LDLEN);
7468 mono_mb_emit_icon (mb, esize);
7469 mono_mb_emit_byte (mb, CEE_MUL);
7470 mono_mb_emit_byte (mb, CEE_PREFIX1);
7471 mono_mb_emit_byte (mb, CEE_CPBLK);
7475 /* Emit marshalling loop */
7476 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7477 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7478 mono_mb_emit_stloc (mb, index_var);
7479 label2 = mono_mb_get_label (mb);
7480 mono_mb_emit_ldloc (mb, index_var);
7481 mono_mb_emit_ldloc (mb, conv_arg);
7482 mono_mb_emit_byte (mb, CEE_LDLEN);
7483 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7485 /* Emit marshalling code */
7487 g_assert (conv != -1);
7489 mono_mb_emit_ldloc (mb, conv_arg);
7490 mono_mb_emit_ldloc (mb, index_var);
7492 mono_mb_emit_ldloc (mb, src_ptr);
7493 mono_mb_emit_byte (mb, CEE_LDIND_I);
7495 mono_mb_emit_icall (mb, conv_to_icall (conv));
7496 mono_mb_emit_byte (mb, CEE_STELEM_REF);
7499 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7500 mono_mb_emit_exception_marshal_directive (mb, msg);
7504 mono_mb_emit_add_to_local (mb, index_var, 1);
7505 mono_mb_emit_add_to_local (mb, src_ptr, esize);
7507 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7509 mono_mb_patch_branch (mb, label1);
7510 mono_mb_patch_branch (mb, label3);
7514 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7516 guint32 label1, label2, label3;
7517 int index_var, dest_ptr, loc, esize, param_num, num_elem;
7518 MonoMarshalConv conv;
7519 gboolean is_string = FALSE;
7522 /* Already handled in CONV_IN */
7525 /* These are already checked in CONV_IN */
7526 g_assert (!t->byref);
7527 g_assert (spec->native == MONO_NATIVE_LPARRAY);
7528 g_assert (t->attrs & PARAM_ATTRIBUTE_OUT);
7530 param_num = spec->data.array_data.param_num;
7531 num_elem = spec->data.array_data.num_elem;
7533 if (spec->data.array_data.elem_mult == 0)
7534 /* param_num is not specified */
7537 if (param_num == -1) {
7538 if (num_elem <= 0) {
7539 g_assert_not_reached ();
7543 /* FIXME: Optimize blittable case */
7545 eklass = klass->element_class;
7546 if (eklass == mono_defaults.string_class) {
7548 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7550 else if (eklass == mono_defaults.stringbuilder_class) {
7552 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
7557 mono_marshal_load_type_info (eklass);
7560 esize = sizeof (gpointer);
7562 esize = mono_class_native_size (eklass, NULL);
7564 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7565 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7568 mono_mb_emit_ldloc (mb, conv_arg);
7569 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7571 mono_mb_emit_ldarg (mb, argnum);
7572 mono_mb_emit_stloc (mb, dest_ptr);
7574 if (eklass->blittable) {
7576 mono_mb_emit_ldarg (mb, argnum);
7578 mono_mb_emit_ldloc (mb, conv_arg);
7579 mono_mb_emit_byte (mb, CEE_CONV_I);
7580 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
7581 mono_mb_emit_byte (mb, CEE_ADD);
7583 mono_mb_emit_ldloc (mb, conv_arg);
7584 mono_mb_emit_byte (mb, CEE_LDLEN);
7585 mono_mb_emit_icon (mb, esize);
7586 mono_mb_emit_byte (mb, CEE_MUL);
7587 mono_mb_emit_byte (mb, CEE_PREFIX1);
7588 mono_mb_emit_byte (mb, CEE_CPBLK);
7592 /* Emit marshalling loop */
7593 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7594 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7595 mono_mb_emit_stloc (mb, index_var);
7596 label2 = mono_mb_get_label (mb);
7597 mono_mb_emit_ldloc (mb, index_var);
7598 mono_mb_emit_ldloc (mb, conv_arg);
7599 mono_mb_emit_byte (mb, CEE_LDLEN);
7600 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7602 /* Emit marshalling code */
7604 g_assert (conv != -1);
7607 mono_mb_emit_ldloc (mb, dest_ptr);
7610 mono_mb_emit_ldloc (mb, conv_arg);
7611 mono_mb_emit_ldloc (mb, index_var);
7613 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7615 mono_mb_emit_icall (mb, conv_to_icall (conv));
7616 mono_mb_emit_byte (mb, CEE_STIND_I);
7619 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7620 mono_mb_emit_exception_marshal_directive (mb, msg);
7624 mono_mb_emit_add_to_local (mb, index_var, 1);
7625 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
7627 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7629 mono_mb_patch_branch (mb, label1);
7630 mono_mb_patch_branch (mb, label3);
7634 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7636 guint32 label1, label2, label3;
7637 int index_var, src, dest, esize;
7638 MonoMarshalConv conv = -1;
7639 gboolean is_string = FALSE;
7641 g_assert (!t->byref);
7643 eklass = klass->element_class;
7645 mono_marshal_load_type_info (eklass);
7647 if (eklass == mono_defaults.string_class) {
7649 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7652 g_assert_not_reached ();
7656 esize = sizeof (gpointer);
7657 else if (eklass == mono_defaults.char_class)
7658 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
7660 esize = mono_class_native_size (eklass, NULL);
7662 src = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7663 dest = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7665 mono_mb_emit_stloc (mb, src);
7666 mono_mb_emit_ldloc (mb, src);
7667 mono_mb_emit_stloc (mb, 3);
7669 /* Check for null */
7670 mono_mb_emit_ldloc (mb, src);
7671 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7673 /* Allocate native array */
7674 mono_mb_emit_icon (mb, esize);
7675 mono_mb_emit_ldloc (mb, src);
7676 mono_mb_emit_byte (mb, CEE_LDLEN);
7678 if (eklass == mono_defaults.string_class) {
7679 /* Make the array bigger for the terminating null */
7680 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7681 mono_mb_emit_byte (mb, CEE_ADD);
7683 mono_mb_emit_byte (mb, CEE_MUL);
7684 mono_mb_emit_icall (mb, mono_marshal_alloc);
7685 mono_mb_emit_stloc (mb, dest);
7686 mono_mb_emit_ldloc (mb, dest);
7687 mono_mb_emit_stloc (mb, 3);
7689 /* Emit marshalling loop */
7690 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7691 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7692 mono_mb_emit_stloc (mb, index_var);
7693 label2 = mono_mb_get_label (mb);
7694 mono_mb_emit_ldloc (mb, index_var);
7695 mono_mb_emit_ldloc (mb, src);
7696 mono_mb_emit_byte (mb, CEE_LDLEN);
7697 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7699 /* Emit marshalling code */
7701 g_assert (conv != -1);
7704 mono_mb_emit_ldloc (mb, dest);
7707 mono_mb_emit_ldloc (mb, src);
7708 mono_mb_emit_ldloc (mb, index_var);
7710 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7712 mono_mb_emit_icall (mb, conv_to_icall (conv));
7713 mono_mb_emit_byte (mb, CEE_STIND_I);
7716 char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
7717 mono_mb_emit_exception_marshal_directive (mb, msg);
7721 mono_mb_emit_add_to_local (mb, index_var, 1);
7722 mono_mb_emit_add_to_local (mb, dest, esize);
7724 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7726 mono_mb_patch_branch (mb, label3);
7727 mono_mb_patch_branch (mb, label1);
7731 g_assert_not_reached ();
7738 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
7739 MonoMarshalSpec *spec,
7740 int conv_arg, MonoType **conv_arg_type,
7741 MarshalAction action)
7743 MonoMethodBuilder *mb = m->mb;
7746 case MARSHAL_ACTION_CONV_IN: {
7747 MonoType *local_type;
7749 guint8 ldc_op = CEE_LDC_I4_1;
7752 local_type = &mono_defaults.int32_class->byval_arg;
7754 switch (spec->native) {
7755 case MONO_NATIVE_I1:
7756 case MONO_NATIVE_U1:
7757 local_type = &mono_defaults.byte_class->byval_arg;
7759 case MONO_NATIVE_VARIANTBOOL:
7760 local_type = &mono_defaults.int16_class->byval_arg;
7761 ldc_op = CEE_LDC_I4_M1;
7763 case MONO_NATIVE_BOOLEAN:
7764 local_type = &mono_defaults.int32_class->byval_arg;
7767 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
7768 local_type = &mono_defaults.int32_class->byval_arg;
7773 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7775 *conv_arg_type = local_type;
7776 conv_arg = mono_mb_add_local (mb, local_type);
7778 mono_mb_emit_ldarg (mb, argnum);
7780 mono_mb_emit_byte (mb, CEE_LDIND_I1);
7781 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7782 mono_mb_emit_byte (mb, ldc_op);
7783 mono_mb_emit_stloc (mb, conv_arg);
7784 mono_mb_patch_branch (mb, label_false);
7789 case MARSHAL_ACTION_CONV_OUT:
7791 int label_false, label_end;
7795 mono_mb_emit_ldarg (mb, argnum);
7796 mono_mb_emit_ldloc (mb, conv_arg);
7798 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7799 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7801 label_end = mono_mb_emit_branch (mb, CEE_BR);
7802 mono_mb_patch_branch (mb, label_false);
7803 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7804 mono_mb_patch_branch (mb, label_end);
7806 mono_mb_emit_byte (mb, CEE_STIND_I1);
7810 case MARSHAL_ACTION_PUSH:
7812 mono_mb_emit_ldloc_addr (mb, conv_arg);
7814 mono_mb_emit_ldloc (mb, conv_arg);
7816 mono_mb_emit_ldarg (mb, argnum);
7819 case MARSHAL_ACTION_CONV_RESULT:
7820 /* maybe we need to make sure that it fits within 8 bits */
7821 mono_mb_emit_stloc (mb, 3);
7824 case MARSHAL_ACTION_MANAGED_CONV_IN: {
7825 MonoClass* conv_arg_class = mono_defaults.int32_class;
7826 guint8 ldop = CEE_LDIND_I4;
7827 int label_null, label_false;
7829 conv_arg = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
7832 switch (spec->native) {
7833 case MONO_NATIVE_I1:
7834 case MONO_NATIVE_U1:
7835 conv_arg_class = mono_defaults.byte_class;
7836 ldop = CEE_LDIND_I1;
7838 case MONO_NATIVE_VARIANTBOOL:
7839 conv_arg_class = mono_defaults.int16_class;
7840 ldop = CEE_LDIND_I2;
7842 case MONO_NATIVE_BOOLEAN:
7845 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
7850 *conv_arg_type = &conv_arg_class->this_arg;
7852 *conv_arg_type = &conv_arg_class->byval_arg;
7855 mono_mb_emit_ldarg (mb, argnum);
7859 label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
7860 mono_mb_emit_ldarg (mb, argnum);
7861 mono_mb_emit_byte (mb, ldop);
7865 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7866 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7867 mono_mb_emit_stloc (mb, conv_arg);
7868 mono_mb_patch_branch (mb, label_false);
7871 mono_mb_patch_branch (mb, label_null);
7875 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7876 guint8 stop = CEE_STIND_I4;
7877 guint8 ldc_op = CEE_LDC_I4_1;
7878 int label_null,label_false, label_end;;
7883 switch (spec->native) {
7884 case MONO_NATIVE_I1:
7885 case MONO_NATIVE_U1:
7886 stop = CEE_STIND_I1;
7888 case MONO_NATIVE_VARIANTBOOL:
7889 stop = CEE_STIND_I2;
7890 ldc_op = CEE_LDC_I4_M1;
7898 mono_mb_emit_ldarg (mb, argnum);
7899 label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
7901 mono_mb_emit_ldarg (mb, argnum);
7902 mono_mb_emit_ldloc (mb, conv_arg);
7904 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7905 mono_mb_emit_byte (mb, ldc_op);
7906 label_end = mono_mb_emit_branch (mb, CEE_BR);
7908 mono_mb_patch_branch (mb, label_false);
7909 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7910 mono_mb_patch_branch (mb, label_end);
7912 mono_mb_emit_byte (mb, stop);
7913 mono_mb_patch_branch (mb, label_null);
7918 g_assert_not_reached ();
7925 emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t,
7926 MonoMarshalSpec *spec, int conv_arg,
7927 MonoType **conv_arg_type, MarshalAction action)
7929 MonoMethodBuilder *mb = m->mb;
7932 case MARSHAL_ACTION_CONV_IN:
7933 /* MS seems to allow this in some cases, ie. bxc #158 */
7935 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
7936 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
7937 mono_mb_emit_exception_marshal_directive (m->mb, msg);
7942 case MARSHAL_ACTION_PUSH:
7943 mono_mb_emit_ldarg (mb, argnum);
7946 case MARSHAL_ACTION_CONV_RESULT:
7947 /* no conversions necessary */
7948 mono_mb_emit_stloc (mb, 3);
7959 emit_marshal_char (EmitMarshalContext *m, int argnum, MonoType *t,
7960 MonoMarshalSpec *spec, int conv_arg,
7961 MonoType **conv_arg_type, MarshalAction action)
7963 MonoMethodBuilder *mb = m->mb;
7966 case MARSHAL_ACTION_PUSH:
7967 /* fixme: dont know how to marshal that. We cant simply
7968 * convert it to a one byte UTF8 character, because an
7969 * unicode character may need more that one byte in UTF8 */
7970 mono_mb_emit_ldarg (mb, argnum);
7973 case MARSHAL_ACTION_CONV_RESULT:
7974 /* fixme: we need conversions here */
7975 mono_mb_emit_stloc (mb, 3);
7986 emit_marshal_scalar (EmitMarshalContext *m, int argnum, MonoType *t,
7987 MonoMarshalSpec *spec, int conv_arg,
7988 MonoType **conv_arg_type, MarshalAction action)
7990 MonoMethodBuilder *mb = m->mb;
7993 case MARSHAL_ACTION_PUSH:
7994 mono_mb_emit_ldarg (mb, argnum);
7997 case MARSHAL_ACTION_CONV_RESULT:
7998 /* no conversions necessary */
7999 mono_mb_emit_stloc (mb, 3);
8010 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
8011 MonoMarshalSpec *spec, int conv_arg,
8012 MonoType **conv_arg_type, MarshalAction action)
8014 /* Ensure that we have marshalling info for this param */
8015 mono_marshal_load_type_info (mono_class_from_mono_type (t));
8017 if (spec && spec->native == MONO_NATIVE_CUSTOM)
8018 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8020 if (spec && spec->native == MONO_NATIVE_ASANY)
8021 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8024 case MONO_TYPE_VALUETYPE:
8025 if (t->data.klass == mono_defaults.handleref_class)
8026 return emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8028 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8029 case MONO_TYPE_STRING:
8030 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8031 case MONO_TYPE_CLASS:
8032 case MONO_TYPE_OBJECT:
8033 if (spec && spec->native == MONO_NATIVE_STRUCT)
8034 return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8037 if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
8038 spec->native == MONO_NATIVE_IDISPATCH ||
8039 spec->native == MONO_NATIVE_INTERFACE))
8040 return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8041 if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) &&
8042 (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) &&
8043 ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH)))
8044 return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8047 if (mono_defaults.safehandle_class != NULL && t->data.klass &&
8048 mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE))
8049 return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8051 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8052 case MONO_TYPE_ARRAY:
8053 case MONO_TYPE_SZARRAY:
8054 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8055 case MONO_TYPE_BOOLEAN:
8056 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8058 return emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8059 case MONO_TYPE_CHAR:
8060 return emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8073 case MONO_TYPE_FNPTR:
8074 return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8075 case MONO_TYPE_GENERICINST:
8076 if (mono_type_generic_inst_is_valuetype (t))
8077 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8079 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8086 * mono_marshal_emit_native_wrapper:
8087 * @image: the image to use for looking up custom marshallers
8088 * @sig: The signature of the native function
8089 * @piinfo: Marshalling information
8090 * @mspecs: Marshalling information
8091 * @aot: whenever the created method will be compiled by the AOT compiler
8092 * @method: if non-NULL, the pinvoke method to call
8093 * @check_exceptions: Whenever to check for pending exceptions after the native call
8095 * generates IL code for the pinvoke wrapper, the generated code calls @func.
8098 mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions)
8100 EmitMarshalContext m;
8101 MonoMethodSignature *csig;
8103 int i, argnum, *tmp_locals;
8105 static MonoMethodSignature *get_last_error_sig = NULL;
8110 /* we copy the signature, so that we can set pinvoke to 0 */
8111 csig = signature_dup (mb->method->klass->image, sig);
8116 /* we allocate local for use with emit_struct_conv() */
8117 /* allocate local 0 (pointer) src_ptr */
8118 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8119 /* allocate local 1 (pointer) dst_ptr */
8120 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8121 /* allocate local 2 (boolean) delete_old */
8122 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
8124 /* delete_old = FALSE */
8125 mono_mb_emit_icon (mb, 0);
8126 mono_mb_emit_stloc (mb, 2);
8128 if (!MONO_TYPE_IS_VOID(sig->ret)) {
8129 /* allocate local 3 to store the return value */
8130 mono_mb_add_local (mb, sig->ret);
8133 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
8134 /* Return type custom marshaling */
8136 * Since we can't determine the return type of the unmanaged function,
8137 * we assume it returns a pointer, and pass that pointer to
8138 * MarshalNativeToManaged.
8140 csig->ret = &mono_defaults.int_class->byval_arg;
8143 /* we first do all conversions */
8144 tmp_locals = alloca (sizeof (int) * sig->param_count);
8145 m.orig_conv_args = alloca (sizeof (int) * (sig->param_count + 1));
8147 for (i = 0; i < sig->param_count; i ++) {
8148 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
8151 /* push all arguments */
8154 mono_mb_emit_byte (mb, CEE_LDARG_0);
8156 for (i = 0; i < sig->param_count; i++) {
8157 emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
8160 /* call the native method */
8161 if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
8163 mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
8165 g_assert_not_reached ();
8170 /* Reuse the ICALL_ADDR opcode for pinvokes too */
8171 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8172 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
8173 mono_mb_emit_calli (mb, csig);
8175 mono_mb_emit_native_call (mb, csig, func);
8179 /* Set LastError if needed */
8180 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
8181 if (!get_last_error_sig) {
8182 get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
8183 get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
8184 get_last_error_sig->pinvoke = 1;
8189 * Have to call GetLastError () early and without a wrapper, since various runtime components could
8190 * clobber its value.
8192 mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
8193 mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
8195 mono_mb_emit_icall (mb, mono_marshal_set_last_error);
8199 /* convert the result */
8200 if (!sig->ret->byref) {
8201 MonoMarshalSpec *spec = mspecs [0];
8202 type = sig->ret->type;
8204 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
8205 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8210 case MONO_TYPE_VOID:
8212 case MONO_TYPE_VALUETYPE:
8213 klass = sig->ret->data.klass;
8214 if (klass->enumtype) {
8215 type = mono_class_enum_basetype (sig->ret->data.klass)->type;
8218 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8232 case MONO_TYPE_FNPTR:
8233 case MONO_TYPE_STRING:
8234 case MONO_TYPE_CLASS:
8235 case MONO_TYPE_OBJECT:
8236 case MONO_TYPE_BOOLEAN:
8237 case MONO_TYPE_ARRAY:
8238 case MONO_TYPE_SZARRAY:
8239 case MONO_TYPE_CHAR:
8241 case MONO_TYPE_GENERICINST:
8242 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8244 case MONO_TYPE_TYPEDBYREF:
8246 g_warning ("return type 0x%02x unknown", sig->ret->type);
8247 g_assert_not_reached ();
8251 mono_mb_emit_stloc (mb, 3);
8255 * Need to call this after converting the result since MONO_VTADDR needs
8256 * to be adjacent to the call instruction.
8258 if (check_exceptions)
8259 emit_thread_interrupt_checkpoint (mb);
8261 /* we need to convert byref arguments back and free string arrays */
8262 for (i = 0; i < sig->param_count; i++) {
8263 MonoType *t = sig->params [i];
8264 MonoMarshalSpec *spec = mspecs [i + 1];
8266 argnum = i + sig->hasthis;
8268 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
8269 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
8274 case MONO_TYPE_STRING:
8275 case MONO_TYPE_VALUETYPE:
8276 case MONO_TYPE_CLASS:
8277 case MONO_TYPE_OBJECT:
8278 case MONO_TYPE_SZARRAY:
8279 case MONO_TYPE_BOOLEAN:
8280 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
8285 if (!MONO_TYPE_IS_VOID(sig->ret))
8286 mono_mb_emit_ldloc (mb, 3);
8288 mono_mb_emit_byte (mb, CEE_RET);
8291 G_GNUC_UNUSED static void
8292 code_for (MonoMethod *method) {
8293 MonoMethodHeader *header = mono_method_get_header (method);
8294 printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (method, TRUE), mono_disasm_code (0, method, header->code, header->code + header->code_size));
8298 * mono_marshal_get_native_wrapper:
8299 * @method: The MonoMethod to wrap.
8300 * @check_exceptions: Whenever to check for pending exceptions
8302 * generates IL code for the pinvoke wrapper (the generated method
8303 * calls the unmanaged code in piinfo->addr)
8304 * The wrapper info for the wrapper is a WrapperInfo structure.
8307 mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
8309 MonoMethodSignature *sig, *csig;
8310 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
8311 MonoMethodBuilder *mb;
8312 MonoMarshalSpec **mspecs;
8315 gboolean pinvoke = FALSE;
8318 const char *exc_class = "MissingMethodException";
8319 const char *exc_arg = NULL;
8322 g_assert (method != NULL);
8323 g_assert (mono_method_signature (method)->pinvoke);
8326 cache = get_cache (&method->klass->image->native_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
8328 cache = get_cache (&method->klass->image->native_wrapper_cache, mono_aligned_addr_hash, NULL);
8329 if ((res = mono_marshal_find_in_cache (cache, method)))
8332 if (MONO_CLASS_IS_IMPORT (method->klass)) {
8334 return mono_cominterop_get_native_wrapper (method);
8336 g_assert_not_reached ();
8340 sig = mono_method_signature (method);
8342 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
8343 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
8346 if (!piinfo->addr) {
8348 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
8349 exc_arg = "Method contains unsupported native code";
8351 mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
8353 piinfo->addr = mono_lookup_internal_call (method);
8356 /* hack - redirect certain string constructors to CreateString */
8357 if (piinfo->addr == ves_icall_System_String_ctor_RedirectToCreateString) {
8358 g_assert (!pinvoke);
8359 g_assert (method->string_ctor);
8360 g_assert (sig->hasthis);
8362 /* CreateString returns a value */
8363 csig = signature_dup (method->klass->image, sig);
8364 csig->ret = &mono_defaults.string_class->byval_arg;
8368 while ((res = mono_class_get_methods (mono_defaults.string_class, &iter))) {
8369 if (!strcmp ("CreateString", res->name) &&
8370 mono_metadata_signature_equal (csig, mono_method_signature (res))) {
8373 g_assert (!(res->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
8374 g_assert (!(res->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
8376 /* create a wrapper to preserve .ctor in stack trace */
8377 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
8379 mono_mb_emit_byte (mb, CEE_LDARG_0);
8380 for (i = 1; i <= csig->param_count; i++)
8381 mono_mb_emit_ldarg (mb, i);
8382 mono_mb_emit_managed_call (mb, res, NULL);
8383 mono_mb_emit_byte (mb, CEE_RET);
8385 /* use native_wrapper_cache because internal calls are looked up there */
8386 res = mono_mb_create_and_cache (cache, method,
8387 mb, csig, csig->param_count + 1);
8391 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_STRING_CTOR);
8392 info->d.string_ctor.method = method;
8394 mono_marshal_set_wrapper_info (res, info);
8400 /* exception will be thrown */
8401 piinfo->addr = NULL;
8402 g_warning ("cannot find CreateString for .ctor");
8405 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8407 mb->method->save_lmf = 1;
8410 * In AOT mode and embedding scenarios, it is possible that the icall is not
8411 * registered in the runtime doing the AOT compilation.
8413 if (!piinfo->addr && !aot) {
8414 mono_mb_emit_exception (mb, exc_class, exc_arg);
8415 csig = signature_dup (method->klass->image, sig);
8417 res = mono_mb_create_and_cache (cache, method,
8418 mb, csig, csig->param_count + 16);
8423 /* internal calls: we simply push all arguments and call the method (no conversions) */
8424 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
8426 csig = signature_dup_add_this (sig, method->klass);
8428 csig = signature_dup (method->klass->image, sig);
8430 /* hack - string constructors returns a value */
8431 if (method->string_ctor)
8432 csig->ret = &mono_defaults.string_class->byval_arg;
8438 * Add a null check since public icalls can be called with 'call' which
8439 * does no such check.
8441 mono_mb_emit_byte (mb, CEE_LDARG_0);
8442 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
8443 mono_mb_emit_exception (mb, "NullReferenceException", NULL);
8444 mono_mb_patch_branch (mb, pos);
8446 mono_mb_emit_byte (mb, CEE_LDARG_0);
8449 for (i = 0; i < sig->param_count; i++)
8450 mono_mb_emit_ldarg (mb, i + sig->hasthis);
8453 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8454 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
8455 mono_mb_emit_calli (mb, csig);
8457 g_assert (piinfo->addr);
8458 mono_mb_emit_native_call (mb, csig, piinfo->addr);
8460 if (check_exceptions)
8461 emit_thread_interrupt_checkpoint (mb);
8462 mono_mb_emit_byte (mb, CEE_RET);
8464 csig = signature_dup (method->klass->image, csig);
8466 res = mono_mb_create_and_cache (cache, method,
8467 mb, csig, csig->param_count + 16);
8469 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE);
8470 info->d.managed_to_native.method = method;
8471 mono_marshal_set_wrapper_info (res, info);
8479 g_assert (piinfo->addr);
8481 mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
8482 mono_method_get_marshal_info (method, mspecs);
8484 mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, aot, check_exceptions);
8486 csig = signature_dup (method->klass->image, sig);
8488 res = mono_mb_create_and_cache (cache, method,
8489 mb, csig, csig->param_count + 16);
8492 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE);
8493 info->d.managed_to_native.method = method;
8494 mono_marshal_set_wrapper_info (res, info);
8496 for (i = sig->param_count; i >= 0; i--)
8498 mono_metadata_free_marshal_spec (mspecs [i]);
8501 /* code_for (res); */
8507 * mono_marshal_get_native_func_wrapper:
8508 * @image: The image to use for memory allocation and for looking up custom marshallers.
8509 * @sig: The signature of the function
8510 * @func: The native function to wrap
8512 * Returns a wrapper method around native functions, similar to the pinvoke
8516 mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig,
8517 MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
8519 MonoMethodSignature *csig;
8521 MonoMethodBuilder *mb;
8526 cache = get_cache (&image->native_wrapper_cache, mono_aligned_addr_hash, NULL);
8527 if ((res = mono_marshal_find_in_cache (cache, func)))
8530 name = g_strdup_printf ("wrapper_native_%p", func);
8531 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8532 mb->method->save_lmf = 1;
8534 mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE);
8536 csig = signature_dup (image, sig);
8538 res = mono_mb_create_and_cache (cache, func,
8539 mb, csig, csig->param_count + 16);
8542 mono_marshal_set_wrapper_info (res, NULL);
8544 /* code_for (res); */
8550 * mono_marshal_emit_managed_wrapper:
8552 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
8553 * the delegate which wraps the managed method to be called. For closed delegates,
8554 * it could have fewer parameters than the method it wraps.
8555 * THIS_LOC is the memory location where the target of the delegate is stored.
8558 mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle)
8560 MonoMethodSignature *sig, *csig;
8562 gboolean closed = FALSE;
8567 /* allocate local 0 (pointer) src_ptr */
8568 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8569 /* allocate local 1 (pointer) dst_ptr */
8570 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8571 /* allocate local 2 (boolean) delete_old */
8572 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
8574 if (!sig->hasthis && sig->param_count != invoke_sig->param_count) {
8575 /* Closed delegate */
8576 g_assert (sig->param_count == invoke_sig->param_count + 1);
8578 /* Use a new signature without the first argument */
8579 sig = mono_metadata_signature_dup (sig);
8580 memmove (&sig->params [0], &sig->params [1], (sig->param_count - 1) * sizeof (MonoType*));
8581 sig->param_count --;
8584 if (!MONO_TYPE_IS_VOID(sig->ret)) {
8585 /* allocate local 3 to store the return value */
8586 mono_mb_add_local (mb, sig->ret);
8589 mono_mb_emit_icon (mb, 0);
8590 mono_mb_emit_stloc (mb, 2);
8592 /* we first do all conversions */
8593 tmp_locals = alloca (sizeof (int) * sig->param_count);
8594 for (i = 0; i < sig->param_count; i ++) {
8595 MonoType *t = sig->params [i];
8598 case MONO_TYPE_OBJECT:
8599 case MONO_TYPE_CLASS:
8600 case MONO_TYPE_VALUETYPE:
8601 case MONO_TYPE_ARRAY:
8602 case MONO_TYPE_SZARRAY:
8603 case MONO_TYPE_STRING:
8604 case MONO_TYPE_BOOLEAN:
8605 tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
8614 emit_thread_interrupt_checkpoint (mb);
8617 if (target_handle) {
8618 mono_mb_emit_icon (mb, (gint32)target_handle);
8619 mono_mb_emit_icall (mb, mono_gchandle_get_target);
8622 g_assert_not_reached ();
8624 } else if (closed) {
8625 mono_mb_emit_icon (mb, (gint32)target_handle);
8626 mono_mb_emit_icall (mb, mono_gchandle_get_target);
8629 for (i = 0; i < sig->param_count; i++) {
8630 MonoType *t = sig->params [i];
8632 if (tmp_locals [i]) {
8634 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
8636 mono_mb_emit_ldloc (mb, tmp_locals [i]);
8639 mono_mb_emit_ldarg (mb, i);
8642 mono_mb_emit_managed_call (mb, method, NULL);
8644 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
8645 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8646 } else if (!sig->ret->byref) {
8647 switch (sig->ret->type) {
8648 case MONO_TYPE_VOID:
8650 case MONO_TYPE_BOOLEAN:
8653 case MONO_TYPE_CHAR:
8665 case MONO_TYPE_OBJECT:
8666 mono_mb_emit_stloc (mb, 3);
8668 case MONO_TYPE_STRING:
8669 csig->ret = &mono_defaults.int_class->byval_arg;
8670 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8672 case MONO_TYPE_VALUETYPE:
8673 case MONO_TYPE_CLASS:
8674 case MONO_TYPE_SZARRAY:
8675 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8678 g_warning ("return type 0x%02x unknown", sig->ret->type);
8679 g_assert_not_reached ();
8682 mono_mb_emit_stloc (mb, 3);
8685 /* Convert byref arguments back */
8686 for (i = 0; i < sig->param_count; i ++) {
8687 MonoType *t = sig->params [i];
8688 MonoMarshalSpec *spec = mspecs [i + 1];
8690 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
8691 emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8693 else if (t->byref) {
8695 case MONO_TYPE_CLASS:
8696 case MONO_TYPE_VALUETYPE:
8697 case MONO_TYPE_OBJECT:
8698 case MONO_TYPE_STRING:
8699 case MONO_TYPE_BOOLEAN:
8700 emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8704 else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
8705 /* The [Out] information is encoded in the delegate signature */
8707 case MONO_TYPE_SZARRAY:
8708 case MONO_TYPE_CLASS:
8709 case MONO_TYPE_VALUETYPE:
8710 emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8713 g_assert_not_reached ();
8718 if (m->retobj_var) {
8719 mono_mb_emit_ldloc (mb, m->retobj_var);
8720 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8721 mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
8724 if (!MONO_TYPE_IS_VOID(sig->ret))
8725 mono_mb_emit_ldloc (mb, 3);
8726 mono_mb_emit_byte (mb, CEE_RET);
8735 mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *csig)
8737 MonoMethodSignature *sig;
8742 * Under windows, delegates passed to native code must use the STDCALL
8743 * calling convention.
8745 csig->call_convention = MONO_CALL_STDCALL;
8748 sig = mono_method_signature (method);
8750 /* Change default calling convention if needed */
8751 /* Why is this a modopt ? */
8752 if (sig->ret && sig->ret->num_mods) {
8753 for (i = 0; i < sig->ret->num_mods; ++i) {
8754 MonoClass *cmod_class = mono_class_get (method->klass->image, sig->ret->modifiers [i].token);
8755 g_assert (cmod_class);
8756 if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
8757 if (!strcmp (cmod_class->name, "CallConvCdecl"))
8758 csig->call_convention = MONO_CALL_C;
8759 else if (!strcmp (cmod_class->name, "CallConvStdcall"))
8760 csig->call_convention = MONO_CALL_STDCALL;
8761 else if (!strcmp (cmod_class->name, "CallConvFastcall"))
8762 csig->call_convention = MONO_CALL_FASTCALL;
8763 else if (!strcmp (cmod_class->name, "CallConvThiscall"))
8764 csig->call_convention = MONO_CALL_THISCALL;
8771 * generates IL code to call managed methods from unmanaged code
8772 * If target_handle==0, the wrapper info will be a WrapperInfo structure.
8775 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
8777 static MonoClass *UnmanagedFunctionPointerAttribute;
8778 MonoMethodSignature *sig, *csig, *invoke_sig;
8779 MonoMethodBuilder *mb;
8780 MonoMethod *res, *invoke;
8781 MonoMarshalSpec **mspecs;
8782 MonoMethodPInvoke piinfo;
8785 EmitMarshalContext m;
8787 g_assert (method != NULL);
8788 g_assert (!mono_method_signature (method)->pinvoke);
8791 * FIXME: Should cache the method+delegate type pair, since the same method
8792 * could be called with different delegates, thus different marshalling
8795 cache = get_cache (&method->klass->image->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
8796 if (!target_handle && (res = mono_marshal_find_in_cache (cache, method)))
8799 invoke = mono_get_delegate_invoke (delegate_klass);
8800 invoke_sig = mono_method_signature (invoke);
8802 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
8803 mono_method_get_marshal_info (invoke, mspecs);
8805 sig = mono_method_signature (method);
8807 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
8809 /*the target gchandle must be the first entry after size and the wrapper itself.*/
8810 mono_mb_add_data (mb, GUINT_TO_POINTER (target_handle));
8812 /* we copy the signature, so that we can modify it */
8814 /* Need to free this later */
8815 csig = mono_metadata_signature_dup (invoke_sig);
8817 csig = signature_dup (method->klass->image, invoke_sig);
8826 m.image = method->klass->image;
8828 mono_marshal_set_callconv_from_modopt (invoke, csig);
8830 /* Handle the UnmanagedFunctionPointerAttribute */
8831 if (!UnmanagedFunctionPointerAttribute)
8832 UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
8834 /* The attribute is only available in Net 2.0 */
8835 if (UnmanagedFunctionPointerAttribute) {
8836 MonoCustomAttrInfo *cinfo;
8837 MonoCustomAttrEntry *attr;
8840 * The pinvoke attributes are stored in a real custom attribute. Obtain the
8841 * contents of the attribute without constructing it, as that might not be
8842 * possible when running in cross-compiling mode.
8844 cinfo = mono_custom_attrs_from_class (delegate_klass);
8847 for (i = 0; i < cinfo->num_attrs; ++i) {
8848 if (mono_class_has_parent (cinfo->attrs [i].ctor->klass, UnmanagedFunctionPointerAttribute)) {
8849 attr = &cinfo->attrs [i];
8855 MonoArray *typed_args, *named_args;
8856 CattrNamedArg *arginfo;
8860 MonoBoolean set_last_error = 0;
8861 MonoBoolean best_fit_mapping = 0;
8862 MonoBoolean throw_on_unmappable = 0;
8864 mono_reflection_create_custom_attr_data_args (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo);
8866 g_assert (mono_array_length (typed_args) == 1);
8869 o = mono_array_get (typed_args, MonoObject*, 0);
8870 call_conv = *(gint32*)mono_object_unbox (o);
8873 for (i = 0; i < mono_array_length (named_args); ++i) {
8874 CattrNamedArg *narg = &arginfo [i];
8876 o = mono_array_get (named_args, MonoObject*, i);
8878 g_assert (narg->field);
8879 if (!strcmp (narg->field->name, "CharSet")) {
8880 charset = *(gint32*)mono_object_unbox (o);
8881 } else if (!strcmp (narg->field->name, "SetLastError")) {
8882 set_last_error = *(MonoBoolean*)mono_object_unbox (o);
8883 } else if (!strcmp (narg->field->name, "BestFitMapping")) {
8884 best_fit_mapping = *(MonoBoolean*)mono_object_unbox (o);
8885 } else if (!strcmp (narg->field->name, "ThrowOnUnmappableChar")) {
8886 throw_on_unmappable = *(MonoBoolean*)mono_object_unbox (o);
8888 g_assert_not_reached ();
8894 memset (&piinfo, 0, sizeof (piinfo));
8896 piinfo.piflags = (call_conv << 8) | (charset ? (charset - 1) * 2 : 1) | set_last_error;
8898 csig->call_convention = call_conv - 1;
8901 if (cinfo && !cinfo->cached)
8902 mono_custom_attrs_free (cinfo);
8905 mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle);
8907 if (!target_handle) {
8910 res = mono_mb_create_and_cache (cache, method,
8911 mb, csig, sig->param_count + 16);
8912 // FIXME: Associate it with the method+delegate_klass pair
8913 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE);
8914 info->d.native_to_managed.method = method;
8915 info->d.native_to_managed.klass = delegate_klass;
8916 mono_marshal_set_wrapper_info (res, info);
8919 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
8923 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
8925 mono_metadata_free_marshal_spec (mspecs [i]);
8928 /* code_for (res); */
8934 mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
8937 MonoMethodSignature *sig;
8938 MonoMethodBuilder *mb;
8943 method = mono_get_method (image, token, NULL);
8946 if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) {
8947 MonoMethodSignature *csig;
8948 MonoMarshalSpec **mspecs;
8949 EmitMarshalContext m;
8951 sig = mono_method_signature (method);
8952 g_assert (!sig->hasthis);
8954 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
8955 mono_method_get_marshal_info (method, mspecs);
8957 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
8958 csig = signature_dup (image, sig);
8969 mono_marshal_set_callconv_from_modopt (method, csig);
8971 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
8973 mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, 0);
8976 method = mono_mb_create_method (mb, csig, sig->param_count + 16);
8979 for (i = sig->param_count; i >= 0; i--)
8981 mono_metadata_free_marshal_spec (mspecs [i]);
8984 return mono_compile_method (method);
8987 sig = mono_method_signature (method);
8988 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
8990 param_count = sig->param_count + sig->hasthis;
8991 for (i = 0; i < param_count; i++)
8992 mono_mb_emit_ldarg (mb, i);
8994 if (type & VTFIXUP_TYPE_CALL_MOST_DERIVED)
8995 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
8997 mono_mb_emit_op (mb, CEE_CALL, method);
8998 mono_mb_emit_byte (mb, CEE_RET);
9001 method = mono_mb_create_method (mb, sig, param_count);
9004 return mono_compile_method (method);
9007 static MonoReflectionType *
9008 type_from_handle (MonoType *handle)
9010 MonoDomain *domain = mono_domain_get ();
9011 MonoClass *klass = mono_class_from_mono_type (handle);
9013 MONO_ARCH_SAVE_REGS;
9015 mono_class_init (klass);
9016 return mono_type_get_object (domain, handle);
9020 * This does the equivalent of mono_object_castclass_with_cache.
9021 * The wrapper info for the wrapper is a WrapperInfo structure.
9024 mono_marshal_get_castclass_with_cache (void)
9026 static MonoMethod *cached;
9028 MonoMethodBuilder *mb;
9029 MonoMethodSignature *sig;
9030 int return_null_pos, cache_miss_pos, invalid_cast_pos;
9036 mb = mono_mb_new (mono_defaults.object_class, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS);
9037 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9038 sig->params [0] = &mono_defaults.object_class->byval_arg;
9039 sig->params [1] = &mono_defaults.int_class->byval_arg;
9040 sig->params [2] = &mono_defaults.int_class->byval_arg;
9041 sig->ret = &mono_defaults.object_class->byval_arg;
9044 /* allocate local 0 (pointer) obj_vtable */
9045 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9048 mono_mb_emit_ldarg (mb, 0);
9049 return_null_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
9051 /*obj_vtable = obj->vtable;*/
9052 mono_mb_emit_ldarg (mb, 0);
9053 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
9054 mono_mb_emit_byte (mb, CEE_LDIND_I);
9055 mono_mb_emit_stloc (mb, 0);
9058 mono_mb_emit_ldarg (mb, 2);
9059 mono_mb_emit_byte (mb, CEE_LDIND_I);
9060 mono_mb_emit_ldloc (mb, 0);
9062 /*if (*cache == obj_vtable)*/
9063 cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
9066 mono_mb_emit_ldarg (mb, 0);
9067 mono_mb_emit_byte (mb, CEE_RET);
9069 mono_mb_patch_branch (mb, cache_miss_pos);
9070 /*if (mono_object_isinst (obj, klass)) */
9071 mono_mb_emit_ldarg (mb, 0);
9072 mono_mb_emit_ldarg (mb, 1);
9073 mono_mb_emit_icall (mb, mono_object_isinst);
9074 invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
9076 /**cache = obj_vtable;*/
9077 mono_mb_emit_ldarg (mb, 2);
9078 mono_mb_emit_ldloc (mb, 0);
9079 mono_mb_emit_byte (mb, CEE_STIND_I);
9082 mono_mb_emit_ldarg (mb, 0);
9083 mono_mb_emit_byte (mb, CEE_RET);
9086 mono_mb_patch_branch (mb, invalid_cast_pos);
9087 mono_mb_emit_exception (mb, "InvalidCastException", NULL);
9090 mono_mb_patch_branch (mb, return_null_pos);
9091 mono_mb_emit_byte (mb, CEE_LDNULL);
9092 mono_mb_emit_byte (mb, CEE_RET);
9094 res = mono_mb_create_method (mb, sig, 8);
9095 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE);
9096 mono_marshal_set_wrapper_info (res, info);
9099 if (InterlockedCompareExchangePointer ((volatile gpointer *)&cached, res, NULL)) {
9100 mono_free_method (res);
9101 mono_metadata_free_method_signature (sig);
9109 * This does the equivalent of mono_object_isinst_with_cache.
9110 * The wrapper info for the wrapper is a WrapperInfo structure.
9113 mono_marshal_get_isinst_with_cache (void)
9115 static MonoMethod *cached;
9117 MonoMethodBuilder *mb;
9118 MonoMethodSignature *sig;
9119 int return_null_pos, cache_miss_pos, cache_hit_pos, not_an_instance_pos, negative_cache_hit_pos;
9125 mb = mono_mb_new (mono_defaults.object_class, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS);
9126 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9127 sig->params [0] = &mono_defaults.object_class->byval_arg;
9128 sig->params [1] = &mono_defaults.int_class->byval_arg;
9129 sig->params [2] = &mono_defaults.int_class->byval_arg;
9130 sig->ret = &mono_defaults.object_class->byval_arg;
9133 /* allocate local 0 (pointer) obj_vtable */
9134 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9135 /* allocate local 1 (pointer) cached_vtable */
9136 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9139 mono_mb_emit_ldarg (mb, 0);
9140 return_null_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
9142 /*obj_vtable = obj->vtable;*/
9143 mono_mb_emit_ldarg (mb, 0);
9144 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
9145 mono_mb_emit_byte (mb, CEE_LDIND_I);
9146 mono_mb_emit_stloc (mb, 0);
9148 /* cached_vtable = *cache*/
9149 mono_mb_emit_ldarg (mb, 2);
9150 mono_mb_emit_byte (mb, CEE_LDIND_I);
9151 mono_mb_emit_stloc (mb, 1);
9153 mono_mb_emit_ldloc (mb, 1);
9154 mono_mb_emit_byte (mb, CEE_LDC_I4);
9155 mono_mb_emit_i4 (mb, ~0x1);
9156 mono_mb_emit_byte (mb, CEE_CONV_U);
9157 mono_mb_emit_byte (mb, CEE_AND);
9158 mono_mb_emit_ldloc (mb, 0);
9159 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
9160 cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
9162 /*return (cached_vtable & 0x1) ? NULL : obj;*/
9163 mono_mb_emit_ldloc (mb, 1);
9164 mono_mb_emit_byte(mb, CEE_LDC_I4_1);
9165 mono_mb_emit_byte (mb, CEE_CONV_U);
9166 mono_mb_emit_byte (mb, CEE_AND);
9167 negative_cache_hit_pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
9170 mono_mb_emit_ldarg (mb, 0);
9171 cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
9174 mono_mb_patch_branch (mb, negative_cache_hit_pos);
9175 mono_mb_emit_byte (mb, CEE_LDNULL);
9177 mono_mb_patch_branch (mb, cache_hit_pos);
9178 mono_mb_emit_byte (mb, CEE_RET);
9180 mono_mb_patch_branch (mb, cache_miss_pos);
9181 /*if (mono_object_isinst (obj, klass)) */
9182 mono_mb_emit_ldarg (mb, 0);
9183 mono_mb_emit_ldarg (mb, 1);
9184 mono_mb_emit_icall (mb, mono_object_isinst);
9185 not_an_instance_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
9187 /**cache = obj_vtable;*/
9188 mono_mb_emit_ldarg (mb, 2);
9189 mono_mb_emit_ldloc (mb, 0);
9190 mono_mb_emit_byte (mb, CEE_STIND_I);
9193 mono_mb_emit_ldarg (mb, 0);
9194 mono_mb_emit_byte (mb, CEE_RET);
9197 mono_mb_patch_branch (mb, not_an_instance_pos);
9198 /* *cache = (gpointer)(obj_vtable | 0x1);*/
9199 mono_mb_emit_ldarg (mb, 2);
9200 /*obj_vtable | 0x1*/
9201 mono_mb_emit_ldloc (mb, 0);
9202 mono_mb_emit_byte(mb, CEE_LDC_I4_1);
9203 mono_mb_emit_byte (mb, CEE_CONV_U);
9204 mono_mb_emit_byte (mb, CEE_OR);
9207 mono_mb_emit_byte (mb, CEE_STIND_I);
9210 mono_mb_patch_branch (mb, return_null_pos);
9211 mono_mb_emit_byte (mb, CEE_LDNULL);
9212 mono_mb_emit_byte (mb, CEE_RET);
9214 res = mono_mb_create_method (mb, sig, 8);
9215 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_ISINST_WITH_CACHE);
9216 mono_marshal_set_wrapper_info (res, info);
9219 if (InterlockedCompareExchangePointer ((volatile gpointer *)&cached, res, NULL)) {
9220 mono_free_method (res);
9221 mono_metadata_free_method_signature (sig);
9229 * mono_marshal_get_isinst:
9230 * @klass: the type of the field
9232 * This method generates a function which can be used to check if an object is
9233 * an instance of the given type, icluding the case where the object is a proxy.
9234 * The generated function has the following signature:
9235 * MonoObject* __isinst_wrapper_ (MonoObject *obj)
9238 mono_marshal_get_isinst (MonoClass *klass)
9240 static MonoMethodSignature *isint_sig = NULL;
9243 int pos_was_ok, pos_failed, pos_end, pos_end2;
9245 MonoMethodBuilder *mb;
9247 cache = get_cache (&klass->image->isinst_cache, mono_aligned_addr_hash, NULL);
9248 if ((res = mono_marshal_find_in_cache (cache, klass)))
9252 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
9253 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
9254 isint_sig->ret = &mono_defaults.object_class->byval_arg;
9255 isint_sig->pinvoke = 0;
9258 name = g_strdup_printf ("__isinst_wrapper_%s", klass->name);
9259 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
9262 mb->method->save_lmf = 1;
9264 /* check if the object is a proxy that needs special cast */
9265 mono_mb_emit_ldarg (mb, 0);
9266 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
9267 mono_mb_emit_op (mb, CEE_MONO_CISINST, klass);
9269 /* The result of MONO_ISINST can be:
9270 0) the type check succeeded
9271 1) the type check did not succeed
9272 2) a CanCastTo call is needed */
9274 mono_mb_emit_byte (mb, CEE_DUP);
9275 pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
9277 mono_mb_emit_byte (mb, CEE_LDC_I4_2);
9278 pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
9280 /* get the real proxy from the transparent proxy*/
9282 mono_mb_emit_ldarg (mb, 0);
9283 mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
9284 pos_end = mono_mb_emit_branch (mb, CEE_BR);
9288 mono_mb_patch_branch (mb, pos_failed);
9289 mono_mb_emit_byte (mb, CEE_LDNULL);
9290 pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
9294 mono_mb_patch_branch (mb, pos_was_ok);
9295 mono_mb_emit_byte (mb, CEE_POP);
9296 mono_mb_emit_ldarg (mb, 0);
9300 mono_mb_patch_branch (mb, pos_end);
9301 mono_mb_patch_branch (mb, pos_end2);
9302 mono_mb_emit_byte (mb, CEE_RET);
9304 res = mono_mb_create_and_cache (cache, klass, mb, isint_sig, isint_sig->param_count + 16);
9311 * mono_marshal_get_castclass:
9312 * @klass: the type of the field
9314 * This method generates a function which can be used to cast an object to
9315 * an instance of the given type, icluding the case where the object is a proxy.
9316 * The generated function has the following signature:
9317 * MonoObject* __castclass_wrapper_ (MonoObject *obj)
9318 * The wrapper info for the wrapper is a WrapperInfo structure.
9321 mono_marshal_get_castclass (MonoClass *klass)
9323 static MonoMethodSignature *castclass_sig = NULL;
9326 int pos_was_ok, pos_was_ok2;
9328 MonoMethodBuilder *mb;
9331 cache = get_cache (&klass->image->castclass_cache, mono_aligned_addr_hash, NULL);
9332 if ((res = mono_marshal_find_in_cache (cache, klass)))
9335 if (!castclass_sig) {
9336 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
9337 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
9338 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
9339 castclass_sig->pinvoke = 0;
9342 name = g_strdup_printf ("__castclass_wrapper_%s", klass->name);
9343 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
9346 mb->method->save_lmf = 1;
9348 /* check if the object is a proxy that needs special cast */
9349 mono_mb_emit_ldarg (mb, 0);
9350 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
9351 mono_mb_emit_op (mb, CEE_MONO_CCASTCLASS, klass);
9353 /* The result of MONO_ISINST can be:
9354 0) the cast is valid
9355 1) cast of unknown proxy type
9356 or an exception if the cast is is invalid
9359 pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
9361 /* get the real proxy from the transparent proxy*/
9363 mono_mb_emit_ldarg (mb, 0);
9364 mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
9365 pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
9368 mono_mb_emit_exception (mb, "InvalidCastException", NULL);
9371 mono_mb_patch_branch (mb, pos_was_ok);
9372 mono_mb_patch_branch (mb, pos_was_ok2);
9373 mono_mb_emit_ldarg (mb, 0);
9376 mono_mb_emit_byte (mb, CEE_RET);
9378 res = mono_mb_create_and_cache (cache, klass, mb, castclass_sig, castclass_sig->param_count + 16);
9381 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE);
9382 mono_marshal_set_wrapper_info (res, info);
9388 mono_marshal_get_proxy_cancast (MonoClass *klass)
9390 static MonoMethodSignature *isint_sig = NULL;
9393 int pos_failed, pos_end;
9394 char *name, *klass_name;
9395 MonoMethod *can_cast_to;
9396 MonoMethodDesc *desc;
9397 MonoMethodBuilder *mb;
9399 cache = get_cache (&klass->image->proxy_isinst_cache, mono_aligned_addr_hash, NULL);
9400 if ((res = mono_marshal_find_in_cache (cache, klass)))
9404 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
9405 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
9406 isint_sig->ret = &mono_defaults.object_class->byval_arg;
9407 isint_sig->pinvoke = 0;
9410 klass_name = mono_type_full_name (&klass->byval_arg);
9411 name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass_name);
9412 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
9413 g_free (klass_name);
9416 mb->method->save_lmf = 1;
9418 /* get the real proxy from the transparent proxy*/
9419 mono_mb_emit_ldarg (mb, 0);
9420 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
9421 mono_mb_emit_byte (mb, CEE_LDIND_REF);
9423 /* get the reflection type from the type handle */
9424 mono_mb_emit_ptr (mb, &klass->byval_arg);
9425 mono_mb_emit_icall (mb, type_from_handle);
9427 mono_mb_emit_ldarg (mb, 0);
9429 /* make the call to CanCastTo (type, ob) */
9430 desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
9431 can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
9432 g_assert (can_cast_to);
9433 mono_method_desc_free (desc);
9434 mono_mb_emit_op (mb, CEE_CALLVIRT, can_cast_to);
9436 pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
9438 /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
9439 mono_mb_emit_ptr (mb, &klass->byval_arg);
9440 mono_mb_emit_icall (mb, type_from_handle);
9441 mono_mb_emit_ldarg (mb, 0);
9443 mono_mb_emit_icall (mb, mono_upgrade_remote_class_wrapper);
9444 emit_thread_interrupt_checkpoint (mb);
9446 mono_mb_emit_ldarg (mb, 0);
9447 pos_end = mono_mb_emit_branch (mb, CEE_BR);
9451 mono_mb_patch_branch (mb, pos_failed);
9452 mono_mb_emit_byte (mb, CEE_LDNULL);
9456 mono_mb_patch_branch (mb, pos_end);
9457 mono_mb_emit_byte (mb, CEE_RET);
9459 res = mono_mb_create_and_cache (cache, klass, mb, isint_sig, isint_sig->param_count + 16);
9466 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
9469 MonoDomain *domain = ((MonoObject*)tproxy)->vtable->domain;
9470 klass = mono_class_from_mono_type (rtype->type);
9471 mono_upgrade_remote_class (domain, (MonoObject*)tproxy, klass);
9475 * mono_marshal_get_struct_to_ptr:
9478 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
9479 * The wrapper info for the wrapper is a WrapperInfo structure.
9482 mono_marshal_get_struct_to_ptr (MonoClass *klass)
9484 MonoMethodBuilder *mb;
9485 static MonoMethod *stoptr = NULL;
9489 g_assert (klass != NULL);
9491 mono_marshal_load_type_info (klass);
9493 if (klass->marshal_info->str_to_ptr)
9494 return klass->marshal_info->str_to_ptr;
9497 stoptr = mono_class_get_method_from_name (mono_defaults.marshal_class, "StructureToPtr", 3);
9500 mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
9502 if (klass->blittable) {
9503 mono_mb_emit_byte (mb, CEE_LDARG_1);
9504 mono_mb_emit_byte (mb, CEE_LDARG_0);
9505 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9506 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9507 mono_mb_emit_byte (mb, CEE_PREFIX1);
9508 mono_mb_emit_byte (mb, CEE_CPBLK);
9511 /* allocate local 0 (pointer) src_ptr */
9512 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9513 /* allocate local 1 (pointer) dst_ptr */
9514 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9515 /* allocate local 2 (boolean) delete_old */
9516 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
9517 mono_mb_emit_byte (mb, CEE_LDARG_2);
9518 mono_mb_emit_stloc (mb, 2);
9520 /* initialize src_ptr to point to the start of object data */
9521 mono_mb_emit_byte (mb, CEE_LDARG_0);
9522 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9523 mono_mb_emit_stloc (mb, 0);
9525 /* initialize dst_ptr */
9526 mono_mb_emit_byte (mb, CEE_LDARG_1);
9527 mono_mb_emit_stloc (mb, 1);
9529 emit_struct_conv (mb, klass, FALSE);
9532 mono_mb_emit_byte (mb, CEE_RET);
9534 res = mono_mb_create_method (mb, mono_signature_no_pinvoke (stoptr), 0);
9537 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR);
9538 mono_marshal_set_wrapper_info (res, info);
9540 klass->marshal_info->str_to_ptr = res;
9545 * mono_marshal_get_ptr_to_struct:
9548 * generates IL code for PtrToStructure (IntPtr src, object structure)
9549 * The wrapper info for the wrapper is a WrapperInfo structure.
9552 mono_marshal_get_ptr_to_struct (MonoClass *klass)
9554 MonoMethodBuilder *mb;
9555 static MonoMethodSignature *ptostr = NULL;
9559 g_assert (klass != NULL);
9561 mono_marshal_load_type_info (klass);
9563 if (klass->marshal_info->ptr_to_str)
9564 return klass->marshal_info->ptr_to_str;
9567 MonoMethodSignature *sig;
9569 /* Create the signature corresponding to
9570 static void PtrToStructure (IntPtr ptr, object structure);
9571 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9572 sig = mono_create_icall_signature ("void ptr object");
9573 sig = signature_dup (mono_defaults.corlib, sig);
9575 mono_memory_barrier ();
9579 mb = mono_mb_new (klass, "PtrToStructure", MONO_WRAPPER_UNKNOWN);
9581 if (klass->blittable) {
9582 mono_mb_emit_byte (mb, CEE_LDARG_1);
9583 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9584 mono_mb_emit_byte (mb, CEE_LDARG_0);
9585 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9586 mono_mb_emit_byte (mb, CEE_PREFIX1);
9587 mono_mb_emit_byte (mb, CEE_CPBLK);
9590 /* allocate local 0 (pointer) src_ptr */
9591 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9592 /* allocate local 1 (pointer) dst_ptr */
9593 mono_mb_add_local (mb, &klass->this_arg);
9595 /* initialize src_ptr to point to the start of object data */
9596 mono_mb_emit_byte (mb, CEE_LDARG_0);
9597 mono_mb_emit_stloc (mb, 0);
9599 /* initialize dst_ptr */
9600 mono_mb_emit_byte (mb, CEE_LDARG_1);
9601 mono_mb_emit_op (mb, CEE_UNBOX, klass);
9602 mono_mb_emit_stloc (mb, 1);
9604 emit_struct_conv (mb, klass, TRUE);
9607 mono_mb_emit_byte (mb, CEE_RET);
9609 res = mono_mb_create_method (mb, ptostr, 0);
9612 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE);
9613 mono_marshal_set_wrapper_info (res, info);
9615 klass->marshal_info->ptr_to_str = res;
9620 * generates IL code for the synchronized wrapper: the generated method
9621 * calls METHOD while locking 'this' or the parent type.
9624 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
9626 static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method;
9627 MonoMethodSignature *sig;
9628 MonoExceptionClause *clause;
9629 MonoMethodBuilder *mb;
9632 int i, pos, this_local, ret_local = 0;
9636 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
9639 cache = get_cache (&method->klass->image->synchronized_cache, mono_aligned_addr_hash, NULL);
9640 if ((res = mono_marshal_find_in_cache (cache, method)))
9643 sig = signature_dup (method->klass->image, mono_method_signature (method));
9646 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
9649 if (!MONO_TYPE_IS_VOID (sig->ret))
9650 ret_local = mono_mb_add_local (mb, sig->ret);
9652 if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
9653 mono_class_set_failure (method->klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
9654 /* This will throw the type load exception when the wrapper is compiled */
9655 mono_mb_emit_byte (mb, CEE_LDNULL);
9656 mono_mb_emit_op (mb, CEE_ISINST, method->klass);
9657 mono_mb_emit_byte (mb, CEE_POP);
9659 if (!MONO_TYPE_IS_VOID (sig->ret))
9660 mono_mb_emit_ldloc (mb, ret_local);
9661 mono_mb_emit_byte (mb, CEE_RET);
9663 res = mono_mb_create_and_cache (cache, method,
9664 mb, sig, sig->param_count + 16);
9671 this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
9673 clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
9674 clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
9676 mono_loader_lock ();
9678 if (!enter_method) {
9679 MonoMethodDesc *desc;
9681 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
9682 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9683 g_assert (enter_method);
9684 mono_method_desc_free (desc);
9686 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
9687 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9688 g_assert (exit_method);
9689 mono_method_desc_free (desc);
9691 desc = mono_method_desc_new ("Type:GetTypeFromHandle", FALSE);
9692 gettypefromhandle_method = mono_method_desc_search_in_class (desc, mono_defaults.monotype_class->parent);
9693 g_assert (gettypefromhandle_method);
9694 mono_method_desc_free (desc);
9697 mono_loader_unlock ();
9699 /* Push this or the type object */
9700 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
9701 /* We have special handling for this in the JIT */
9702 int index = mono_mb_add_data (mb, method->klass);
9703 mono_mb_add_data (mb, mono_defaults.typehandle_class);
9704 mono_mb_emit_byte (mb, CEE_LDTOKEN);
9705 mono_mb_emit_i4 (mb, index);
9707 mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL);
9710 mono_mb_emit_ldarg (mb, 0);
9711 mono_mb_emit_stloc (mb, this_local);
9713 /* Call Monitor::Enter() */
9714 mono_mb_emit_ldloc (mb, this_local);
9715 mono_mb_emit_managed_call (mb, enter_method, NULL);
9717 clause->try_offset = mono_mb_get_label (mb);
9719 /* Call the method */
9721 mono_mb_emit_ldarg (mb, 0);
9722 for (i = 0; i < sig->param_count; i++)
9723 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
9725 mono_mb_emit_managed_call (mb, method, NULL);
9727 if (!MONO_TYPE_IS_VOID (sig->ret))
9728 mono_mb_emit_stloc (mb, ret_local);
9730 pos = mono_mb_emit_branch (mb, CEE_LEAVE);
9732 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
9733 clause->handler_offset = mono_mb_get_label (mb);
9735 /* Call Monitor::Exit() */
9736 mono_mb_emit_ldloc (mb, this_local);
9737 mono_mb_emit_managed_call (mb, exit_method, NULL);
9738 mono_mb_emit_byte (mb, CEE_ENDFINALLY);
9740 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
9742 mono_mb_patch_branch (mb, pos);
9743 if (!MONO_TYPE_IS_VOID (sig->ret))
9744 mono_mb_emit_ldloc (mb, ret_local);
9745 mono_mb_emit_byte (mb, CEE_RET);
9747 mono_mb_set_clauses (mb, 1, clause);
9749 res = mono_mb_create_and_cache (cache, method,
9750 mb, sig, sig->param_count + 16);
9758 * the returned method calls 'method' unboxing the this argument
9761 mono_marshal_get_unbox_wrapper (MonoMethod *method)
9763 MonoMethodSignature *sig = mono_method_signature (method);
9765 MonoMethodBuilder *mb;
9769 cache = get_cache (&method->klass->image->unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
9770 if ((res = mono_marshal_find_in_cache (cache, method)))
9773 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNBOX);
9775 g_assert (sig->hasthis);
9777 mono_mb_emit_ldarg (mb, 0);
9778 mono_mb_emit_icon (mb, sizeof (MonoObject));
9779 mono_mb_emit_byte (mb, CEE_ADD);
9780 for (i = 0; i < sig->param_count; ++i)
9781 mono_mb_emit_ldarg (mb, i + 1);
9782 mono_mb_emit_managed_call (mb, method, NULL);
9783 mono_mb_emit_byte (mb, CEE_RET);
9785 res = mono_mb_create_and_cache (cache, method,
9786 mb, sig, sig->param_count + 16);
9789 /* code_for (res); */
9795 STELEMREF_OBJECT, /*no check at all*/
9796 STELEMREF_SEALED_CLASS, /*check vtable->klass->element_type */
9797 STELEMREF_CLASS, /*only the klass->parents check*/
9798 STELEMREF_INTERFACE, /*interfaces without variant generic arguments. */
9799 STELEMREF_COMPLEX, /*arrays, MBR or types with variant generic args - go straight to icalls*/
9800 STELEMREF_KIND_COUNT
9803 static const char *strelemref_wrapper_name[] = {
9804 "object", "sealed_class", "class", "interface", "complex"
9808 is_monomorphic_array (MonoClass *klass)
9810 MonoClass *element_class;
9811 if (klass->rank != 1)
9814 element_class = klass->element_class;
9815 return (element_class->flags & TYPE_ATTRIBUTE_SEALED) || element_class->valuetype;
9819 get_virtual_stelemref_kind (MonoClass *element_class)
9821 if (element_class == mono_defaults.object_class)
9822 return STELEMREF_OBJECT;
9823 if (is_monomorphic_array (element_class))
9824 return STELEMREF_SEALED_CLASS;
9825 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
9826 if (MONO_CLASS_IS_INTERFACE (element_class) && !mono_class_has_variant_generic_params (element_class))
9827 #ifdef COMPRESSED_INTERFACE_BITMAP
9828 return STELEMREF_COMPLEX;
9830 return STELEMREF_INTERFACE;
9832 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
9833 if (element_class->marshalbyref || element_class->rank || mono_class_has_variant_generic_params (element_class))
9834 return STELEMREF_COMPLEX;
9835 if (element_class->flags & TYPE_ATTRIBUTE_SEALED)
9836 return STELEMREF_SEALED_CLASS;
9837 return STELEMREF_CLASS;
9841 load_array_element_address (MonoMethodBuilder *mb)
9843 mono_mb_emit_ldarg (mb, 0);
9844 mono_mb_emit_ldarg (mb, 1);
9845 mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
9849 load_array_class (MonoMethodBuilder *mb, int aklass)
9851 mono_mb_emit_ldarg (mb, 0);
9852 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
9853 mono_mb_emit_byte (mb, CEE_LDIND_I);
9854 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
9855 mono_mb_emit_byte (mb, CEE_LDIND_I);
9856 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
9857 mono_mb_emit_byte (mb, CEE_LDIND_I);
9858 mono_mb_emit_stloc (mb, aklass);
9862 load_value_class (MonoMethodBuilder *mb, int vklass)
9864 mono_mb_emit_ldarg (mb, 2);
9865 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
9866 mono_mb_emit_byte (mb, CEE_LDIND_I);
9867 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
9868 mono_mb_emit_byte (mb, CEE_LDIND_I);
9869 mono_mb_emit_stloc (mb, vklass);
9874 record_slot_vstore (MonoObject *array, size_t index, MonoObject *value)
9876 char *name = mono_type_get_full_name (array->vtable->klass->element_class);
9877 printf ("slow vstore of %s\n", name);
9883 * The wrapper info for the wrapper is a WrapperInfo structure.
9886 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
9887 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
9888 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
9889 * - Add a case for arrays of arrays.
9892 mono_marshal_get_virtual_stelemref (MonoClass *array_class)
9894 static MonoMethod *cached_methods [STELEMREF_KIND_COUNT] = { NULL }; /*object iface sealed regular*/
9895 static MonoMethodSignature *signature;
9896 MonoMethodBuilder *mb;
9900 const char *param_names [16];
9902 int aklass, vklass, vtable, uiid;
9903 int array_slot_addr;
9906 g_assert (array_class->rank == 1);
9907 kind = get_virtual_stelemref_kind (array_class->element_class);
9909 if (cached_methods [kind])
9910 return cached_methods [kind];
9912 name = g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name [kind]);
9913 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STELEMREF);
9916 param_names [0] = "index";
9917 param_names [1] = "value";
9918 mono_mb_set_param_names (mb, param_names);
9921 MonoMethodSignature *sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
9923 /* void this::stelemref (size_t idx, void* value) */
9924 sig->ret = &mono_defaults.void_class->byval_arg;
9925 sig->hasthis = TRUE;
9926 sig->params [0] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
9927 sig->params [1] = &mono_defaults.object_class->byval_arg;
9931 /*For now simply call plain old stelemref*/
9933 case STELEMREF_OBJECT:
9934 /* ldelema (implicit bound check) */
9935 load_array_element_address (mb);
9937 mono_mb_emit_ldarg (mb, 2);
9938 mono_mb_emit_byte (mb, CEE_STIND_REF);
9939 mono_mb_emit_byte (mb, CEE_RET);
9942 case STELEMREF_COMPLEX:
9944 <ldelema (bound check)>
9947 if (!mono_object_isinst (value, aklass))
9951 *array_slot_addr = value;
9954 throw new ArrayTypeMismatchException ();
9957 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9958 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
9962 /*Use this to debug/record stores that are going thru the slow path*/
9963 MonoMethodSignature *csig;
9964 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9965 csig->ret = &mono_defaults.void_class->byval_arg;
9966 csig->params [0] = &mono_defaults.object_class->byval_arg;
9967 csig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
9968 csig->params [2] = &mono_defaults.object_class->byval_arg;
9969 mono_mb_emit_ldarg (mb, 0);
9970 mono_mb_emit_ldarg (mb, 1);
9971 mono_mb_emit_ldarg (mb, 2);
9972 mono_mb_emit_native_call (mb, csig, record_slot_vstore);
9976 /* ldelema (implicit bound check) */
9977 load_array_element_address (mb);
9978 mono_mb_emit_stloc (mb, array_slot_addr);
9980 /* if (!value) goto do_store */
9981 mono_mb_emit_ldarg (mb, 2);
9982 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
9984 /* aklass = array->vtable->klass->element_class */
9985 load_array_class (mb, aklass);
9987 /*if (mono_object_isinst (value, aklass)) */
9988 mono_mb_emit_ldarg (mb, 2);
9989 mono_mb_emit_ldloc (mb, aklass);
9990 mono_mb_emit_icall (mb, mono_object_isinst);
9991 b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
9994 mono_mb_patch_branch (mb, b1);
9995 mono_mb_emit_ldloc (mb, array_slot_addr);
9996 mono_mb_emit_ldarg (mb, 2);
9997 mono_mb_emit_byte (mb, CEE_STIND_REF);
9998 mono_mb_emit_byte (mb, CEE_RET);
10000 /* do_exception: */
10001 mono_mb_patch_branch (mb, b2);
10003 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10006 case STELEMREF_SEALED_CLASS:
10008 <ldelema (bound check)>
10012 aklass = array->vtable->klass->element_class;
10013 vklass = value->vtable->klass;
10015 if (vklass != aklass)
10019 *array_slot_addr = value;
10022 throw new ArrayTypeMismatchException ();
10024 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10025 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10026 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10029 /* ldelema (implicit bound check) */
10030 load_array_element_address (mb);
10031 mono_mb_emit_stloc (mb, array_slot_addr);
10033 /* if (!value) goto do_store */
10034 mono_mb_emit_ldarg (mb, 2);
10035 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10037 /* aklass = array->vtable->klass->element_class */
10038 load_array_class (mb, aklass);
10040 /* vklass = value->vtable->klass */
10041 load_value_class (mb, vklass);
10043 /*if (vklass != aklass) goto do_exception; */
10044 mono_mb_emit_ldloc (mb, aklass);
10045 mono_mb_emit_ldloc (mb, vklass);
10046 b2 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10049 mono_mb_patch_branch (mb, b1);
10050 mono_mb_emit_ldloc (mb, array_slot_addr);
10051 mono_mb_emit_ldarg (mb, 2);
10052 mono_mb_emit_byte (mb, CEE_STIND_REF);
10053 mono_mb_emit_byte (mb, CEE_RET);
10055 /* do_exception: */
10056 mono_mb_patch_branch (mb, b2);
10057 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10060 case STELEMREF_CLASS:
10063 <ldelema (bound check)>
10067 aklass = array->vtable->klass->element_class;
10068 vklass = value->vtable->klass;
10070 if (vklass->idepth < aklass->idepth)
10073 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10077 *array_slot_addr = value;
10081 throw new ArrayTypeMismatchException ();
10083 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10084 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10085 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10087 /* ldelema (implicit bound check) */
10088 load_array_element_address (mb);
10089 mono_mb_emit_stloc (mb, array_slot_addr);
10091 /* if (!value) goto do_store */
10092 mono_mb_emit_ldarg (mb, 2);
10093 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10095 /* aklass = array->vtable->klass->element_class */
10096 load_array_class (mb, aklass);
10098 /* vklass = value->vtable->klass */
10099 load_value_class (mb, vklass);
10101 /*if (mono_object_isinst (value, aklass)) */
10102 mono_mb_emit_ldarg (mb, 2);
10103 mono_mb_emit_ldloc (mb, aklass);
10104 mono_mb_emit_icall (mb, mono_object_isinst);
10105 b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10107 /* if (vklass->idepth < aklass->idepth) goto failue */
10108 mono_mb_emit_ldloc (mb, vklass);
10109 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10110 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10112 mono_mb_emit_ldloc (mb, aklass);
10113 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10114 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10116 b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
10118 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10119 mono_mb_emit_ldloc (mb, vklass);
10120 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
10121 mono_mb_emit_byte (mb, CEE_LDIND_I);
10123 mono_mb_emit_ldloc (mb, aklass);
10124 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10125 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10126 mono_mb_emit_icon (mb, 1);
10127 mono_mb_emit_byte (mb, CEE_SUB);
10128 mono_mb_emit_icon (mb, sizeof (void*));
10129 mono_mb_emit_byte (mb, CEE_MUL);
10130 mono_mb_emit_byte (mb, CEE_ADD);
10131 mono_mb_emit_byte (mb, CEE_LDIND_I);
10133 mono_mb_emit_ldloc (mb, aklass);
10134 b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10137 mono_mb_patch_branch (mb, b1);
10138 mono_mb_emit_ldloc (mb, array_slot_addr);
10139 mono_mb_emit_ldarg (mb, 2);
10140 mono_mb_emit_byte (mb, CEE_STIND_REF);
10141 mono_mb_emit_byte (mb, CEE_RET);
10143 /* do_exception: */
10144 mono_mb_patch_branch (mb, b2);
10145 mono_mb_patch_branch (mb, b3);
10147 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10150 case STELEMREF_INTERFACE:
10157 klass = array->obj.vtable->klass->element_class;
10158 vt = value->vtable;
10159 uiid = klass->interface_id;
10160 if (uiid > vt->max_interface_id)
10162 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
10165 mono_array_setref (array, index, value);
10168 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
10170 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10171 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10172 vtable = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10173 uiid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10175 /* ldelema (implicit bound check) */
10176 load_array_element_address (mb);
10177 mono_mb_emit_stloc (mb, array_slot_addr);
10179 /* if (!value) goto do_store */
10180 mono_mb_emit_ldarg (mb, 2);
10181 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10183 /* klass = array->vtable->klass->element_class */
10184 load_array_class (mb, aklass);
10186 /* vt = value->vtable */
10187 mono_mb_emit_ldarg (mb, 2);
10188 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
10189 mono_mb_emit_byte (mb, CEE_LDIND_I);
10190 mono_mb_emit_stloc (mb, vtable);
10192 /* uiid = klass->interface_id; */
10193 mono_mb_emit_ldloc (mb, aklass);
10194 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, interface_id));
10195 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10196 mono_mb_emit_stloc (mb, uiid);
10198 /*if (uiid > vt->max_interface_id)*/
10199 mono_mb_emit_ldloc (mb, uiid);
10200 mono_mb_emit_ldloc (mb, vtable);
10201 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
10202 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10203 b2 = mono_mb_emit_branch (mb, CEE_BGT_UN);
10205 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
10207 /*vt->interface_bitmap*/
10208 mono_mb_emit_ldloc (mb, vtable);
10209 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, interface_bitmap));
10210 mono_mb_emit_byte (mb, CEE_LDIND_I);
10213 mono_mb_emit_ldloc (mb, uiid);
10214 mono_mb_emit_icon (mb, 3);
10215 mono_mb_emit_byte (mb, CEE_SHR_UN);
10217 /*vt->interface_bitmap [(uiid) >> 3]*/
10218 mono_mb_emit_byte (mb, CEE_ADD); /*interface_bitmap is a guint8 array*/
10219 mono_mb_emit_byte (mb, CEE_LDIND_U1);
10221 /*(1 << ((uiid)&7)))*/
10222 mono_mb_emit_icon (mb, 1);
10223 mono_mb_emit_ldloc (mb, uiid);
10224 mono_mb_emit_icon (mb, 7);
10225 mono_mb_emit_byte (mb, CEE_AND);
10226 mono_mb_emit_byte (mb, CEE_SHL);
10228 /*bitwise and the whole thing*/
10229 mono_mb_emit_byte (mb, CEE_AND);
10230 b3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10233 mono_mb_patch_branch (mb, b1);
10234 mono_mb_emit_ldloc (mb, array_slot_addr);
10235 mono_mb_emit_ldarg (mb, 2);
10236 mono_mb_emit_byte (mb, CEE_STIND_REF);
10237 mono_mb_emit_byte (mb, CEE_RET);
10239 /* do_exception: */
10240 mono_mb_patch_branch (mb, b2);
10241 mono_mb_patch_branch (mb, b3);
10242 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10246 mono_mb_emit_ldarg (mb, 0);
10247 mono_mb_emit_ldarg (mb, 1);
10248 mono_mb_emit_ldarg (mb, 2);
10249 mono_mb_emit_managed_call (mb, mono_marshal_get_stelemref (), NULL);
10250 mono_mb_emit_byte (mb, CEE_RET);
10254 res = mono_mb_create_method (mb, signature, 4);
10255 res->flags |= METHOD_ATTRIBUTE_VIRTUAL;
10257 info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF);
10258 info->d.virtual_stelemref.kind = kind;
10259 mono_marshal_set_wrapper_info (res, info);
10261 mono_marshal_lock ();
10262 if (!cached_methods [kind]) {
10263 cached_methods [kind] = res;
10264 mono_marshal_unlock ();
10266 mono_marshal_unlock ();
10267 mono_free_method (res);
10271 return cached_methods [kind];
10275 * The wrapper info for the wrapper is a WrapperInfo structure.
10278 mono_marshal_get_stelemref ()
10280 static MonoMethod* ret = NULL;
10281 MonoMethodSignature *sig;
10282 MonoMethodBuilder *mb;
10285 guint32 b1, b2, b3, b4;
10287 int aklass, vklass;
10288 int array_slot_addr;
10293 mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
10296 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
10298 /* void stelemref (void* array, int idx, void* value) */
10299 sig->ret = &mono_defaults.void_class->byval_arg;
10300 sig->params [0] = &mono_defaults.object_class->byval_arg;
10301 sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
10302 sig->params [2] = &mono_defaults.object_class->byval_arg;
10304 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10305 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10306 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10310 <ldelema (bound check)>
10314 aklass = array->vtable->klass->element_class;
10315 vklass = value->vtable->klass;
10317 if (vklass->idepth < aklass->idepth)
10320 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10324 *array_slot_addr = value;
10328 if (mono_object_isinst (value, aklass))
10331 throw new ArrayTypeMismatchException ();
10334 /* ldelema (implicit bound check) */
10335 mono_mb_emit_ldarg (mb, 0);
10336 mono_mb_emit_ldarg (mb, 1);
10337 mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
10338 mono_mb_emit_stloc (mb, array_slot_addr);
10340 /* if (!value) goto do_store */
10341 mono_mb_emit_ldarg (mb, 2);
10342 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10344 /* aklass = array->vtable->klass->element_class */
10345 mono_mb_emit_ldarg (mb, 0);
10346 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
10347 mono_mb_emit_byte (mb, CEE_LDIND_I);
10348 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
10349 mono_mb_emit_byte (mb, CEE_LDIND_I);
10350 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
10351 mono_mb_emit_byte (mb, CEE_LDIND_I);
10352 mono_mb_emit_stloc (mb, aklass);
10354 /* vklass = value->vtable->klass */
10355 mono_mb_emit_ldarg (mb, 2);
10356 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
10357 mono_mb_emit_byte (mb, CEE_LDIND_I);
10358 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
10359 mono_mb_emit_byte (mb, CEE_LDIND_I);
10360 mono_mb_emit_stloc (mb, vklass);
10362 /* if (vklass->idepth < aklass->idepth) goto failue */
10363 mono_mb_emit_ldloc (mb, vklass);
10364 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10365 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10367 mono_mb_emit_ldloc (mb, aklass);
10368 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10369 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10371 b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
10373 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10374 mono_mb_emit_ldloc (mb, vklass);
10375 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
10376 mono_mb_emit_byte (mb, CEE_LDIND_I);
10378 mono_mb_emit_ldloc (mb, aklass);
10379 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10380 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10381 mono_mb_emit_icon (mb, 1);
10382 mono_mb_emit_byte (mb, CEE_SUB);
10383 mono_mb_emit_icon (mb, sizeof (void*));
10384 mono_mb_emit_byte (mb, CEE_MUL);
10385 mono_mb_emit_byte (mb, CEE_ADD);
10386 mono_mb_emit_byte (mb, CEE_LDIND_I);
10388 mono_mb_emit_ldloc (mb, aklass);
10390 b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10392 copy_pos = mono_mb_get_label (mb);
10394 mono_mb_patch_branch (mb, b1);
10395 mono_mb_emit_ldloc (mb, array_slot_addr);
10396 mono_mb_emit_ldarg (mb, 2);
10397 mono_mb_emit_byte (mb, CEE_STIND_REF);
10399 mono_mb_emit_byte (mb, CEE_RET);
10402 mono_mb_patch_branch (mb, b2);
10403 mono_mb_patch_branch (mb, b3);
10405 mono_mb_emit_ldarg (mb, 2);
10406 mono_mb_emit_ldloc (mb, aklass);
10407 mono_mb_emit_icall (mb, mono_object_isinst);
10409 b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
10410 mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
10411 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10413 mono_mb_emit_byte (mb, CEE_RET);
10414 ret = mono_mb_create_method (mb, sig, 4);
10417 info = mono_wrapper_info_create (ret, WRAPPER_SUBTYPE_NONE);
10418 mono_marshal_set_wrapper_info (ret, info);
10426 MonoMethod *method;
10429 /* LOCKING: vars accessed under the marshal lock */
10430 static ArrayElemAddr *elem_addr_cache = NULL;
10431 static int elem_addr_cache_size = 0;
10432 static int elem_addr_cache_next = 0;
10435 * mono_marshal_get_array_address:
10436 * @rank: rank of the array type
10437 * @elem_size: size in bytes of an element of an array.
10439 * Returns a MonoMethd that implements the code to get the address
10440 * of an element in a multi-dimenasional array of @rank dimensions.
10441 * The returned method takes an array as the first argument and then
10442 * @rank indexes for the @rank dimensions.
10445 mono_marshal_get_array_address (int rank, int elem_size)
10448 MonoMethodBuilder *mb;
10449 MonoMethodSignature *sig;
10450 int i, bounds, ind, realidx;
10451 int branch_pos, *branch_positions;
10455 mono_marshal_lock ();
10456 for (i = 0; i < elem_addr_cache_next; ++i) {
10457 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
10458 ret = elem_addr_cache [i].method;
10462 mono_marshal_unlock ();
10466 branch_positions = g_new0 (int, rank);
10468 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank);
10470 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
10471 sig->ret = &mono_defaults.int_class->byval_arg;
10472 sig->params [0] = &mono_defaults.object_class->byval_arg;
10473 for (i = 0; i < rank; ++i) {
10474 sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
10477 mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED);
10479 bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10480 ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10481 realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10483 /* bounds = array->bounds; */
10484 mono_mb_emit_ldarg (mb, 0);
10485 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, bounds));
10486 mono_mb_emit_byte (mb, CEE_LDIND_I);
10487 mono_mb_emit_stloc (mb, bounds);
10489 /* ind is the overall element index, realidx is the partial index in a single dimension */
10490 /* ind = idx0 - bounds [0].lower_bound */
10491 mono_mb_emit_ldarg (mb, 1);
10492 mono_mb_emit_ldloc (mb, bounds);
10493 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
10494 mono_mb_emit_byte (mb, CEE_ADD);
10495 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10496 mono_mb_emit_byte (mb, CEE_SUB);
10497 mono_mb_emit_stloc (mb, ind);
10498 /* if (ind >= bounds [0].length) goto exeception; */
10499 mono_mb_emit_ldloc (mb, ind);
10500 mono_mb_emit_ldloc (mb, bounds);
10501 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, length));
10502 mono_mb_emit_byte (mb, CEE_ADD);
10503 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10504 /* note that we use unsigned comparison */
10505 branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
10507 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
10508 * We could also decide to ignore the passed elem_size and get it
10509 * from the array object, to reduce the number of methods we generate:
10510 * the additional cost is 3 memory loads and a non-immediate mul.
10512 for (i = 1; i < rank; ++i) {
10513 /* realidx = idxi - bounds [i].lower_bound */
10514 mono_mb_emit_ldarg (mb, 1 + i);
10515 mono_mb_emit_ldloc (mb, bounds);
10516 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
10517 mono_mb_emit_byte (mb, CEE_ADD);
10518 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10519 mono_mb_emit_byte (mb, CEE_SUB);
10520 mono_mb_emit_stloc (mb, realidx);
10521 /* if (realidx >= bounds [i].length) goto exeception; */
10522 mono_mb_emit_ldloc (mb, realidx);
10523 mono_mb_emit_ldloc (mb, bounds);
10524 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
10525 mono_mb_emit_byte (mb, CEE_ADD);
10526 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10527 branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
10528 /* ind = ind * bounds [i].length + realidx */
10529 mono_mb_emit_ldloc (mb, ind);
10530 mono_mb_emit_ldloc (mb, bounds);
10531 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
10532 mono_mb_emit_byte (mb, CEE_ADD);
10533 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10534 mono_mb_emit_byte (mb, CEE_MUL);
10535 mono_mb_emit_ldloc (mb, realidx);
10536 mono_mb_emit_byte (mb, CEE_ADD);
10537 mono_mb_emit_stloc (mb, ind);
10540 /* return array->vector + ind * element_size */
10541 mono_mb_emit_ldarg (mb, 0);
10542 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
10543 mono_mb_emit_ldloc (mb, ind);
10544 mono_mb_emit_icon (mb, elem_size);
10545 mono_mb_emit_byte (mb, CEE_MUL);
10546 mono_mb_emit_byte (mb, CEE_ADD);
10547 mono_mb_emit_byte (mb, CEE_RET);
10549 /* patch the branches to get here and throw */
10550 for (i = 1; i < rank; ++i) {
10551 mono_mb_patch_branch (mb, branch_positions [i]);
10553 mono_mb_patch_branch (mb, branch_pos);
10554 /* throw exception */
10555 mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
10557 g_free (branch_positions);
10558 ret = mono_mb_create_method (mb, sig, 4);
10561 /* cache the result */
10563 mono_marshal_lock ();
10564 for (i = 0; i < elem_addr_cache_next; ++i) {
10565 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
10566 /* FIXME: free ret */
10567 ret = elem_addr_cache [i].method;
10575 if (elem_addr_cache_next >= elem_addr_cache_size) {
10576 int new_size = elem_addr_cache_size + 4;
10577 ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size);
10578 memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr));
10579 g_free (elem_addr_cache);
10580 elem_addr_cache = new_array;
10581 elem_addr_cache_size = new_size;
10583 elem_addr_cache [elem_addr_cache_next].rank = rank;
10584 elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
10585 elem_addr_cache [elem_addr_cache_next].method = ret;
10586 elem_addr_cache_next ++;
10588 info = mono_wrapper_info_create (ret, WRAPPER_SUBTYPE_ELEMENT_ADDR);
10589 info->d.element_addr.rank = rank;
10590 info->d.element_addr.elem_size = elem_size;
10591 mono_marshal_set_wrapper_info (ret, info);
10593 mono_marshal_unlock ();
10598 mono_marshal_alloc (gulong size)
10603 res = CoTaskMemAlloc (size);
10605 res = g_try_malloc ((gulong)size);
10607 mono_gc_out_of_memory ((gulong)size);
10613 mono_marshal_free (gpointer ptr)
10616 CoTaskMemFree (ptr);
10623 mono_marshal_free_array (gpointer *ptr, int size)
10630 for (i = 0; i < size; i++)
10636 mono_marshal_string_to_utf16 (MonoString *s)
10638 return s ? mono_string_chars (s) : NULL;
10642 mono_marshal_string_to_utf16_copy (MonoString *s)
10647 gunichar2 *res = mono_marshal_alloc ((mono_string_length (s) * 2) + 2);
10648 memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
10649 res [mono_string_length (s)] = 0;
10655 * mono_marshal_set_last_error:
10657 * This function is invoked to set the last error value from a P/Invoke call
10658 * which has SetLastError set.
10661 mono_marshal_set_last_error (void)
10664 mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
10666 mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (errno));
10671 mono_marshal_set_last_error_windows (int error)
10674 mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (error));
10679 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
10680 gpointer dest, gint32 length)
10685 MONO_ARCH_SAVE_REGS;
10687 MONO_CHECK_ARG_NULL (src);
10688 MONO_CHECK_ARG_NULL (dest);
10690 if (src->obj.vtable->klass->rank != 1)
10691 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10692 if (start_index < 0)
10693 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10695 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10696 if (start_index + length > mono_array_length (src))
10697 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10699 element_size = mono_array_element_size (src->obj.vtable->klass);
10701 /* no references should be involved */
10702 source_addr = mono_array_addr_with_size (src, element_size, start_index);
10704 memcpy (dest, source_addr, length * element_size);
10708 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
10709 MonoArray *dest, gint32 length)
10714 MONO_ARCH_SAVE_REGS;
10716 MONO_CHECK_ARG_NULL (src);
10717 MONO_CHECK_ARG_NULL (dest);
10719 if (dest->obj.vtable->klass->rank != 1)
10720 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10721 if (start_index < 0)
10722 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10724 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10725 if (start_index + length > mono_array_length (dest))
10726 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10728 element_size = mono_array_element_size (dest->obj.vtable->klass);
10730 /* no references should be involved */
10731 dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
10733 memcpy (dest_addr, src, length * element_size);
10736 #if NO_UNALIGNED_ACCESS
10737 #define RETURN_UNALIGNED(type, addr) \
10740 memcpy(&val, p + offset, sizeof(val)); \
10743 #define WRITE_UNALIGNED(type, addr, val) \
10744 memcpy(addr, &val, sizeof(type))
10746 #define RETURN_UNALIGNED(type, addr) \
10747 return *(type*)(p + offset);
10748 #define WRITE_UNALIGNED(type, addr, val) \
10749 (*(type *)(addr) = (val))
10753 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
10757 MONO_ARCH_SAVE_REGS;
10759 RETURN_UNALIGNED(gpointer, p + offset);
10763 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
10767 MONO_ARCH_SAVE_REGS;
10769 return *(unsigned char*)(p + offset);
10773 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
10777 MONO_ARCH_SAVE_REGS;
10779 RETURN_UNALIGNED(gint16, p + offset);
10783 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
10787 MONO_ARCH_SAVE_REGS;
10789 RETURN_UNALIGNED(gint32, p + offset);
10793 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
10797 MONO_ARCH_SAVE_REGS;
10799 RETURN_UNALIGNED(gint64, p + offset);
10803 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
10807 MONO_ARCH_SAVE_REGS;
10809 *(unsigned char*)(p + offset) = val;
10813 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
10817 MONO_ARCH_SAVE_REGS;
10819 WRITE_UNALIGNED(gpointer, p + offset, val);
10823 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
10827 MONO_ARCH_SAVE_REGS;
10829 WRITE_UNALIGNED(gint16, p + offset, val);
10833 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
10837 MONO_ARCH_SAVE_REGS;
10839 WRITE_UNALIGNED(gint32, p + offset, val);
10843 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
10847 MONO_ARCH_SAVE_REGS;
10849 WRITE_UNALIGNED(gint64, p + offset, val);
10853 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
10855 MONO_ARCH_SAVE_REGS;
10860 return mono_string_new (mono_domain_get (), ptr);
10864 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
10866 MONO_ARCH_SAVE_REGS;
10869 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10870 g_assert_not_reached ();
10873 return mono_string_new_len (mono_domain_get (), ptr, len);
10878 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
10880 MonoDomain *domain = mono_domain_get ();
10884 MONO_ARCH_SAVE_REGS;
10892 return mono_string_new_utf16 (domain, ptr, len);
10896 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
10898 MonoDomain *domain = mono_domain_get ();
10900 MONO_ARCH_SAVE_REGS;
10903 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10904 g_assert_not_reached ();
10907 return mono_string_new_utf16 (domain, ptr, len);
10912 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10914 MONO_ARCH_SAVE_REGS;
10916 return (GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id)));
10920 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
10926 MONO_ARCH_SAVE_REGS;
10928 MONO_CHECK_ARG_NULL (rtype);
10930 type = rtype->type;
10931 klass = mono_class_from_mono_type (type);
10932 if (!mono_class_init (klass))
10933 mono_raise_exception (mono_class_get_exception_for_failure (klass));
10935 layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
10937 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
10939 MonoException *exc;
10941 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
10942 exc = mono_get_exception_argument ("t", msg);
10944 mono_raise_exception (exc);
10948 return mono_class_native_size (klass, NULL);
10952 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
10954 MonoMethod *method;
10957 MONO_ARCH_SAVE_REGS;
10959 MONO_CHECK_ARG_NULL (obj);
10960 MONO_CHECK_ARG_NULL (dst);
10962 method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
10966 pa [2] = &delete_old;
10968 mono_runtime_invoke (method, NULL, pa, NULL);
10972 ptr_to_structure (gpointer src, MonoObject *dst)
10974 MonoMethod *method;
10977 method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
10982 mono_runtime_invoke (method, NULL, pa, NULL);
10986 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
10990 MONO_ARCH_SAVE_REGS;
10992 MONO_CHECK_ARG_NULL (src);
10993 MONO_CHECK_ARG_NULL (dst);
10995 t = mono_type_get_underlying_type (mono_class_get_type (dst->vtable->klass));
10997 if (t->type == MONO_TYPE_VALUETYPE) {
10998 MonoException *exc;
11001 tmp = g_strdup_printf ("Destination is a boxed value type.");
11002 exc = mono_get_exception_argument ("dst", tmp);
11005 mono_raise_exception (exc);
11009 ptr_to_structure (src, dst);
11013 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
11016 MonoDomain *domain = mono_domain_get ();
11019 MONO_ARCH_SAVE_REGS;
11021 MONO_CHECK_ARG_NULL (src);
11022 MONO_CHECK_ARG_NULL (type);
11024 klass = mono_class_from_mono_type (type->type);
11025 if (!mono_class_init (klass))
11026 mono_raise_exception (mono_class_get_exception_for_failure (klass));
11028 res = mono_object_new (domain, klass);
11030 ptr_to_structure (src, res);
11036 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
11038 MonoMarshalType *info;
11041 int match_index = -1;
11043 MONO_ARCH_SAVE_REGS;
11045 MONO_CHECK_ARG_NULL (type);
11046 MONO_CHECK_ARG_NULL (field_name);
11048 fname = mono_string_to_utf8 (field_name);
11049 klass = mono_class_from_mono_type (type->type);
11050 if (!mono_class_init (klass))
11051 mono_raise_exception (mono_class_get_exception_for_failure (klass));
11053 while (klass && match_index == -1) {
11054 MonoClassField* field;
11056 gpointer iter = NULL;
11057 while ((field = mono_class_get_fields (klass, &iter))) {
11058 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11060 if (!strcmp (fname, mono_field_get_name (field))) {
11067 if (match_index == -1)
11068 klass = klass->parent;
11073 if(match_index == -1) {
11074 MonoException* exc;
11077 /* Get back original class instance */
11078 klass = mono_class_from_mono_type (type->type);
11080 tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
11081 exc = mono_get_exception_argument ("fieldName", tmp);
11084 mono_raise_exception ((MonoException*)exc);
11087 info = mono_marshal_load_type_info (klass);
11088 return info->fields [match_index].offset;
11092 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
11097 tres = mono_string_to_utf8 (string);
11101 len = strlen (tres) + 1;
11102 ret = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len);
11103 memcpy (ret, tres, len);
11108 return mono_string_to_utf8 (string);
11113 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
11115 MONO_ARCH_SAVE_REGS;
11117 if (string == NULL)
11120 #ifdef TARGET_WIN32
11121 gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal
11122 ((mono_string_length (string) + 1) * 2);
11124 gunichar2 *res = g_malloc ((mono_string_length (string) + 1) * 2);
11126 memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
11127 res [mono_string_length (string)] = 0;
11133 mono_struct_delete_old (MonoClass *klass, char *ptr)
11135 MonoMarshalType *info;
11138 info = mono_marshal_load_type_info (klass);
11140 for (i = 0; i < info->num_fields; i++) {
11141 MonoMarshalNative ntype;
11142 MonoMarshalConv conv;
11143 MonoType *ftype = info->fields [i].field->type;
11146 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
11149 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE,
11150 klass->unicode, &conv);
11152 cpos = ptr + info->fields [i].offset;
11155 case MONO_MARSHAL_CONV_NONE:
11156 if (MONO_TYPE_ISSTRUCT (ftype)) {
11157 mono_struct_delete_old (ftype->data.klass, cpos);
11161 case MONO_MARSHAL_CONV_STR_LPWSTR:
11162 /* We assume this field points inside a MonoString */
11164 case MONO_MARSHAL_CONV_STR_LPTSTR:
11165 #ifdef TARGET_WIN32
11166 /* We assume this field points inside a MonoString
11170 case MONO_MARSHAL_CONV_STR_LPSTR:
11171 case MONO_MARSHAL_CONV_STR_BSTR:
11172 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
11173 case MONO_MARSHAL_CONV_STR_TBSTR:
11174 mono_marshal_free (*(gpointer *)cpos);
11184 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
11188 MONO_ARCH_SAVE_REGS;
11190 MONO_CHECK_ARG_NULL (src);
11191 MONO_CHECK_ARG_NULL (type);
11193 klass = mono_class_from_mono_type (type->type);
11194 if (!mono_class_init (klass))
11195 mono_raise_exception (mono_class_get_exception_for_failure (klass));
11197 mono_struct_delete_old (klass, (char *)src);
11201 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
11205 MONO_ARCH_SAVE_REGS;
11207 if ((gulong)size == 0)
11208 /* This returns a valid pointer for size 0 on MS.NET */
11212 res = GlobalAlloc (GMEM_FIXED, (gulong)size);
11214 res = g_try_malloc ((gulong)size);
11217 mono_gc_out_of_memory ((gulong)size);
11223 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, int size)
11228 mono_gc_out_of_memory ((gulong)size);
11233 res = GlobalReAlloc (ptr, (gulong)size, GMEM_MOVEABLE);
11235 res = g_try_realloc (ptr, (gulong)size);
11238 mono_gc_out_of_memory ((gulong)size);
11244 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
11246 MONO_ARCH_SAVE_REGS;
11256 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
11258 MONO_ARCH_SAVE_REGS;
11261 return CoTaskMemAlloc (size);
11263 return g_try_malloc ((gulong)size);
11268 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
11270 MONO_ARCH_SAVE_REGS;
11273 CoTaskMemFree (ptr);
11280 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
11282 MONO_ARCH_SAVE_REGS;
11285 return CoTaskMemRealloc (ptr, size);
11287 return g_try_realloc (ptr, (gulong)size);
11292 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
11294 return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
11298 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type)
11300 MonoClass *klass = mono_type_get_class (type->type);
11301 if (!mono_class_init (klass))
11302 mono_raise_exception (mono_class_get_exception_for_failure (klass));
11304 return mono_ftnptr_to_delegate (klass, ftn);
11308 * mono_marshal_is_loading_type_info:
11310 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
11314 mono_marshal_is_loading_type_info (MonoClass *klass)
11316 GSList *loads_list = mono_native_tls_get_value (load_type_info_tls_id);
11318 return g_slist_find (loads_list, klass) != NULL;
11322 * mono_marshal_load_type_info:
11324 * Initialize klass->marshal_info using information from metadata. This function can
11325 * recursively call itself, and the caller is responsible to avoid that by calling
11326 * mono_marshal_is_loading_type_info () beforehand.
11328 * LOCKING: Acquires the loader lock.
11331 mono_marshal_load_type_info (MonoClass* klass)
11334 guint32 native_size = 0, min_align = 1, packing;
11335 MonoMarshalType *info;
11336 MonoClassField* field;
11339 GSList *loads_list;
11341 g_assert (klass != NULL);
11343 if (klass->marshal_info)
11344 return klass->marshal_info;
11346 if (!klass->inited)
11347 mono_class_init (klass);
11349 mono_loader_lock ();
11351 if (klass->marshal_info) {
11352 mono_loader_unlock ();
11353 return klass->marshal_info;
11357 * This function can recursively call itself, so we keep the list of classes which are
11358 * under initialization in a TLS list.
11360 g_assert (!mono_marshal_is_loading_type_info (klass));
11361 loads_list = mono_native_tls_get_value (load_type_info_tls_id);
11362 loads_list = g_slist_prepend (loads_list, klass);
11363 mono_native_tls_set_value (load_type_info_tls_id, loads_list);
11366 while ((field = mono_class_get_fields (klass, &iter))) {
11367 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11369 if (mono_field_is_deleted (field))
11374 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
11376 /* The mempool is protected by the loader lock */
11377 info = mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
11378 info->num_fields = count;
11380 /* Try to find a size for this type in metadata */
11381 mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
11383 if (klass->parent) {
11384 int parent_size = mono_class_native_size (klass->parent, NULL);
11386 /* Add parent size to real size */
11387 native_size += parent_size;
11388 info->native_size = parent_size;
11391 packing = klass->packing_size ? klass->packing_size : 8;
11394 while ((field = mono_class_get_fields (klass, &iter))) {
11398 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11401 if (mono_field_is_deleted (field))
11403 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
11404 mono_metadata_field_info_with_mempool (klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1,
11405 NULL, NULL, &info->fields [j].mspec);
11407 info->fields [j].field = field;
11409 if ((mono_class_num_fields (klass) == 1) && (klass->instance_size == sizeof (MonoObject)) &&
11410 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
11411 /* This field is a hack inserted by MCS to empty structures */
11416 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
11417 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
11418 size = mono_marshal_type_size (field->type, info->fields [j].mspec,
11419 &align, TRUE, klass->unicode);
11420 align = klass->packing_size ? MIN (klass->packing_size, align): align;
11421 min_align = MAX (align, min_align);
11422 info->fields [j].offset = info->native_size;
11423 info->fields [j].offset += align - 1;
11424 info->fields [j].offset &= ~(align - 1);
11425 info->native_size = info->fields [j].offset + size;
11427 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
11428 size = mono_marshal_type_size (field->type, info->fields [j].mspec,
11429 &align, TRUE, klass->unicode);
11430 min_align = packing;
11431 info->fields [j].offset = field->offset - sizeof (MonoObject);
11432 info->native_size = MAX (info->native_size, info->fields [j].offset + size);
11438 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
11439 info->native_size = MAX (native_size, info->native_size);
11441 * If the provided Size is equal or larger than the calculated size, and there
11442 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
11444 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)
11445 if (native_size && native_size == info->native_size && klass->packing_size == 0)
11449 if (info->native_size & (min_align - 1)) {
11450 info->native_size += min_align - 1;
11451 info->native_size &= ~(min_align - 1);
11454 info->min_align = min_align;
11456 /* Update the class's blittable info, if the layouts don't match */
11457 if (info->native_size != mono_class_value_size (klass, NULL))
11458 klass->blittable = FALSE;
11460 /* If this is an array type, ensure that we have element info */
11461 if (klass->rank && !mono_marshal_is_loading_type_info (klass->element_class)) {
11462 mono_marshal_load_type_info (klass->element_class);
11465 loads_list = mono_native_tls_get_value (load_type_info_tls_id);
11466 loads_list = g_slist_remove (loads_list, klass);
11467 mono_native_tls_set_value (load_type_info_tls_id, loads_list);
11469 /*We do double-checking locking on marshal_info */
11470 mono_memory_barrier ();
11472 klass->marshal_info = info;
11474 mono_loader_unlock ();
11476 return klass->marshal_info;
11480 * mono_class_native_size:
11483 * Returns: the native size of an object instance (when marshaled
11484 * to unmanaged code)
11487 mono_class_native_size (MonoClass *klass, guint32 *align)
11489 if (!klass->marshal_info) {
11490 if (mono_marshal_is_loading_type_info (klass)) {
11495 mono_marshal_load_type_info (klass);
11500 *align = klass->marshal_info->min_align;
11502 return klass->marshal_info->native_size;
11505 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
11506 the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
11507 but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
11508 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
11511 * mono_type_native_stack_size:
11512 * @t: the type to return the size it uses on the stack
11514 * Returns: the number of bytes required to hold an instance of this
11515 * type on the native stack
11518 mono_type_native_stack_size (MonoType *t, guint32 *align)
11522 g_assert (t != NULL);
11528 *align = sizeof (gpointer);
11529 return sizeof (gpointer);
11533 case MONO_TYPE_BOOLEAN:
11534 case MONO_TYPE_CHAR:
11545 case MONO_TYPE_STRING:
11546 case MONO_TYPE_OBJECT:
11547 case MONO_TYPE_CLASS:
11548 case MONO_TYPE_SZARRAY:
11549 case MONO_TYPE_PTR:
11550 case MONO_TYPE_FNPTR:
11551 case MONO_TYPE_ARRAY:
11552 *align = sizeof (gpointer);
11553 return sizeof (gpointer);
11558 *align = ALIGNMENT (gdouble);
11562 *align = ALIGNMENT (glong);
11564 case MONO_TYPE_GENERICINST:
11565 if (!mono_type_generic_inst_is_valuetype (t)) {
11566 *align = sizeof (gpointer);
11567 return sizeof (gpointer);
11570 case MONO_TYPE_TYPEDBYREF:
11571 case MONO_TYPE_VALUETYPE: {
11573 MonoClass *klass = mono_class_from_mono_type (t);
11575 if (klass->enumtype)
11576 return mono_type_native_stack_size (mono_class_enum_basetype (klass), align);
11578 size = mono_class_native_size (klass, align);
11579 *align = *align + 3;
11589 g_error ("type 0x%02x unknown", t->type);
11595 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
11596 gboolean as_field, gboolean unicode)
11598 MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
11601 switch (native_type) {
11602 case MONO_NATIVE_BOOLEAN:
11605 case MONO_NATIVE_I1:
11606 case MONO_NATIVE_U1:
11609 case MONO_NATIVE_I2:
11610 case MONO_NATIVE_U2:
11611 case MONO_NATIVE_VARIANTBOOL:
11614 case MONO_NATIVE_I4:
11615 case MONO_NATIVE_U4:
11616 case MONO_NATIVE_ERROR:
11619 case MONO_NATIVE_I8:
11620 case MONO_NATIVE_U8:
11621 *align = ALIGNMENT(guint64);
11623 case MONO_NATIVE_R4:
11626 case MONO_NATIVE_R8:
11627 *align = ALIGNMENT(double);
11629 case MONO_NATIVE_INT:
11630 case MONO_NATIVE_UINT:
11631 case MONO_NATIVE_LPSTR:
11632 case MONO_NATIVE_LPWSTR:
11633 case MONO_NATIVE_LPTSTR:
11634 case MONO_NATIVE_BSTR:
11635 case MONO_NATIVE_ANSIBSTR:
11636 case MONO_NATIVE_TBSTR:
11637 case MONO_NATIVE_LPARRAY:
11638 case MONO_NATIVE_SAFEARRAY:
11639 case MONO_NATIVE_IUNKNOWN:
11640 case MONO_NATIVE_IDISPATCH:
11641 case MONO_NATIVE_INTERFACE:
11642 case MONO_NATIVE_ASANY:
11643 case MONO_NATIVE_FUNC:
11644 case MONO_NATIVE_LPSTRUCT:
11645 *align = ALIGNMENT(gpointer);
11646 return sizeof (gpointer);
11647 case MONO_NATIVE_STRUCT:
11648 klass = mono_class_from_mono_type (type);
11649 if (klass == mono_defaults.object_class &&
11650 (mspec && mspec->native == MONO_NATIVE_STRUCT)) {
11654 return mono_class_native_size (klass, align);
11655 case MONO_NATIVE_BYVALTSTR: {
11656 int esize = unicode ? 2: 1;
11659 return mspec->data.array_data.num_elem * esize;
11661 case MONO_NATIVE_BYVALARRAY: {
11662 // FIXME: Have to consider ArraySubType
11664 klass = mono_class_from_mono_type (type);
11665 if (klass->element_class == mono_defaults.char_class) {
11666 esize = unicode ? 2 : 1;
11669 esize = mono_class_native_size (klass->element_class, align);
11672 return mspec->data.array_data.num_elem * esize;
11674 case MONO_NATIVE_CUSTOM:
11675 *align = sizeof (gpointer);
11676 return sizeof (gpointer);
11678 case MONO_NATIVE_CURRENCY:
11679 case MONO_NATIVE_VBBYREFSTR:
11681 g_error ("native type %02x not implemented", native_type);
11684 g_assert_not_reached ();
11689 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
11697 t = &o->vtable->klass->byval_arg;
11701 case MONO_TYPE_PTR:
11704 case MONO_TYPE_BOOLEAN:
11707 case MONO_TYPE_CHAR:
11712 return mono_object_unbox (o);
11714 case MONO_TYPE_STRING:
11715 switch (string_encoding) {
11716 case MONO_NATIVE_LPWSTR:
11717 return mono_marshal_string_to_utf16_copy ((MonoString*)o);
11719 case MONO_NATIVE_LPSTR:
11720 return mono_string_to_lpstr ((MonoString*)o);
11723 g_warning ("marshaling conversion %d not implemented", string_encoding);
11724 g_assert_not_reached ();
11727 case MONO_TYPE_CLASS:
11728 case MONO_TYPE_VALUETYPE: {
11729 MonoMethod *method;
11732 MonoBoolean delete_old = FALSE;
11734 klass = t->data.klass;
11736 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
11739 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
11740 klass->blittable || klass->enumtype))
11741 return mono_object_unbox (o);
11743 res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
11745 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
11746 method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
11750 pa [2] = &delete_old;
11752 mono_runtime_invoke (method, NULL, pa, NULL);
11759 mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
11765 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
11773 t = &o->vtable->klass->byval_arg;
11775 case MONO_TYPE_STRING:
11776 switch (string_encoding) {
11777 case MONO_NATIVE_LPWSTR:
11778 case MONO_NATIVE_LPSTR:
11779 mono_marshal_free (ptr);
11782 g_warning ("marshaling conversion %d not implemented", string_encoding);
11783 g_assert_not_reached ();
11786 case MONO_TYPE_CLASS:
11787 case MONO_TYPE_VALUETYPE: {
11788 klass = t->data.klass;
11790 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
11791 klass->blittable || klass->enumtype))
11794 if (param_attrs & PARAM_ATTRIBUTE_OUT) {
11795 MonoMethod *method = mono_marshal_get_ptr_to_struct (o->vtable->klass);
11801 mono_runtime_invoke (method, NULL, pa, NULL);
11804 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
11805 mono_struct_delete_old (klass, ptr);
11808 mono_marshal_free (ptr);
11817 mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar *name, MonoMethod *method)
11819 MonoMethodSignature *sig, *csig;
11820 MonoMethodBuilder *mb;
11824 mb = mono_mb_new_no_dup_name (class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
11825 mb->method->slot = -1;
11827 mb->method->flags = METHOD_ATTRIBUTE_PRIVATE | METHOD_ATTRIBUTE_VIRTUAL |
11828 METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
11830 sig = mono_method_signature (method);
11831 csig = signature_dup (method->klass->image, sig);
11832 csig->generic_param_count = 0;
11834 mono_mb_emit_ldarg (mb, 0);
11835 for (i = 0; i < csig->param_count; i++)
11836 mono_mb_emit_ldarg (mb, i + 1);
11837 mono_mb_emit_managed_call (mb, method, NULL);
11838 mono_mb_emit_byte (mb, CEE_RET);
11840 /* We can corlib internal methods */
11841 mb->skip_visibility = TRUE;
11843 res = mono_mb_create_method (mb, csig, csig->param_count + 16);
11851 * The mono_win32_compat_* functions are implementations of inline
11852 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11853 * although not exported by kernel32.
11855 * We map the appropiate kernel32 entries to these functions using
11856 * dllmaps declared in the global etc/mono/config.
11860 mono_win32_compat_CopyMemory (gpointer dest, gconstpointer source, gsize length)
11862 if (!dest || !source)
11865 memcpy (dest, source, length);
11869 mono_win32_compat_FillMemory (gpointer dest, gsize length, guchar fill)
11871 memset (dest, fill, length);
11875 mono_win32_compat_MoveMemory (gpointer dest, gconstpointer source, gsize length)
11877 if (!dest || !source)
11880 memmove (dest, source, length);
11884 mono_win32_compat_ZeroMemory (gpointer dest, gsize length)
11886 memset (dest, 0, length);
11890 mono_marshal_find_nonzero_bit_offset (guint8 *buf, int len, int *byte_offset, guint8 *bitmask)
11895 for (i = 0; i < len; ++i)
11899 g_assert (i < len);
11902 while (byte && !(byte & 1))
11904 g_assert (byte == 1);
11907 *bitmask = buf [i];
11911 mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
11913 MonoMethodBuilder *mb;
11914 MonoMethodSignature *sig, *csig;
11915 MonoExceptionClause *clause;
11920 int i, param_count, sig_size, pos_leave;
11924 klass = method->klass;
11925 image = method->klass->image;
11926 cache = get_cache (&image->thunk_invoke_cache, mono_aligned_addr_hash, NULL);
11928 if ((res = mono_marshal_find_in_cache (cache, method)))
11931 sig = mono_method_signature (method);
11932 mb = mono_mb_new (klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
11934 /* add "this" and exception param */
11935 param_count = sig->param_count + sig->hasthis + 1;
11937 /* dup & extend signature */
11938 csig = mono_metadata_signature_alloc (image, param_count);
11939 sig_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
11940 memcpy (csig, sig, sig_size);
11941 csig->param_count = param_count;
11944 csig->call_convention = MONO_CALL_DEFAULT;
11946 if (sig->hasthis) {
11948 csig->params [0] = &klass->byval_arg;
11949 /* move params up by one */
11950 for (i = 0; i < sig->param_count; i++)
11951 csig->params [i + 1] = sig->params [i];
11954 /* setup exception param as byref+[out] */
11955 csig->params [param_count - 1] = mono_metadata_type_dup (image,
11956 &mono_defaults.exception_class->byval_arg);
11957 csig->params [param_count - 1]->byref = 1;
11958 csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT;
11960 /* convert struct return to object */
11961 if (MONO_TYPE_ISSTRUCT (sig->ret))
11962 csig->ret = &mono_defaults.object_class->byval_arg;
11964 /* local 0 (temp for exception object) */
11965 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
11967 /* local 1 (temp for result) */
11968 if (!MONO_TYPE_IS_VOID (sig->ret))
11969 mono_mb_add_local (mb, sig->ret);
11971 /* clear exception arg */
11972 mono_mb_emit_ldarg (mb, param_count - 1);
11973 mono_mb_emit_byte (mb, CEE_LDNULL);
11974 mono_mb_emit_byte (mb, CEE_STIND_REF);
11977 clause = mono_image_alloc0 (image, sizeof (MonoExceptionClause));
11978 clause->try_offset = mono_mb_get_label (mb);
11980 /* push method's args */
11981 for (i = 0; i < param_count - 1; i++) {
11985 mono_mb_emit_ldarg (mb, i);
11987 /* get the byval type of the param */
11988 klass = mono_class_from_mono_type (csig->params [i]);
11989 type = &klass->byval_arg;
11991 /* unbox struct args */
11992 if (MONO_TYPE_ISSTRUCT (type)) {
11993 mono_mb_emit_op (mb, CEE_UNBOX, klass);
11995 /* byref args & and the "this" arg must remain a ptr.
11996 Otherwise make a copy of the value type */
11997 if (!(csig->params [i]->byref || (i == 0 && sig->hasthis)))
11998 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
12000 csig->params [i] = &mono_defaults.object_class->byval_arg;
12005 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
12006 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
12008 mono_mb_emit_op (mb, CEE_CALL, method);
12010 /* save result at local 1 */
12011 if (!MONO_TYPE_IS_VOID (sig->ret))
12012 mono_mb_emit_stloc (mb, 1);
12014 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
12017 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
12018 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
12019 clause->data.catch_class = mono_defaults.object_class;
12021 clause->handler_offset = mono_mb_get_label (mb);
12023 /* store exception at local 0 */
12024 mono_mb_emit_stloc (mb, 0);
12025 mono_mb_emit_ldarg (mb, param_count - 1);
12026 mono_mb_emit_ldloc (mb, 0);
12027 mono_mb_emit_byte (mb, CEE_STIND_REF);
12028 mono_mb_emit_branch (mb, CEE_LEAVE);
12030 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
12032 mono_mb_set_clauses (mb, 1, clause);
12034 mono_mb_patch_branch (mb, pos_leave);
12037 if (!MONO_TYPE_IS_VOID (sig->ret)) {
12038 mono_mb_emit_ldloc (mb, 1);
12040 /* box the return value */
12041 if (MONO_TYPE_ISSTRUCT (sig->ret))
12042 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
12045 mono_mb_emit_byte (mb, CEE_RET);
12047 res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16);
12054 * mono_marshal_free_dynamic_wrappers:
12056 * Free wrappers of the dynamic method METHOD.
12059 mono_marshal_free_dynamic_wrappers (MonoMethod *method)
12061 MonoImage *image = method->klass->image;
12063 g_assert (method->dynamic);
12065 /* This could be called during shutdown */
12066 if (marshal_mutex_initialized)
12067 mono_marshal_lock ();
12069 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
12070 * they could be shared with other methods ?
12072 if (image->runtime_invoke_direct_cache)
12073 g_hash_table_remove (image->runtime_invoke_direct_cache, method);
12074 if (image->delegate_bound_static_invoke_cache)
12075 g_hash_table_foreach_remove (image->delegate_bound_static_invoke_cache, signature_method_pair_matches_method, method);
12076 if (image->delegate_abstract_invoke_cache)
12077 g_hash_table_foreach_remove (image->delegate_abstract_invoke_cache, signature_method_pair_matches_method, method);
12079 if (marshal_mutex_initialized)
12080 mono_marshal_unlock ();
12084 * mono_marshal_free_inflated_wrappers:
12086 * Free wrappers of the inflated method METHOD.
12090 signature_method_pair_matches_signature (gpointer key, gpointer value, gpointer user_data)
12092 SignatureMethodPair *pair = (SignatureMethodPair*)key;
12093 MonoMethodSignature *sig = (MonoMethodSignature*)user_data;
12095 return mono_metadata_signature_equal (pair->sig, sig);
12099 mono_marshal_free_inflated_wrappers (MonoMethod *method)
12101 MonoMethodSignature *sig = method->signature;
12103 g_assert (method->is_inflated);
12105 /* Ignore calls occuring late during cleanup. */
12106 if (!marshal_mutex_initialized)
12109 mono_marshal_lock ();
12111 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
12112 * they could be shared with other methods ?
12116 * indexed by MonoMethodSignature
12118 /* FIXME: This could remove unrelated wrappers as well */
12119 if (sig && method->klass->image->delegate_begin_invoke_cache)
12120 g_hash_table_remove (method->klass->image->delegate_begin_invoke_cache, sig);
12121 if (sig && method->klass->image->delegate_end_invoke_cache)
12122 g_hash_table_remove (method->klass->image->delegate_end_invoke_cache, sig);
12123 if (sig && method->klass->image->delegate_invoke_cache)
12124 g_hash_table_remove (method->klass->image->delegate_invoke_cache, sig);
12125 if (sig && method->klass->image->runtime_invoke_cache)
12126 g_hash_table_remove (method->klass->image->runtime_invoke_cache, sig);
12129 * indexed by SignatureMethodPair
12131 if (sig && method->klass->image->delegate_abstract_invoke_cache)
12132 g_hash_table_foreach_remove (method->klass->image->delegate_abstract_invoke_cache,
12133 signature_method_pair_matches_signature, (gpointer)sig);
12135 if (sig && method->klass->image->delegate_bound_static_invoke_cache)
12136 g_hash_table_foreach_remove (method->klass->image->delegate_bound_static_invoke_cache,
12137 signature_method_pair_matches_signature, (gpointer)sig);
12140 * indexed by MonoMethod pointers
12142 if (method->klass->image->runtime_invoke_direct_cache)
12143 g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method);
12144 if (method->klass->image->managed_wrapper_cache)
12145 g_hash_table_remove (method->klass->image->managed_wrapper_cache, method);
12146 if (method->klass->image->native_wrapper_cache)
12147 g_hash_table_remove (method->klass->image->native_wrapper_cache, method);
12148 if (method->klass->image->remoting_invoke_cache)
12149 g_hash_table_remove (method->klass->image->remoting_invoke_cache, method);
12150 if (method->klass->image->synchronized_cache)
12151 g_hash_table_remove (method->klass->image->synchronized_cache, method);
12152 if (method->klass->image->unbox_wrapper_cache)
12153 g_hash_table_remove (method->klass->image->unbox_wrapper_cache, method);
12154 if (method->klass->image->cominterop_invoke_cache)
12155 g_hash_table_remove (method->klass->image->cominterop_invoke_cache, method);
12156 if (method->klass->image->cominterop_wrapper_cache)
12157 g_hash_table_remove (method->klass->image->cominterop_wrapper_cache, method);
12158 if (method->klass->image->thunk_invoke_cache)
12159 g_hash_table_remove (method->klass->image->thunk_invoke_cache, method);
12161 mono_marshal_unlock ();