2 * marshal.c: Routines for marshaling complex types in P/Invoke methods.
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2002 Ximian, Inc. http://www.ximian.com
14 #include "metadata/marshal.h"
15 #include "metadata/tabledefs.h"
16 #include "metadata/exception.h"
17 #include "metadata/appdomain.h"
18 #include "mono/metadata/debug-helpers.h"
19 #include "mono/metadata/threadpool.h"
20 #include "mono/metadata/threads.h"
21 #include "mono/metadata/monitor.h"
22 #include "mono/metadata/metadata-internals.h"
23 #include "mono/metadata/domain-internals.h"
24 #include "mono/metadata/gc-internal.h"
25 #include "mono/metadata/threads-types.h"
26 #include <mono/os/gc_wrapper.h>
30 /* #define DEBUG_RUNTIME_CODE */
32 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
36 MONO_MARSHAL_NONE, /* No marshalling needed */
37 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
38 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
39 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
40 } MonoXDomainMarshalType;
43 #include "mono/cil/opcode.def"
48 struct _MonoMethodBuilder {
52 guint32 code_size, pos;
56 struct _MonoRemotingMethods {
58 MonoMethod *invoke_with_check;
59 MonoMethod *xdomain_invoke;
60 MonoMethod *xdomain_dispatch;
63 typedef struct _MonoRemotingMethods MonoRemotingMethods;
66 delegate_hash_table_add (MonoDelegate *d);
69 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
71 #ifdef DEBUG_RUNTIME_CODE
73 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
75 return g_strdup (" ");
78 static MonoDisHelper marshal_dh = {
88 /* This mutex protects the various marshalling related caches in MonoImage */
89 #define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
90 #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
91 static CRITICAL_SECTION marshal_mutex;
93 /* Maps wrapper methods to the methods they wrap */
94 static GHashTable *wrapper_hash;
96 static guint32 last_error_tls_id;
98 static void mono_struct_delete_old (MonoClass *klass, char *ptr);
99 void * mono_marshal_string_to_utf16 (MonoString *s);
101 static gpointer mono_string_to_lpstr (MonoString *string_obj);
104 mono_remoting_wrapper (MonoMethod *method, gpointer *params);
106 static MonoAsyncResult *
107 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params);
110 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
113 mono_marshal_xdomain_copy_value (MonoObject *val);
116 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst);
119 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push);
122 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
124 static MonoReflectionType *
125 type_from_handle (MonoType *handle);
128 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
130 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
132 mono_register_jit_icall (func, name, sig, save);
135 static MonoMethodSignature*
136 signature_no_pinvoke (MonoMethodSignature* sig)
139 sig = mono_metadata_signature_dup (sig);
140 sig->pinvoke = FALSE;
147 mono_marshal_init (void)
149 static gboolean module_initialized = FALSE;
151 if (!module_initialized) {
152 module_initialized = TRUE;
153 InitializeCriticalSection (&marshal_mutex);
154 wrapper_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
155 last_error_tls_id = TlsAlloc ();
157 register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
158 register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
159 register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
160 register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
161 register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
162 register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
163 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
164 register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
165 register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
166 register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
167 register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
168 register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
169 register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
170 register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
171 register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
172 register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
173 register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
174 register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
175 register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
176 register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
177 register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
178 register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
179 register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
180 register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
181 register_icall (g_free, "g_free", "void ptr", FALSE);
182 register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
183 register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
184 register_icall (mono_remoting_wrapper, "mono_remoting_wrapper", "object ptr ptr", FALSE);
185 register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
186 register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
187 register_icall (mono_marshal_xdomain_copy_value, "mono_marshal_xdomain_copy_value", "object object", FALSE);
188 register_icall (mono_marshal_xdomain_copy_out_value, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE);
189 register_icall (mono_marshal_set_domain_by_id, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE);
190 register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
191 register_icall (mono_context_get, "mono_context_get", "object", FALSE);
192 register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
193 register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE);
194 register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE);
199 MonoClass *byte_array_class;
200 static MonoMethod *method_rs_serialize, *method_rs_deserialize, *method_exc_fixexc, *method_rs_appdomain_target;
201 static MonoMethod *method_set_context, *method_get_context;
202 static MonoMethod *method_set_call_context, *method_needs_context_sink, *method_rs_serialize_exc;
205 mono_remoting_marshal_init (void)
209 static gboolean module_initialized = FALSE;
211 if (!module_initialized) {
212 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
213 method_rs_serialize = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
214 method_rs_deserialize = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
215 method_rs_serialize_exc = mono_class_get_method_from_name (klass, "SerializeExceptionData", -1);
217 klass = mono_defaults.real_proxy_class;
218 method_rs_appdomain_target = mono_class_get_method_from_name (klass, "GetAppDomainTarget", -1);
220 klass = mono_defaults.exception_class;
221 method_exc_fixexc = mono_class_get_method_from_name (klass, "FixRemotingException", -1);
223 klass = mono_defaults.thread_class;
224 method_get_context = mono_class_get_method_from_name (klass, "get_CurrentContext", -1);
226 klass = mono_defaults.appdomain_class;
227 method_set_context = mono_class_get_method_from_name (klass, "InternalSetContext", -1);
228 byte_array_class = mono_array_class_get (mono_defaults.byte_class, 1);
230 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "CallContext");
231 method_set_call_context = mono_class_get_method_from_name (klass, "SetCurrentCallContext", -1);
233 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
234 method_needs_context_sink = mono_class_get_method_from_name (klass, "get_NeedsContextSink", -1);
236 module_initialized = TRUE;
241 mono_delegate_to_ftnptr (MonoDelegate *delegate)
243 MonoMethod *method, *wrapper;
249 if (delegate->delegate_trampoline)
250 return delegate->delegate_trampoline;
252 klass = ((MonoObject *)delegate)->vtable->klass;
253 g_assert (klass->delegate);
255 method = delegate->method_info->method;
257 wrapper = mono_marshal_get_managed_wrapper (method, klass, delegate->target);
259 delegate->delegate_trampoline = mono_compile_method (wrapper);
261 // Add the delegate to the delegate hash table
262 delegate_hash_table_add (delegate);
264 /* when the object is collected, collect the dunamic method, too */
265 mono_object_register_finalizer ((MonoObject*)delegate);
267 return delegate->delegate_trampoline;
270 static GHashTable *delegate_hash_table;
273 delegate_hash_table_new (void) {
274 return g_hash_table_new (NULL, NULL);
278 delegate_hash_table_remove (MonoDelegate *d)
280 mono_marshal_lock ();
281 if (delegate_hash_table == NULL)
282 delegate_hash_table = delegate_hash_table_new ();
283 g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
284 mono_marshal_unlock ();
288 delegate_hash_table_add (MonoDelegate *d)
290 mono_marshal_lock ();
291 if (delegate_hash_table == NULL)
292 delegate_hash_table = delegate_hash_table_new ();
293 g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d);
294 mono_marshal_unlock ();
298 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
302 mono_marshal_lock ();
303 if (delegate_hash_table == NULL)
304 delegate_hash_table = delegate_hash_table_new ();
306 d = g_hash_table_lookup (delegate_hash_table, ftn);
307 mono_marshal_unlock ();
309 /* This is a native function, so construct a delegate for it */
310 static MonoClass *UnmanagedFunctionPointerAttribute;
311 MonoMethodSignature *sig;
313 MonoMarshalSpec **mspecs;
314 MonoCustomAttrInfo *cinfo;
315 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
316 MonoMethod *invoke = mono_get_delegate_invoke (klass);
317 MonoMethodPInvoke piinfo;
320 memset (&piinfo, 0, sizeof (piinfo));
321 if (!UnmanagedFunctionPointerAttribute)
322 UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
324 /* The attribute is only available in Net 2.0 */
325 if (UnmanagedFunctionPointerAttribute) {
327 * The pinvoke attributes are stored in a real custom attribute so we have to
330 cinfo = mono_custom_attrs_from_class (klass);
332 attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
334 piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
337 mono_custom_attrs_free (cinfo);
341 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
342 mono_method_get_marshal_info (invoke, mspecs);
343 sig = mono_metadata_signature_dup (mono_method_signature (invoke));
346 wrapper = mono_marshal_get_native_func_wrapper (sig, &piinfo, mspecs, ftn);
348 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
350 mono_metadata_free_marshal_spec (mspecs [i]);
354 d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
355 mono_delegate_ctor ((MonoObject*)d, NULL, mono_compile_method (wrapper));
358 if (d->object.vtable->domain != mono_domain_get ())
359 mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
365 mono_delegate_free_ftnptr (MonoDelegate *delegate)
370 delegate_hash_table_remove (delegate);
372 ptr = (gpointer)InterlockedExchangePointer (&delegate->delegate_trampoline, NULL);
374 if (!delegate->target) {
375 /* The wrapper method is shared between delegates -> no need to free it */
380 ji = mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr));
383 mono_runtime_free_method (mono_object_domain (delegate), ji->method);
388 mono_array_to_savearray (MonoArray *array)
393 g_assert_not_reached ();
398 mono_array_to_lparray (MonoArray *array)
403 /* fixme: maybe we need to make a copy */
404 return array->vector;
408 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
410 GError *error = NULL;
420 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
422 if (items_written > mono_stringbuilder_capacity (sb))
423 items_written = mono_stringbuilder_capacity (sb);
426 if (! sb->str || sb->str == sb->cached_str) {
427 MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), items_written));
428 sb->cached_str = NULL;
431 memcpy (mono_string_chars (sb->str), ut, items_written * 2);
432 sb->length = items_written;
434 g_error_free (error);
440 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
447 g_assert (mono_string_chars (sb->str) == text);
449 for (len = 0; text [len] != 0; ++len)
456 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
458 GError *error = NULL;
465 res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
467 tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error);
469 g_error_free (error);
470 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
473 memcpy (res, tmp, sb->length + 1);
481 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
487 * The sb could have been allocated with the default capacity and be empty.
488 * we need to alloc a buffer of the default capacity in this case.
491 MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), mono_stringbuilder_capacity (sb)));
493 * The stringbuilder might not have ownership of this string. If this is
494 * the case, we must duplicate the string, so that we don't munge immutable
497 else if (sb->str == sb->cached_str) {
498 MONO_OBJECT_SETREF (sb, str, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb->str), mono_stringbuilder_capacity (sb)));
499 sb->cached_str = NULL;
502 return mono_string_chars (sb->str);
506 mono_string_to_lpstr (MonoString *s)
508 #ifdef PLATFORM_WIN32
511 GError *error = NULL;
517 as = CoTaskMemAlloc (1);
522 tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
524 MonoException *exc = mono_get_exception_argument ("string", error->message);
525 g_error_free (error);
526 mono_raise_exception(exc);
529 as = CoTaskMemAlloc (len + 1);
530 memcpy (as, tmp, len + 1);
534 return mono_string_to_utf8 (s);
539 mono_string_to_ansibstr (MonoString *string_obj)
541 g_error ("UnmanagedMarshal.BStr is not implemented.");
546 mono_string_to_bstr (MonoString *string_obj)
548 g_error ("UnmanagedMarshal.AnsiBStr is not implemented.");
553 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
558 g_assert (dst != NULL);
561 memset (dst, 0, size);
566 s = mono_string_to_utf8 (src);
567 len = MIN (size, strlen (s));
568 memcpy (dst, s, len);
571 *((char *)dst + size - 1) = 0;
575 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
579 g_assert (dst != NULL);
583 memset (dst, 0, size);
587 len = MIN (size, (mono_string_length (src) * 2));
588 memcpy (dst, mono_string_chars (src), len);
590 *((char *)dst + size - 1) = 0;
591 *((char *)dst + size - 2) = 0;
595 mono_mb_free (MonoMethodBuilder *mb)
597 g_list_free (mb->locals_list);
602 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
604 MonoMethodBuilder *mb;
607 g_assert (klass != NULL);
608 g_assert (name != NULL);
610 mb = g_new0 (MonoMethodBuilder, 1);
612 mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
615 m->name = g_strdup (name);
617 m->wrapper_type = type;
620 mb->code = g_malloc (mb->code_size);
626 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
628 int res = mb->locals;
630 g_assert (mb != NULL);
631 g_assert (type != NULL);
633 mb->locals_list = g_list_append (mb->locals_list, type);
640 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
642 MonoMethodHeader *header;
643 MonoMethodWrapper *mw;
647 g_assert (mb != NULL);
649 ((MonoMethodNormal *)mb->method)->header = header = (MonoMethodHeader *)
650 g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
655 header->max_stack = max_stack;
657 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
658 header->locals [i] = (MonoType *)l->data;
661 mb->method->signature = signature;
662 header->code = mb->code;
663 header->code_size = mb->pos;
664 header->num_locals = mb->locals;
666 mw = (MonoMethodWrapper*) mb->method;
667 i = g_list_length (mw->method_data);
671 l = g_list_reverse (mw->method_data);
672 data = mw->method_data = g_new (gpointer, i + 1);
673 /* store the size in the first element */
674 data [0] = GUINT_TO_POINTER (i);
676 for (tmp = l; tmp; tmp = tmp->next) {
677 data [i++] = tmp->data;
682 static int total_code = 0;
683 static int total_alloc = 0;
684 total_code += mb->pos;
685 total_alloc += mb->code_size;
686 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
689 #ifdef DEBUG_RUNTIME_CODE
690 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (mb->method, TRUE));
691 printf ("%s\n", mono_disasm_code (&marshal_dh, mb->method, mb->code, mb->code + mb->pos));
698 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
700 MonoMethodWrapper *mw;
702 g_assert (mb != NULL);
704 mw = (MonoMethodWrapper *)mb->method;
706 /* one O(n) is enough */
707 mw->method_data = g_list_prepend (mw->method_data, data);
709 return g_list_length (mw->method_data);
713 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
715 mb->code [pos] = value & 0xff;
716 mb->code [pos + 1] = (value >> 8) & 0xff;
717 mb->code [pos + 2] = (value >> 16) & 0xff;
718 mb->code [pos + 3] = (value >> 24) & 0xff;
722 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
724 *((gint8 *)(&mb->code [pos])) = value;
728 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
730 if (mb->pos >= mb->code_size) {
731 mb->code_size += mb->code_size >> 1;
732 mb->code = g_realloc (mb->code, mb->code_size);
735 mb->code [mb->pos++] = op;
739 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
741 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
742 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
745 mono_mb_emit_icon (mb, offset);
746 mono_mb_emit_byte (mb, CEE_ADD);
751 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
754 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
755 mono_mb_emit_byte (mb, CEE_LDIND_I);
756 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
757 mono_mb_emit_byte (mb, CEE_ADD);
758 mono_mb_emit_byte (mb, CEE_LDIND_I);
759 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
760 mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
761 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
762 mono_mb_emit_byte (mb, branch_code);
764 mono_mb_emit_i4 (mb, 0);
769 mono_mb_emit_xdomain_check (MonoMethodBuilder *mb, int branch_code)
772 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
773 mono_mb_emit_byte (mb, CEE_LDIND_REF);
774 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
775 mono_mb_emit_byte (mb, CEE_LDIND_I4);
776 mono_mb_emit_icon (mb, -1);
777 mono_mb_emit_byte (mb, branch_code);
779 mono_mb_emit_i4 (mb, 0);
784 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
786 if ((mb->pos + 4) >= mb->code_size) {
787 mb->code_size += mb->code_size >> 1;
788 mb->code = g_realloc (mb->code, mb->code_size);
791 mono_mb_patch_addr (mb, mb->pos, data);
796 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
798 if ((mb->pos + 2) >= mb->code_size) {
799 mb->code_size += mb->code_size >> 1;
800 mb->code = g_realloc (mb->code, mb->code_size);
803 mb->code [mb->pos] = data & 0xff;
804 mb->code [mb->pos + 1] = (data >> 8) & 0xff;
809 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
811 mono_mb_emit_byte (mb, CEE_LDSTR);
812 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, str));
817 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
820 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
821 } else if (argnum < 256) {
822 mono_mb_emit_byte (mb, CEE_LDARG_S);
823 mono_mb_emit_byte (mb, argnum);
825 mono_mb_emit_byte (mb, CEE_PREFIX1);
826 mono_mb_emit_byte (mb, CEE_LDARG);
827 mono_mb_emit_i2 (mb, argnum);
832 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
835 mono_mb_emit_byte (mb, CEE_LDARGA_S);
836 mono_mb_emit_byte (mb, argnum);
838 mono_mb_emit_byte (mb, CEE_PREFIX1);
839 mono_mb_emit_byte (mb, CEE_LDARGA);
840 mono_mb_emit_i2 (mb, argnum);
845 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
848 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
849 mono_mb_emit_byte (mb, locnum);
851 mono_mb_emit_byte (mb, CEE_PREFIX1);
852 mono_mb_emit_byte (mb, CEE_LDLOCA);
853 mono_mb_emit_i2 (mb, locnum);
858 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
861 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
862 } else if (num < 256) {
863 mono_mb_emit_byte (mb, CEE_LDLOC_S);
864 mono_mb_emit_byte (mb, num);
866 mono_mb_emit_byte (mb, CEE_PREFIX1);
867 mono_mb_emit_byte (mb, CEE_LDLOC);
868 mono_mb_emit_i2 (mb, num);
873 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
876 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
877 } else if (num < 256) {
878 mono_mb_emit_byte (mb, CEE_STLOC_S);
879 mono_mb_emit_byte (mb, num);
881 mono_mb_emit_byte (mb, CEE_PREFIX1);
882 mono_mb_emit_byte (mb, CEE_STLOC);
883 mono_mb_emit_i2 (mb, num);
888 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
890 if (value >= -1 && value < 8) {
891 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
892 } else if (value >= -128 && value <= 127) {
893 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
894 mono_mb_emit_byte (mb, value);
896 mono_mb_emit_byte (mb, CEE_LDC_I4);
897 mono_mb_emit_i4 (mb, value);
902 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
905 mono_mb_emit_byte (mb, op);
907 mono_mb_emit_i4 (mb, 0);
912 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
914 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
915 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
916 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ptr));
920 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
922 mono_mb_emit_byte (mb, CEE_CALLI);
923 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
927 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
929 mono_mb_emit_byte (mb, CEE_CALL);
930 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
934 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
936 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
937 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
938 mono_mb_emit_ptr (mb, func);
939 mono_mb_emit_calli (mb, sig);
940 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
941 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
945 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
947 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
948 mono_mb_emit_byte (mb, CEE_MONO_ICALL);
949 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
953 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
955 MonoMethod *ctor = NULL;
957 MonoClass *mme = mono_class_from_name (mono_defaults.corlib, exc_nspace, exc_name);
958 mono_class_init (mme);
959 ctor = mono_class_get_method_from_name (mme, ".ctor", 0);
961 mono_mb_emit_byte (mb, CEE_NEWOBJ);
962 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ctor));
964 mono_mb_emit_byte (mb, CEE_DUP);
965 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message));
966 mono_mb_emit_ldstr (mb, (char*)msg);
967 mono_mb_emit_byte (mb, CEE_STIND_REF);
969 mono_mb_emit_byte (mb, CEE_THROW);
973 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
975 mono_mb_emit_exception_full (mb, "System", exc_name, msg);
979 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, const char *msg)
981 mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", msg);
985 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
987 mono_mb_emit_ldloc (mb, local);
988 mono_mb_emit_icon (mb, incr);
989 mono_mb_emit_byte (mb, CEE_ADD);
990 mono_mb_emit_stloc (mb, local);
994 emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
997 case MONO_MARSHAL_CONV_BOOL_I4:
998 mono_mb_emit_ldloc (mb, 1);
999 mono_mb_emit_ldloc (mb, 0);
1000 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1001 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1002 mono_mb_emit_byte (mb, 3);
1003 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1004 mono_mb_emit_byte (mb, CEE_BR_S);
1005 mono_mb_emit_byte (mb, 1);
1006 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1007 mono_mb_emit_byte (mb, CEE_STIND_I1);
1009 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1010 mono_mb_emit_ldloc (mb, 1);
1011 mono_mb_emit_ldloc (mb, 0);
1012 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1013 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1014 mono_mb_emit_byte (mb, 3);
1015 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1016 mono_mb_emit_byte (mb, CEE_BR_S);
1017 mono_mb_emit_byte (mb, 1);
1018 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1019 mono_mb_emit_byte (mb, CEE_STIND_I1);
1021 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1022 MonoClass *eclass = NULL;
1025 if (type->type == MONO_TYPE_SZARRAY) {
1026 eclass = type->data.klass;
1028 g_assert_not_reached ();
1031 if (eclass->valuetype)
1032 esize = mono_class_instance_size (eclass) - sizeof (MonoObject);
1034 esize = sizeof (gpointer);
1036 /* create a new array */
1037 mono_mb_emit_ldloc (mb, 1);
1038 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1039 mono_mb_emit_byte (mb, CEE_NEWARR);
1040 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass));
1041 mono_mb_emit_byte (mb, CEE_STIND_I);
1043 /* copy the elements */
1044 mono_mb_emit_ldloc (mb, 1);
1045 mono_mb_emit_byte (mb, CEE_LDIND_I);
1046 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
1047 mono_mb_emit_byte (mb, CEE_ADD);
1048 mono_mb_emit_ldloc (mb, 0);
1049 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1050 mono_mb_emit_byte (mb, CEE_PREFIX1);
1051 mono_mb_emit_byte (mb, CEE_CPBLK);
1055 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1056 mono_mb_emit_ldloc (mb, 1);
1057 mono_mb_emit_ldloc (mb, 0);
1058 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1059 mono_mb_emit_byte (mb, CEE_STIND_I);
1061 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1062 mono_mb_emit_ldloc (mb, 1);
1063 mono_mb_emit_ldloc (mb, 0);
1064 mono_mb_emit_icall (mb, mono_string_from_utf16);
1065 mono_mb_emit_byte (mb, CEE_STIND_I);
1067 case MONO_MARSHAL_CONV_STR_LPTSTR:
1068 case MONO_MARSHAL_CONV_STR_LPSTR:
1069 mono_mb_emit_ldloc (mb, 1);
1070 mono_mb_emit_ldloc (mb, 0);
1071 mono_mb_emit_byte (mb, CEE_LDIND_I);
1072 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1073 mono_mb_emit_byte (mb, CEE_STIND_I);
1075 case MONO_MARSHAL_CONV_STR_LPWSTR:
1076 mono_mb_emit_ldloc (mb, 1);
1077 mono_mb_emit_ldloc (mb, 0);
1078 mono_mb_emit_byte (mb, CEE_LDIND_I);
1079 mono_mb_emit_icall (mb, mono_string_from_utf16);
1080 mono_mb_emit_byte (mb, CEE_STIND_I);
1082 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1083 MonoClass *klass = mono_class_from_mono_type (type);
1084 int src_var, dst_var;
1086 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1087 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1089 /* *dst = new object */
1090 mono_mb_emit_ldloc (mb, 1);
1091 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1092 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
1093 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
1094 mono_mb_emit_byte (mb, CEE_STIND_I);
1096 /* save the old src pointer */
1097 mono_mb_emit_ldloc (mb, 0);
1098 mono_mb_emit_stloc (mb, src_var);
1099 /* save the old dst pointer */
1100 mono_mb_emit_ldloc (mb, 1);
1101 mono_mb_emit_stloc (mb, dst_var);
1103 /* dst = pointer to newly created object data */
1104 mono_mb_emit_ldloc (mb, 1);
1105 mono_mb_emit_byte (mb, CEE_LDIND_I);
1106 mono_mb_emit_icon (mb, sizeof (MonoObject));
1107 mono_mb_emit_byte (mb, CEE_ADD);
1108 mono_mb_emit_byte (mb, CEE_STLOC_1);
1110 emit_struct_conv (mb, klass, TRUE);
1112 /* restore the old src pointer */
1113 mono_mb_emit_ldloc (mb, src_var);
1114 mono_mb_emit_stloc (mb, 0);
1115 /* restore the old dst pointer */
1116 mono_mb_emit_ldloc (mb, dst_var);
1117 mono_mb_emit_byte (mb, CEE_STLOC_1);
1120 case MONO_MARSHAL_CONV_DEL_FTN: {
1121 MonoClass *klass = mono_class_from_mono_type (type);
1123 mono_mb_emit_ldloc (mb, 1);
1124 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1125 mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
1126 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
1127 mono_mb_emit_ldloc (mb, 0);
1128 mono_mb_emit_byte (mb, CEE_LDIND_I);
1129 mono_mb_emit_icall (mb, mono_ftnptr_to_delegate);
1130 mono_mb_emit_byte (mb, CEE_STIND_I);
1133 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1134 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
1136 case MONO_MARSHAL_CONV_STR_BSTR:
1137 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1138 case MONO_MARSHAL_CONV_STR_TBSTR:
1139 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1141 g_warning ("marshaling conversion %d not implemented", conv);
1142 g_assert_not_reached ();
1147 conv_to_icall (MonoMarshalConv conv)
1150 case MONO_MARSHAL_CONV_STR_LPWSTR:
1151 return mono_marshal_string_to_utf16;
1152 case MONO_MARSHAL_CONV_LPWSTR_STR:
1153 return mono_string_from_utf16;
1154 case MONO_MARSHAL_CONV_LPSTR_STR:
1155 return mono_string_new_wrapper;
1156 case MONO_MARSHAL_CONV_STR_LPTSTR:
1157 case MONO_MARSHAL_CONV_STR_LPSTR:
1158 return mono_string_to_lpstr;
1159 case MONO_MARSHAL_CONV_STR_BSTR:
1160 return mono_string_to_bstr;
1161 case MONO_MARSHAL_CONV_STR_TBSTR:
1162 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1163 return mono_string_to_ansibstr;
1164 case MONO_MARSHAL_CONV_SB_LPSTR:
1165 case MONO_MARSHAL_CONV_SB_LPTSTR:
1166 return mono_string_builder_to_utf8;
1167 case MONO_MARSHAL_CONV_SB_LPWSTR:
1168 return mono_string_builder_to_utf16;
1169 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1170 return mono_array_to_savearray;
1171 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1172 return mono_array_to_lparray;
1173 case MONO_MARSHAL_CONV_DEL_FTN:
1174 return mono_delegate_to_ftnptr;
1175 case MONO_MARSHAL_CONV_FTN_DEL:
1176 return mono_ftnptr_to_delegate;
1177 case MONO_MARSHAL_CONV_LPSTR_SB:
1178 case MONO_MARSHAL_CONV_LPTSTR_SB:
1179 return mono_string_utf8_to_builder;
1180 case MONO_MARSHAL_CONV_LPWSTR_SB:
1181 return mono_string_utf16_to_builder;
1182 case MONO_MARSHAL_FREE_ARRAY:
1183 return mono_marshal_free_array;
1184 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1185 return mono_string_to_byvalstr;
1186 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1187 return mono_string_to_byvalwstr;
1189 g_assert_not_reached ();
1196 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1201 case MONO_MARSHAL_CONV_BOOL_I4:
1202 mono_mb_emit_ldloc (mb, 1);
1203 mono_mb_emit_ldloc (mb, 0);
1204 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1205 mono_mb_emit_byte (mb, CEE_STIND_I4);
1207 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1208 mono_mb_emit_ldloc (mb, 1);
1209 mono_mb_emit_ldloc (mb, 0);
1210 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1211 mono_mb_emit_byte (mb, CEE_NEG);
1212 mono_mb_emit_byte (mb, CEE_STIND_I2);
1214 case MONO_MARSHAL_CONV_STR_LPWSTR:
1215 case MONO_MARSHAL_CONV_STR_LPSTR:
1216 case MONO_MARSHAL_CONV_STR_LPTSTR:
1217 case MONO_MARSHAL_CONV_STR_BSTR:
1218 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1219 case MONO_MARSHAL_CONV_STR_TBSTR: {
1222 /* free space if free == true */
1223 mono_mb_emit_ldloc (mb, 2);
1224 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1226 mono_mb_emit_byte (mb, 0);
1227 mono_mb_emit_ldloc (mb, 1);
1228 mono_mb_emit_byte (mb, CEE_LDIND_I);
1229 mono_mb_emit_icall (mb, g_free);
1230 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1232 mono_mb_emit_ldloc (mb, 1);
1233 mono_mb_emit_ldloc (mb, 0);
1234 mono_mb_emit_byte (mb, CEE_LDIND_I);
1235 mono_mb_emit_icall (mb, conv_to_icall (conv));
1236 mono_mb_emit_byte (mb, CEE_STIND_I);
1239 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1240 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1241 case MONO_MARSHAL_CONV_DEL_FTN:
1242 mono_mb_emit_ldloc (mb, 1);
1243 mono_mb_emit_ldloc (mb, 0);
1244 mono_mb_emit_byte (mb, CEE_LDIND_I);
1245 mono_mb_emit_icall (mb, conv_to_icall (conv));
1246 mono_mb_emit_byte (mb, CEE_STIND_I);
1248 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1249 case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
1252 mono_mb_emit_ldloc (mb, 1); /* dst */
1253 mono_mb_emit_ldloc (mb, 0);
1254 mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */
1255 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1256 mono_mb_emit_icall (mb, conv_to_icall (conv));
1259 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1260 MonoClass *eclass = NULL;
1263 if (type->type == MONO_TYPE_SZARRAY) {
1264 eclass = type->data.klass;
1266 g_assert_not_reached ();
1269 if (eclass->valuetype)
1270 esize = mono_class_native_size (eclass, NULL);
1272 esize = sizeof (gpointer);
1274 mono_mb_emit_ldloc (mb, 0);
1275 mono_mb_emit_byte (mb, CEE_LDIND_I);
1276 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1278 mono_mb_emit_byte (mb, 0);
1280 mono_mb_emit_ldloc (mb, 1);
1281 mono_mb_emit_ldloc (mb, 0);
1282 mono_mb_emit_byte (mb, CEE_LDIND_I);
1283 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1284 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1285 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
1286 mono_mb_emit_byte (mb, CEE_ADD);
1287 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1288 mono_mb_emit_byte (mb, CEE_PREFIX1);
1289 mono_mb_emit_byte (mb, CEE_CPBLK);
1290 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1293 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1294 int src_var, dst_var;
1296 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1297 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1299 mono_mb_emit_ldloc (mb, 0);
1300 mono_mb_emit_byte (mb, CEE_LDIND_I);
1301 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1303 mono_mb_emit_byte (mb, 0);
1305 /* save the old src pointer */
1306 mono_mb_emit_ldloc (mb, 0);
1307 mono_mb_emit_stloc (mb, src_var);
1308 /* save the old dst pointer */
1309 mono_mb_emit_ldloc (mb, 1);
1310 mono_mb_emit_stloc (mb, dst_var);
1312 /* src = pointer to object data */
1313 mono_mb_emit_ldloc (mb, 0);
1314 mono_mb_emit_byte (mb, CEE_LDIND_I);
1315 mono_mb_emit_icon (mb, sizeof (MonoObject));
1316 mono_mb_emit_byte (mb, CEE_ADD);
1317 mono_mb_emit_stloc (mb, 0);
1319 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
1321 /* restore the old src pointer */
1322 mono_mb_emit_ldloc (mb, src_var);
1323 mono_mb_emit_stloc (mb, 0);
1324 /* restore the old dst pointer */
1325 mono_mb_emit_ldloc (mb, dst_var);
1326 mono_mb_emit_byte (mb, CEE_STLOC_1);
1328 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1332 char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
1333 MonoException *exc = mono_get_exception_not_implemented (msg);
1336 mono_raise_exception (exc);
1342 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
1344 MonoMarshalType *info;
1348 emit_struct_conv(mb, klass->parent, to_object);
1350 info = mono_marshal_load_type_info (klass);
1352 if (info->native_size == 0)
1355 if (klass->blittable) {
1356 int msize = mono_class_value_size (klass, NULL);
1357 g_assert (msize == info->native_size);
1358 mono_mb_emit_ldloc (mb, 1);
1359 mono_mb_emit_ldloc (mb, 0);
1360 mono_mb_emit_icon (mb, msize);
1361 mono_mb_emit_byte (mb, CEE_PREFIX1);
1362 mono_mb_emit_byte (mb, CEE_CPBLK);
1364 mono_mb_emit_add_to_local (mb, 0, msize);
1365 mono_mb_emit_add_to_local (mb, 1, msize);
1369 for (i = 0; i < info->num_fields; i++) {
1370 MonoMarshalNative ntype;
1371 MonoMarshalConv conv;
1372 MonoType *ftype = info->fields [i].field->type;
1375 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
1377 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
1380 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
1383 msize = klass->instance_size - info->fields [i].field->offset;
1384 usize = info->native_size - info->fields [i].offset;
1386 msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
1387 usize = info->fields [i + 1].offset - info->fields [i].offset;
1391 * FIXME: Should really check for usize==0 and msize>0, but we apply
1392 * the layout to the managed structure as well.
1394 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
1395 if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
1396 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a reference field at the same offset as another field.", mono_type_full_name (&klass->byval_arg));
1399 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
1400 g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg));
1403 case MONO_MARSHAL_CONV_NONE: {
1406 if (ftype->byref || ftype->type == MONO_TYPE_I ||
1407 ftype->type == MONO_TYPE_U) {
1408 mono_mb_emit_ldloc (mb, 1);
1409 mono_mb_emit_ldloc (mb, 0);
1410 mono_mb_emit_byte (mb, CEE_LDIND_I);
1411 mono_mb_emit_byte (mb, CEE_STIND_I);
1420 #if SIZEOF_VOID_P == 4
1423 mono_mb_emit_ldloc (mb, 1);
1424 mono_mb_emit_ldloc (mb, 0);
1425 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1426 mono_mb_emit_byte (mb, CEE_STIND_I4);
1430 case MONO_TYPE_BOOLEAN:
1431 mono_mb_emit_ldloc (mb, 1);
1432 mono_mb_emit_ldloc (mb, 0);
1433 mono_mb_emit_byte (mb, CEE_LDIND_I1);
1434 mono_mb_emit_byte (mb, CEE_STIND_I1);
1438 case MONO_TYPE_CHAR:
1439 mono_mb_emit_ldloc (mb, 1);
1440 mono_mb_emit_ldloc (mb, 0);
1441 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1442 mono_mb_emit_byte (mb, CEE_STIND_I2);
1446 #if SIZEOF_VOID_P == 8
1449 mono_mb_emit_ldloc (mb, 1);
1450 mono_mb_emit_ldloc (mb, 0);
1451 mono_mb_emit_byte (mb, CEE_LDIND_I8);
1452 mono_mb_emit_byte (mb, CEE_STIND_I8);
1455 mono_mb_emit_ldloc (mb, 1);
1456 mono_mb_emit_ldloc (mb, 0);
1457 mono_mb_emit_byte (mb, CEE_LDIND_R4);
1458 mono_mb_emit_byte (mb, CEE_STIND_R4);
1461 mono_mb_emit_ldloc (mb, 1);
1462 mono_mb_emit_ldloc (mb, 0);
1463 mono_mb_emit_byte (mb, CEE_LDIND_R8);
1464 mono_mb_emit_byte (mb, CEE_STIND_R8);
1466 case MONO_TYPE_VALUETYPE: {
1467 int src_var, dst_var;
1469 if (ftype->data.klass->enumtype) {
1470 t = ftype->data.klass->enum_basetype->type;
1474 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1475 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1477 /* save the old src pointer */
1478 mono_mb_emit_ldloc (mb, 0);
1479 mono_mb_emit_stloc (mb, src_var);
1480 /* save the old dst pointer */
1481 mono_mb_emit_ldloc (mb, 1);
1482 mono_mb_emit_stloc (mb, dst_var);
1484 emit_struct_conv (mb, ftype->data.klass, to_object);
1486 /* restore the old src pointer */
1487 mono_mb_emit_ldloc (mb, src_var);
1488 mono_mb_emit_stloc (mb, 0);
1489 /* restore the old dst pointer */
1490 mono_mb_emit_ldloc (mb, dst_var);
1491 mono_mb_emit_byte (mb, CEE_STLOC_1);
1496 g_warning ("marshaling type %02x not implemented", ftype->type);
1497 g_assert_not_reached ();
1502 int src_var, dst_var;
1504 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1505 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1507 /* save the old src pointer */
1508 mono_mb_emit_ldloc (mb, 0);
1509 mono_mb_emit_stloc (mb, src_var);
1510 /* save the old dst pointer */
1511 mono_mb_emit_ldloc (mb, 1);
1512 mono_mb_emit_stloc (mb, dst_var);
1515 emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec);
1517 emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec);
1519 /* restore the old src pointer */
1520 mono_mb_emit_ldloc (mb, src_var);
1521 mono_mb_emit_stloc (mb, 0);
1522 /* restore the old dst pointer */
1523 mono_mb_emit_ldloc (mb, dst_var);
1524 mono_mb_emit_byte (mb, CEE_STLOC_1);
1529 mono_mb_emit_add_to_local (mb, 0, usize);
1530 mono_mb_emit_add_to_local (mb, 1, msize);
1532 mono_mb_emit_add_to_local (mb, 0, msize);
1533 mono_mb_emit_add_to_local (mb, 1, usize);
1539 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
1541 /* Call DestroyStructure */
1542 /* FIXME: Only do this if needed */
1543 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1544 mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
1545 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
1546 mono_mb_emit_ldloc (mb, struct_var);
1547 mono_mb_emit_icall (mb, mono_struct_delete_old);
1551 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoint_func)
1555 mono_mb_emit_ptr (mb, (gpointer) mono_thread_interruption_request_flag ());
1556 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1557 pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
1559 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1560 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
1562 mono_mb_emit_icall (mb, checkpoint_func);
1564 mono_mb_patch_addr (mb, pos_noabort, mb->pos - (pos_noabort + 4));
1568 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
1570 if (strstr (mb->method->name, "mono_thread_interruption_checkpoint"))
1573 emit_thread_interrupt_checkpoint_call (mb, mono_thread_interruption_checkpoint);
1577 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
1579 emit_thread_interrupt_checkpoint_call (mb, mono_thread_force_interruption_checkpoint);
1582 static MonoAsyncResult *
1583 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
1585 MonoMethodMessage *msg;
1586 MonoDelegate *async_callback;
1590 MonoMethod *method = NULL, *method2 = NULL;
1592 g_assert (delegate);
1594 if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
1596 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
1597 if (!tp->remote_class->proxy_class->contextbound || tp->rp->context != (MonoObject *) mono_context_get ()) {
1599 /* If the target is a proxy, make a direct call. Is proxy's work
1600 // to make the call asynchronous.
1602 MonoAsyncResult *ares;
1604 MonoArray *out_args;
1606 method = delegate->method_info->method;
1608 msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
1609 handle = CreateEvent (NULL, TRUE, FALSE, NULL);
1610 ares = mono_async_result_new (mono_domain_get (), handle, state, handle);
1611 MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
1612 MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
1613 MONO_OBJECT_SETREF (msg, async_result, ares);
1614 msg->call_type = CallType_BeginInvoke;
1616 mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
1621 klass = delegate->object.vtable->klass;
1623 method = mono_get_delegate_invoke (klass);
1624 method2 = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
1627 g_assert (method != NULL);
1629 im = mono_get_delegate_invoke (method->klass);
1630 msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
1632 return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
1636 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
1638 int i, params_var, tmp_var;
1640 /* allocate local (pointer) *params[] */
1641 params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1642 /* allocate local (pointer) tmp */
1643 tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1645 /* alloate space on stack to store an array of pointers to the arguments */
1646 mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
1647 mono_mb_emit_byte (mb, CEE_PREFIX1);
1648 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1649 mono_mb_emit_stloc (mb, params_var);
1652 mono_mb_emit_ldloc (mb, params_var);
1653 mono_mb_emit_stloc (mb, tmp_var);
1655 if (save_this && sig->hasthis) {
1656 mono_mb_emit_ldloc (mb, tmp_var);
1657 mono_mb_emit_ldarg_addr (mb, 0);
1658 mono_mb_emit_byte (mb, CEE_STIND_I);
1659 /* tmp = tmp + sizeof (gpointer) */
1660 if (sig->param_count)
1661 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
1665 for (i = 0; i < sig->param_count; i++) {
1666 mono_mb_emit_ldloc (mb, tmp_var);
1667 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
1668 mono_mb_emit_byte (mb, CEE_STIND_I);
1669 /* tmp = tmp + sizeof (gpointer) */
1670 if (i < (sig->param_count - 1))
1671 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
1678 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
1682 GString *res = g_string_new ("");
1685 g_string_append (res, prefix);
1686 g_string_append_c (res, '_');
1689 mono_type_get_desc (res, sig->ret, FALSE);
1691 for (i = 0; i < sig->param_count; ++i) {
1692 g_string_append_c (res, '_');
1693 mono_type_get_desc (res, sig->params [i], FALSE);
1696 g_string_free (res, FALSE);
1701 * mono_marshal_get_string_encoding:
1703 * Return the string encoding which should be used for a given parameter.
1705 static MonoMarshalNative
1706 mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1708 /* First try the parameter marshal info */
1710 if (spec->native == MONO_NATIVE_LPARRAY) {
1711 if ((spec->data.array_data.elem_type != 0) && (spec->data.array_data.elem_type != MONO_NATIVE_MAX))
1712 return spec->data.array_data.elem_type;
1715 return spec->native;
1719 return MONO_NATIVE_LPSTR;
1721 /* Then try the method level marshal info */
1722 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
1723 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
1724 return MONO_NATIVE_LPSTR;
1725 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
1726 return MONO_NATIVE_LPWSTR;
1727 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
1728 #ifdef PLATFORM_WIN32
1729 return MONO_NATIVE_LPWSTR;
1731 return MONO_NATIVE_LPSTR;
1734 return MONO_NATIVE_LPSTR;
1738 static MonoMarshalConv
1739 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1741 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1744 case MONO_NATIVE_LPWSTR:
1745 return MONO_MARSHAL_CONV_STR_LPWSTR;
1746 case MONO_NATIVE_LPSTR:
1747 return MONO_MARSHAL_CONV_STR_LPSTR;
1748 case MONO_NATIVE_LPTSTR:
1749 return MONO_MARSHAL_CONV_STR_LPTSTR;
1755 static MonoMarshalConv
1756 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1758 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1761 case MONO_NATIVE_LPWSTR:
1762 return MONO_MARSHAL_CONV_SB_LPWSTR;
1764 case MONO_NATIVE_LPSTR:
1765 return MONO_MARSHAL_CONV_SB_LPSTR;
1767 case MONO_NATIVE_LPTSTR:
1768 return MONO_MARSHAL_CONV_SB_LPTSTR;
1775 static MonoMarshalConv
1776 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
1778 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1783 case MONO_NATIVE_LPWSTR:
1784 return MONO_MARSHAL_CONV_LPWSTR_STR;
1785 case MONO_NATIVE_LPSTR:
1786 return MONO_MARSHAL_CONV_LPSTR_STR;
1787 case MONO_NATIVE_LPTSTR:
1788 return MONO_MARSHAL_CONV_LPTSTR_STR;
1794 static MonoMarshalConv
1795 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
1797 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1802 case MONO_NATIVE_LPWSTR:
1804 * mono_string_builder_to_utf16 does not allocate a
1805 * new buffer, so no need to free it.
1808 return MONO_MARSHAL_CONV_LPWSTR_SB;
1809 case MONO_NATIVE_LPSTR:
1810 return MONO_MARSHAL_CONV_LPSTR_SB;
1812 case MONO_NATIVE_LPTSTR:
1813 return MONO_MARSHAL_CONV_LPTSTR_SB;
1821 * Return whenever a field of a native structure or an array member needs to
1825 mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1827 MonoMarshalNative encoding;
1828 MonoMarshalConv conv;
1831 case MONO_TYPE_VALUETYPE:
1832 /* FIXME: Optimize this */
1834 case MONO_TYPE_OBJECT:
1835 case MONO_TYPE_CLASS:
1836 if (t->data.klass == mono_defaults.stringbuilder_class) {
1838 conv = mono_marshal_get_ptr_to_stringbuilder_conv (piinfo, spec, &need_free);
1842 case MONO_TYPE_STRING:
1843 encoding = mono_marshal_get_string_encoding (piinfo, spec);
1844 return (encoding == MONO_NATIVE_LPWSTR) ? FALSE : TRUE;
1850 static inline MonoMethod*
1851 mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
1855 mono_marshal_lock ();
1856 res = g_hash_table_lookup (cache, key);
1857 mono_marshal_unlock ();
1861 /* Create the method from the builder and place it in the cache */
1862 static inline MonoMethod*
1863 mono_mb_create_and_cache (GHashTable *cache, gpointer key,
1864 MonoMethodBuilder *mb, MonoMethodSignature *sig,
1869 mono_marshal_lock ();
1870 res = g_hash_table_lookup (cache, key);
1872 /* This does not acquire any locks */
1873 res = mono_mb_create_method (mb, sig, max_stack);
1874 g_hash_table_insert (cache, key, res);
1875 g_hash_table_insert (wrapper_hash, res, key);
1877 mono_marshal_unlock ();
1883 static inline MonoMethod*
1884 mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type)
1886 MonoMethod *res = NULL;
1887 MonoRemotingMethods *wrps;
1889 mono_marshal_lock ();
1890 wrps = g_hash_table_lookup (method->klass->image->remoting_invoke_cache, method);
1893 switch (wrapper_type) {
1894 case MONO_WRAPPER_REMOTING_INVOKE: res = wrps->invoke; break;
1895 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = wrps->invoke_with_check; break;
1896 case MONO_WRAPPER_XDOMAIN_INVOKE: res = wrps->xdomain_invoke; break;
1897 case MONO_WRAPPER_XDOMAIN_DISPATCH: res = wrps->xdomain_dispatch; break;
1901 mono_marshal_unlock ();
1905 /* Create the method from the builder and place it in the cache */
1906 static inline MonoMethod*
1907 mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb,
1908 MonoMethodSignature *sig, int max_stack)
1910 MonoMethod **res = NULL;
1911 MonoRemotingMethods *wrps;
1912 GHashTable *cache = key->klass->image->remoting_invoke_cache;
1914 mono_marshal_lock ();
1915 wrps = g_hash_table_lookup (cache, key);
1917 wrps = g_new0 (MonoRemotingMethods, 1);
1918 g_hash_table_insert (cache, key, wrps);
1921 switch (mb->method->wrapper_type) {
1922 case MONO_WRAPPER_REMOTING_INVOKE: res = &wrps->invoke; break;
1923 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = &wrps->invoke_with_check; break;
1924 case MONO_WRAPPER_XDOMAIN_INVOKE: res = &wrps->xdomain_invoke; break;
1925 case MONO_WRAPPER_XDOMAIN_DISPATCH: res = &wrps->xdomain_dispatch; break;
1926 default: g_assert_not_reached (); break;
1930 /* This does not acquire any locks */
1931 *res = mono_mb_create_method (mb, sig, max_stack);
1932 g_hash_table_insert (wrapper_hash, *res, key);
1935 mono_marshal_unlock ();
1941 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
1945 if (wrapper->wrapper_type == MONO_WRAPPER_NONE)
1948 mono_marshal_lock ();
1949 res = g_hash_table_lookup (wrapper_hash, wrapper);
1950 mono_marshal_unlock ();
1955 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
1957 MonoMethodSignature *sig;
1958 MonoMethodBuilder *mb;
1964 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1965 !strcmp (method->name, "BeginInvoke"));
1967 sig = signature_no_pinvoke (mono_method_signature (method));
1969 cache = method->klass->image->delegate_begin_invoke_cache;
1970 if ((res = mono_marshal_find_in_cache (cache, sig)))
1973 g_assert (sig->hasthis);
1975 name = mono_signature_to_name (sig, "begin_invoke");
1976 mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
1979 mb->method->save_lmf = 1;
1981 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
1983 mono_mb_emit_ldarg (mb, 0);
1984 mono_mb_emit_ldloc (mb, params_var);
1985 mono_mb_emit_icall (mb, mono_delegate_begin_invoke);
1986 emit_thread_interrupt_checkpoint (mb);
1987 mono_mb_emit_byte (mb, CEE_RET);
1989 res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
1995 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
1997 MonoDomain *domain = mono_domain_get ();
1998 MonoAsyncResult *ares;
1999 MonoMethod *method = NULL;
2000 MonoMethodSignature *sig;
2001 MonoMethodMessage *msg;
2002 MonoObject *res, *exc;
2003 MonoArray *out_args;
2006 g_assert (delegate);
2008 if (!delegate->method_info || !delegate->method_info->method)
2009 g_assert_not_reached ();
2011 klass = delegate->object.vtable->klass;
2013 method = mono_class_get_method_from_name (klass, "EndInvoke", -1);
2014 g_assert (method != NULL);
2016 sig = signature_no_pinvoke (mono_method_signature (method));
2018 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
2020 ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
2023 if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
2024 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
2025 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2026 mono_message_init (domain, msg, delegate->method_info, NULL);
2027 msg->call_type = CallType_EndInvoke;
2028 MONO_OBJECT_SETREF (msg, async_result, ares);
2029 res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
2032 res = mono_thread_pool_finish (ares, &out_args, &exc);
2035 if (((MonoException*)exc)->stack_trace) {
2036 char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
2038 tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
2040 MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
2043 mono_raise_exception ((MonoException*)exc);
2046 mono_method_return_message_restore (method, params, out_args);
2051 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
2053 MonoType *t = mono_type_get_underlying_type (return_type);
2055 if (return_type->byref)
2056 return_type = &mono_defaults.int_class->byval_arg;
2059 case MONO_TYPE_VOID:
2060 g_assert_not_reached ();
2063 case MONO_TYPE_STRING:
2064 case MONO_TYPE_CLASS:
2065 case MONO_TYPE_OBJECT:
2066 case MONO_TYPE_ARRAY:
2067 case MONO_TYPE_SZARRAY:
2071 case MONO_TYPE_BOOLEAN:
2072 mono_mb_emit_byte (mb, CEE_UNBOX);
2073 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2074 mono_mb_emit_byte (mb, CEE_LDIND_U1);
2077 mono_mb_emit_byte (mb, CEE_UNBOX);
2078 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2079 mono_mb_emit_byte (mb, CEE_LDIND_I1);
2082 case MONO_TYPE_CHAR:
2083 mono_mb_emit_byte (mb, CEE_UNBOX);
2084 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2085 mono_mb_emit_byte (mb, CEE_LDIND_U2);
2088 mono_mb_emit_byte (mb, CEE_UNBOX);
2089 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2090 mono_mb_emit_byte (mb, CEE_LDIND_I2);
2094 mono_mb_emit_byte (mb, CEE_UNBOX);
2095 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2096 mono_mb_emit_byte (mb, CEE_LDIND_I);
2099 mono_mb_emit_byte (mb, CEE_UNBOX);
2100 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2101 mono_mb_emit_byte (mb, CEE_LDIND_I4);
2104 mono_mb_emit_byte (mb, CEE_UNBOX);
2105 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2106 mono_mb_emit_byte (mb, CEE_LDIND_U4);
2110 mono_mb_emit_byte (mb, CEE_UNBOX);
2111 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2112 mono_mb_emit_byte (mb, CEE_LDIND_I8);
2115 mono_mb_emit_byte (mb, CEE_UNBOX);
2116 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2117 mono_mb_emit_byte (mb, CEE_LDIND_R4);
2120 mono_mb_emit_byte (mb, CEE_UNBOX);
2121 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
2122 mono_mb_emit_byte (mb, CEE_LDIND_R8);
2124 case MONO_TYPE_GENERICINST:
2125 if (!mono_type_generic_inst_is_valuetype (return_type))
2128 case MONO_TYPE_VALUETYPE: {
2130 mono_mb_emit_byte (mb, CEE_UNBOX);
2131 class = mono_mb_add_data (mb, mono_class_from_mono_type (return_type));
2132 mono_mb_emit_i4 (mb, class);
2133 mono_mb_emit_byte (mb, CEE_LDOBJ);
2134 mono_mb_emit_i4 (mb, class);
2138 g_warning ("type 0x%x not handled", return_type->type);
2139 g_assert_not_reached ();
2142 mono_mb_emit_byte (mb, CEE_RET);
2146 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
2148 MonoMethodSignature *sig;
2149 MonoMethodBuilder *mb;
2155 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
2156 !strcmp (method->name, "EndInvoke"));
2158 sig = signature_no_pinvoke (mono_method_signature (method));
2160 cache = method->klass->image->delegate_end_invoke_cache;
2161 if ((res = mono_marshal_find_in_cache (cache, sig)))
2164 g_assert (sig->hasthis);
2166 name = mono_signature_to_name (sig, "end_invoke");
2167 mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
2170 mb->method->save_lmf = 1;
2172 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
2174 mono_mb_emit_ldarg (mb, 0);
2175 mono_mb_emit_ldloc (mb, params_var);
2176 mono_mb_emit_icall (mb, mono_delegate_end_invoke);
2177 emit_thread_interrupt_checkpoint (mb);
2179 if (sig->ret->type == MONO_TYPE_VOID) {
2180 mono_mb_emit_byte (mb, CEE_POP);
2181 mono_mb_emit_byte (mb, CEE_RET);
2183 mono_mb_emit_restore_result (mb, sig->ret);
2185 res = mono_mb_create_and_cache (cache, sig,
2186 mb, sig, sig->param_count + 16);
2193 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
2195 MonoMethodMessage *msg;
2196 MonoTransparentProxy *this;
2197 MonoObject *res, *exc;
2198 MonoArray *out_args;
2200 this = *((MonoTransparentProxy **)params [0]);
2203 g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
2205 /* skip the this pointer */
2208 if (this->remote_class->proxy_class->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
2211 MonoMethodSignature *sig = mono_method_signature (method);
2212 int count = sig->param_count;
2213 gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
2215 for (i=0; i<count; i++) {
2216 MonoClass *class = mono_class_from_mono_type (sig->params [i]);
2217 if (class->valuetype) {
2218 if (sig->params [i]->byref)
2219 mparams[i] = *((gpointer *)params [i]);
2221 mparams[i] = params [i];
2223 mparams[i] = *((gpointer**)params [i]);
2227 return mono_runtime_invoke (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this): this, mparams, NULL);
2230 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
2232 res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
2235 mono_raise_exception ((MonoException *)exc);
2237 mono_method_return_message_restore (method, params, out_args);
2243 mono_marshal_get_remoting_invoke (MonoMethod *method)
2245 MonoMethodSignature *sig;
2246 MonoMethodBuilder *mb;
2252 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
2255 sig = signature_no_pinvoke (mono_method_signature (method));
2257 /* we cant remote methods without this pointer */
2261 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE)))
2264 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
2265 mb->method->save_lmf = 1;
2267 params_var = mono_mb_emit_save_args (mb, sig, TRUE);
2269 mono_mb_emit_ptr (mb, method);
2270 mono_mb_emit_ldloc (mb, params_var);
2271 mono_mb_emit_icall (mb, mono_remoting_wrapper);
2272 emit_thread_interrupt_checkpoint (mb);
2274 if (sig->ret->type == MONO_TYPE_VOID) {
2275 mono_mb_emit_byte (mb, CEE_POP);
2276 mono_mb_emit_byte (mb, CEE_RET);
2278 mono_mb_emit_restore_result (mb, sig->ret);
2281 res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
2287 /* mono_get_xdomain_marshal_type()
2288 * Returns the kind of marshalling that a type needs for cross domain calls.
2290 static MonoXDomainMarshalType
2291 mono_get_xdomain_marshal_type (MonoType *t)
2294 case MONO_TYPE_VOID:
2295 g_assert_not_reached ();
2299 case MONO_TYPE_BOOLEAN:
2302 case MONO_TYPE_CHAR:
2309 return MONO_MARSHAL_NONE;
2310 case MONO_TYPE_STRING:
2311 return MONO_MARSHAL_COPY;
2312 case MONO_TYPE_ARRAY:
2313 case MONO_TYPE_SZARRAY: {
2314 MonoClass *elem_class = mono_class_from_mono_type (t)->element_class;
2315 if (mono_get_xdomain_marshal_type (&(elem_class->byval_arg)) != MONO_MARSHAL_SERIALIZE)
2316 return MONO_MARSHAL_COPY;
2321 if (mono_class_from_mono_type (t) == mono_defaults.stringbuilder_class)
2322 return MONO_MARSHAL_COPY;
2324 return MONO_MARSHAL_SERIALIZE;
2328 /* mono_marshal_xdomain_copy_value
2329 * Makes a copy of "val" suitable for the current domain.
2332 mono_marshal_xdomain_copy_value (MonoObject *val)
2335 if (val == NULL) return NULL;
2337 domain = mono_domain_get ();
2339 switch (mono_object_class (val)->byval_arg.type) {
2340 case MONO_TYPE_VOID:
2341 g_assert_not_reached ();
2345 case MONO_TYPE_BOOLEAN:
2348 case MONO_TYPE_CHAR:
2354 case MONO_TYPE_R8: {
2355 return mono_value_box (domain, mono_object_class (val), ((char*)val) + sizeof(MonoObject));
2357 case MONO_TYPE_STRING: {
2358 MonoString *str = (MonoString *) val;
2359 return (MonoObject *) mono_string_new_utf16 (domain, mono_string_chars (str), mono_string_length (str));
2361 case MONO_TYPE_ARRAY:
2362 case MONO_TYPE_SZARRAY: {
2364 MonoXDomainMarshalType mt = mono_get_xdomain_marshal_type (&(mono_object_class (val)->element_class->byval_arg));
2365 if (mt == MONO_MARSHAL_SERIALIZE) return NULL;
2366 acopy = mono_array_clone_in_domain (domain, (MonoArray *) val);
2367 if (mt == MONO_MARSHAL_COPY) {
2368 int i, len = mono_array_length (acopy);
2369 for (i = 0; i < len; i++) {
2370 MonoObject *item = mono_array_get (acopy, gpointer, i);
2371 mono_array_setref (acopy, i, mono_marshal_xdomain_copy_value (item));
2374 return (MonoObject *) acopy;
2378 if (mono_object_class (val) == mono_defaults.stringbuilder_class) {
2379 MonoStringBuilder *oldsb = (MonoStringBuilder *) val;
2380 MonoStringBuilder *newsb = (MonoStringBuilder *) mono_object_new (domain, mono_defaults.stringbuilder_class);
2381 MONO_OBJECT_SETREF (newsb, str, mono_string_new_utf16 (domain, mono_string_chars (oldsb->str), mono_string_length (oldsb->str)));
2382 newsb->length = oldsb->length;
2383 newsb->max_capacity = (gint32)0x7fffffff;
2384 return (MonoObject *) newsb;
2389 /* mono_marshal_xdomain_copy_out_value()
2390 * Copies the contents of the src instance into the dst instance. src and dst
2391 * must have the same type, and if they are arrays, the same size.
2394 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst)
2396 if (src == NULL || dst == NULL) return;
2398 g_assert (mono_object_class (src) == mono_object_class (dst));
2400 switch (mono_object_class (src)->byval_arg.type) {
2401 case MONO_TYPE_ARRAY:
2402 case MONO_TYPE_SZARRAY: {
2403 int mt = mono_get_xdomain_marshal_type (&(mono_object_class (src)->element_class->byval_arg));
2404 if (mt == MONO_MARSHAL_SERIALIZE) return;
2405 if (mt == MONO_MARSHAL_COPY) {
2406 int i, len = mono_array_length ((MonoArray *)dst);
2407 for (i = 0; i < len; i++) {
2408 MonoObject *item = mono_array_get ((MonoArray *)src, gpointer, i);
2409 mono_array_setref ((MonoArray *)dst, i, mono_marshal_xdomain_copy_value (item));
2412 mono_array_full_copy ((MonoArray *)src, (MonoArray *)dst);
2418 if (mono_object_class (src) == mono_defaults.stringbuilder_class) {
2419 MonoStringBuilder *src_sb = (MonoStringBuilder *) src;
2420 MonoStringBuilder *dst_sb = (MonoStringBuilder *) dst;
2422 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)));
2423 dst_sb->cached_str = NULL;
2424 dst_sb->length = src_sb->length;
2429 mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder *mb, MonoClass *pclass)
2431 mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_value);
2432 mono_mb_emit_byte (mb, CEE_CASTCLASS);
2433 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2437 mono_marshal_emit_xdomain_copy_out_value (MonoMethodBuilder *mb, MonoClass *pclass)
2439 mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_out_value);
2442 /* mono_marshal_supports_fast_xdomain()
2443 * Returns TRUE if the method can use the fast xdomain wrapper.
2446 mono_marshal_supports_fast_xdomain (MonoMethod *method)
2448 return !method->klass->contextbound &&
2449 !((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".ctor", method->name) == 0));
2453 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push)
2455 MonoDomain *current_domain = mono_domain_get ();
2456 MonoDomain *domain = mono_domain_get_by_id (id);
2458 if (!domain || !mono_domain_set (domain, FALSE))
2459 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2462 mono_thread_push_appdomain_ref (domain);
2464 mono_thread_pop_appdomain_ref ();
2466 return current_domain->domain_id;
2470 mono_marshal_emit_switch_domain (MonoMethodBuilder *mb)
2472 mono_mb_emit_icall (mb, mono_marshal_set_domain_by_id);
2475 /* mono_marshal_emit_load_domain_method ()
2476 * Loads into the stack a pointer to the code of the provided method for
2477 * the current domain.
2480 mono_marshal_emit_load_domain_method (MonoMethodBuilder *mb, MonoMethod *method)
2482 /* We need a pointer to the method for the running domain (not the domain
2483 * that compiles the method).
2485 mono_mb_emit_ptr (mb, method);
2486 mono_mb_emit_icall (mb, mono_compile_method);
2489 /* mono_marshal_get_xappdomain_dispatch ()
2490 * Generates a method that dispatches a method call from another domain into
2491 * the current domain.
2494 mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, int complex_count, int complex_out_count, int ret_marshal_type)
2496 MonoMethodSignature *sig, *csig;
2497 MonoMethodBuilder *mb;
2499 int i, j, param_index, copy_locals_base;
2500 MonoClass *ret_class = NULL;
2501 int loc_array=0, loc_return=0, loc_serialized_exc=0;
2502 MonoExceptionClause *main_clause;
2503 MonoMethodHeader *header;
2505 gboolean copy_return;
2507 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_DISPATCH)))
2510 sig = mono_method_signature (method);
2511 copy_return = (sig->ret->type != MONO_TYPE_VOID && ret_marshal_type != MONO_MARSHAL_SERIALIZE);
2514 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3 + sig->param_count - complex_count);
2515 csig->params [j++] = &mono_defaults.object_class->byval_arg;
2516 csig->params [j++] = &byte_array_class->this_arg;
2517 csig->params [j++] = &byte_array_class->this_arg;
2518 for (i = 0; i < sig->param_count; i++) {
2519 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE)
2520 csig->params [j++] = sig->params [i];
2523 csig->ret = sig->ret;
2525 csig->ret = &mono_defaults.void_class->byval_arg;
2527 csig->hasthis = FALSE;
2529 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_DISPATCH);
2530 mb->method->save_lmf = 1;
2534 loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
2535 if (complex_count > 0)
2536 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2537 if (sig->ret->type != MONO_TYPE_VOID) {
2538 loc_return = mono_mb_add_local (mb, sig->ret);
2539 ret_class = mono_class_from_mono_type (sig->ret);
2544 main_clause = g_new0 (MonoExceptionClause, 1);
2545 main_clause->try_offset = mb->pos;
2547 /* Clean the call context */
2549 mono_mb_emit_byte (mb, CEE_LDNULL);
2550 mono_mb_emit_managed_call (mb, method_set_call_context, NULL);
2551 mono_mb_emit_byte (mb, CEE_POP);
2553 /* Deserialize call data */
2555 mono_mb_emit_ldarg (mb, 1);
2556 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2557 mono_mb_emit_byte (mb, CEE_DUP);
2558 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
2560 mono_mb_emit_byte (mb, 0);
2562 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
2563 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
2565 if (complex_count > 0)
2566 mono_mb_emit_stloc (mb, loc_array);
2568 mono_mb_emit_byte (mb, CEE_POP);
2570 mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
2572 /* Get the target object */
2574 mono_mb_emit_ldarg (mb, 0);
2575 mono_mb_emit_managed_call (mb, method_rs_appdomain_target, NULL);
2577 /* Load the arguments */
2579 copy_locals_base = mb->locals;
2580 param_index = 3; // Index of the first non-serialized parameter of this wrapper
2582 for (i = 0; i < sig->param_count; i++) {
2583 MonoType *pt = sig->params [i];
2584 MonoClass *pclass = mono_class_from_mono_type (pt);
2585 switch (marshal_types [i]) {
2586 case MONO_MARSHAL_SERIALIZE: {
2587 /* take the value from the serialized array */
2588 mono_mb_emit_ldloc (mb, loc_array);
2589 mono_mb_emit_icon (mb, j++);
2591 if (pclass->valuetype) {
2592 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2593 mono_mb_emit_byte (mb, CEE_UNBOX);
2594 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2596 mono_mb_emit_byte (mb, CEE_LDELEMA);
2597 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2600 if (pclass->valuetype) {
2601 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2602 mono_mb_emit_byte (mb, CEE_UNBOX);
2603 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2604 mono_mb_emit_byte (mb, CEE_LDOBJ);
2605 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2607 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2608 if (pclass != mono_defaults.object_class) {
2609 mono_mb_emit_byte (mb, CEE_CASTCLASS);
2610 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2616 case MONO_MARSHAL_COPY_OUT: {
2617 /* Keep a local copy of the value since we need to copy it back after the call */
2618 int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
2619 mono_mb_emit_ldarg (mb, param_index++);
2620 mono_marshal_emit_xdomain_copy_value (mb, pclass);
2621 mono_mb_emit_byte (mb, CEE_DUP);
2622 mono_mb_emit_stloc (mb, copy_local);
2625 case MONO_MARSHAL_COPY: {
2626 mono_mb_emit_ldarg (mb, param_index);
2628 mono_mb_emit_byte (mb, CEE_DUP);
2629 mono_mb_emit_byte (mb, CEE_DUP);
2630 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2631 mono_marshal_emit_xdomain_copy_value (mb, pclass);
2632 mono_mb_emit_byte (mb, CEE_STIND_REF);
2634 mono_marshal_emit_xdomain_copy_value (mb, pclass);
2639 case MONO_MARSHAL_NONE:
2640 mono_mb_emit_ldarg (mb, param_index++);
2645 /* Make the call to the real object */
2647 emit_thread_force_interrupt_checkpoint (mb);
2649 mono_mb_emit_byte (mb, CEE_CALLVIRT);
2650 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
2652 if (sig->ret->type != MONO_TYPE_VOID)
2653 mono_mb_emit_stloc (mb, loc_return);
2655 /* copy back MONO_MARSHAL_COPY_OUT parameters */
2659 for (i = 0; i < sig->param_count; i++) {
2660 if (marshal_types [i] == MONO_MARSHAL_SERIALIZE) continue;
2661 if (marshal_types [i] == MONO_MARSHAL_COPY_OUT) {
2662 mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
2663 mono_mb_emit_ldarg (mb, param_index);
2664 mono_marshal_emit_xdomain_copy_out_value (mb, mono_class_from_mono_type (sig->params [i]));
2669 /* Serialize the return values */
2671 if (complex_out_count > 0) {
2672 /* Reset parameters in the array that don't need to be serialized back */
2674 for (i = 0; i < sig->param_count; i++) {
2675 if (marshal_types[i] != MONO_MARSHAL_SERIALIZE) continue;
2676 if (!sig->params [i]->byref) {
2677 mono_mb_emit_ldloc (mb, loc_array);
2678 mono_mb_emit_icon (mb, j);
2679 mono_mb_emit_byte (mb, CEE_LDNULL);
2680 mono_mb_emit_byte (mb, CEE_STELEM_REF);
2685 /* Add the return value to the array */
2687 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
2688 mono_mb_emit_ldloc (mb, loc_array);
2689 mono_mb_emit_icon (mb, complex_count); /* The array has an additional slot to hold the ret value */
2690 mono_mb_emit_ldloc (mb, loc_return);
2691 if (ret_class->valuetype) {
2692 mono_mb_emit_byte (mb, CEE_BOX);
2693 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
2695 mono_mb_emit_byte (mb, CEE_STELEM_REF);
2700 mono_mb_emit_ldarg (mb, 1);
2701 mono_mb_emit_ldloc (mb, loc_array);
2702 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
2703 mono_mb_emit_byte (mb, CEE_STIND_REF);
2704 } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
2705 mono_mb_emit_ldarg (mb, 1);
2706 mono_mb_emit_ldloc (mb, loc_return);
2707 if (ret_class->valuetype) {
2708 mono_mb_emit_byte (mb, CEE_BOX);
2709 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
2711 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
2712 mono_mb_emit_byte (mb, CEE_STIND_REF);
2714 mono_mb_emit_ldarg (mb, 1);
2715 mono_mb_emit_byte (mb, CEE_LDNULL);
2716 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
2717 mono_mb_emit_byte (mb, CEE_STIND_REF);
2720 mono_mb_emit_ldarg (mb, 2);
2721 mono_mb_emit_byte (mb, CEE_LDNULL);
2722 mono_mb_emit_byte (mb, CEE_STIND_REF);
2723 mono_mb_emit_byte (mb, CEE_LEAVE);
2724 pos_leave = mb->pos;
2725 mono_mb_emit_i4 (mb, 0);
2727 /* Main exception catch */
2728 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2729 main_clause->try_len = mb->pos - main_clause->try_offset;
2730 main_clause->data.catch_class = mono_defaults.object_class;
2733 main_clause->handler_offset = mb->pos;
2734 mono_mb_emit_managed_call (mb, method_rs_serialize_exc, NULL);
2735 mono_mb_emit_stloc (mb, loc_serialized_exc);
2736 mono_mb_emit_ldarg (mb, 2);
2737 mono_mb_emit_ldloc (mb, loc_serialized_exc);
2738 mono_mb_emit_byte (mb, CEE_STIND_REF);
2739 mono_mb_emit_byte (mb, CEE_LEAVE);
2740 mono_mb_emit_i4 (mb, 0);
2741 main_clause->handler_len = mb->pos - main_clause->handler_offset;
2744 mono_mb_patch_addr (mb, pos_leave, mb->pos - (pos_leave + 4));
2747 mono_mb_emit_ldloc (mb, loc_return);
2749 mono_mb_emit_byte (mb, CEE_RET);
2751 res = mono_remoting_mb_create_and_cache (method, mb, csig, csig->param_count + 16);
2754 header = ((MonoMethodNormal *)res)->header;
2755 header->num_clauses = 1;
2756 header->clauses = main_clause;
2761 /* mono_marshal_get_xappdomain_invoke ()
2762 * Generates a fast remoting wrapper for cross app domain calls.
2765 mono_marshal_get_xappdomain_invoke (MonoMethod *method)
2767 MonoMethodSignature *sig;
2768 MonoMethodBuilder *mb;
2770 int i, j, complex_count, complex_out_count, copy_locals_base;
2772 MonoClass *ret_class = NULL;
2773 MonoMethod *xdomain_method;
2774 int ret_marshal_type = MONO_MARSHAL_NONE;
2775 int loc_array=0, loc_serialized_data=-1, loc_real_proxy;
2776 int loc_old_domainid, loc_return=0, loc_serialized_exc=0, loc_context;
2778 gboolean copy_return = FALSE;
2782 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
2785 /* we cant remote methods without this pointer */
2786 if (!mono_method_signature (method)->hasthis)
2789 if (!mono_marshal_supports_fast_xdomain (method))
2790 return mono_marshal_get_remoting_invoke (method);
2792 mono_remoting_marshal_init ();
2794 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE)))
2797 sig = signature_no_pinvoke (mono_method_signature (method));
2799 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE);
2800 mb->method->save_lmf = 1;
2802 /* Count the number of parameters that need to be serialized */
2804 marshal_types = alloca (sizeof (int) * sig->param_count);
2805 complex_count = complex_out_count = 0;
2806 for (i = 0; i < sig->param_count; i++) {
2807 MonoType *ptype = sig->params[i];
2808 int mt = mono_get_xdomain_marshal_type (ptype);
2810 /* If the [Out] attribute is applied to a parameter that can be internally copied,
2811 * the copy will be made by reusing the original object instance
2813 if ((ptype->attrs & PARAM_ATTRIBUTE_OUT) != 0 && mt == MONO_MARSHAL_COPY && !ptype->byref)
2814 mt = MONO_MARSHAL_COPY_OUT;
2815 else if (mt == MONO_MARSHAL_SERIALIZE) {
2817 if (ptype->byref) complex_out_count++;
2819 marshal_types [i] = mt;
2822 if (sig->ret->type != MONO_TYPE_VOID) {
2823 ret_marshal_type = mono_get_xdomain_marshal_type (sig->ret);
2824 ret_class = mono_class_from_mono_type (sig->ret);
2825 copy_return = ret_marshal_type != MONO_MARSHAL_SERIALIZE;
2830 if (complex_count > 0)
2831 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2832 loc_serialized_data = mono_mb_add_local (mb, &byte_array_class->byval_arg);
2833 loc_real_proxy = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2835 loc_return = mono_mb_add_local (mb, sig->ret);
2836 loc_old_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2837 loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
2838 loc_context = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2840 /* Save thread domain data */
2842 mono_mb_emit_icall (mb, mono_context_get);
2843 mono_mb_emit_byte (mb, CEE_DUP);
2844 mono_mb_emit_stloc (mb, loc_context);
2846 /* If the thread is not running in the default context, it needs to go
2847 * through the whole remoting sink, since the context is going to change
2849 mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL);
2850 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
2852 mono_mb_emit_byte (mb, 0);
2854 mono_mb_emit_ldarg (mb, 0);
2855 for (i = 0; i < sig->param_count; i++)
2856 mono_mb_emit_ldarg (mb, i + 1);
2858 mono_mb_emit_managed_call (mb, mono_marshal_get_remoting_invoke (method), NULL);
2859 mono_mb_emit_byte (mb, CEE_RET);
2860 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
2862 /* Create the array that will hold the parameters to be serialized */
2864 if (complex_count > 0) {
2865 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 */
2866 mono_mb_emit_byte (mb, CEE_NEWARR);
2867 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.object_class));
2870 for (i = 0; i < sig->param_count; i++) {
2872 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
2873 pclass = mono_class_from_mono_type (sig->params[i]);
2874 mono_mb_emit_byte (mb, CEE_DUP);
2875 mono_mb_emit_icon (mb, j);
2876 mono_mb_emit_ldarg (mb, i + 1); /* 0=this */
2877 if (sig->params[i]->byref) {
2878 if (pclass->valuetype) {
2879 mono_mb_emit_byte (mb, CEE_LDOBJ);
2880 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2882 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2885 if (pclass->valuetype) {
2886 mono_mb_emit_byte (mb, CEE_BOX);
2887 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
2889 mono_mb_emit_byte (mb, CEE_STELEM_REF);
2892 mono_mb_emit_stloc (mb, loc_array);
2894 /* Serialize parameters */
2896 mono_mb_emit_ldloc (mb, loc_array);
2897 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
2898 mono_mb_emit_stloc (mb, loc_serialized_data);
2900 mono_mb_emit_byte (mb, CEE_LDNULL);
2901 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
2902 mono_mb_emit_stloc (mb, loc_serialized_data);
2905 /* Get the target domain id */
2907 mono_mb_emit_ldarg (mb, 0);
2908 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
2909 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2910 mono_mb_emit_byte (mb, CEE_DUP);
2911 mono_mb_emit_stloc (mb, loc_real_proxy);
2913 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
2914 mono_mb_emit_byte (mb, CEE_LDIND_I4);
2915 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2919 mono_marshal_emit_switch_domain (mb);
2920 mono_mb_emit_stloc (mb, loc_old_domainid);
2922 /* Load the arguments */
2924 mono_mb_emit_ldloc (mb, loc_real_proxy);
2925 mono_mb_emit_ldloc_addr (mb, loc_serialized_data);
2926 mono_mb_emit_ldloc_addr (mb, loc_serialized_exc);
2928 copy_locals_base = mb->locals;
2929 for (i = 0; i < sig->param_count; i++) {
2930 switch (marshal_types [i]) {
2931 case MONO_MARSHAL_SERIALIZE:
2933 case MONO_MARSHAL_COPY: {
2934 mono_mb_emit_ldarg (mb, i+1);
2935 if (sig->params [i]->byref) {
2936 /* make a local copy of the byref parameter. The real parameter
2937 * will be updated after the xdomain call
2939 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
2940 int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
2941 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2942 mono_mb_emit_stloc (mb, copy_local);
2943 mono_mb_emit_ldloc_addr (mb, copy_local);
2947 case MONO_MARSHAL_COPY_OUT:
2948 case MONO_MARSHAL_NONE:
2949 mono_mb_emit_ldarg (mb, i+1);
2954 /* Make the call to the invoke wrapper in the target domain */
2956 xdomain_method = mono_marshal_get_xappdomain_dispatch (method, marshal_types, complex_count, complex_out_count, ret_marshal_type);
2957 mono_marshal_emit_load_domain_method (mb, xdomain_method);
2958 mono_mb_emit_calli (mb, mono_method_signature (xdomain_method));
2961 mono_mb_emit_stloc (mb, loc_return);
2965 mono_mb_emit_ldloc (mb, loc_old_domainid);
2966 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2967 mono_marshal_emit_switch_domain (mb);
2968 mono_mb_emit_byte (mb, CEE_POP);
2970 /* Restore thread domain data */
2972 mono_mb_emit_ldloc (mb, loc_context);
2973 mono_mb_emit_icall (mb, mono_context_set);
2975 /* if (loc_serialized_exc != null) ... */
2977 mono_mb_emit_ldloc (mb, loc_serialized_exc);
2978 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
2980 mono_mb_emit_byte (mb, 0);
2982 mono_mb_emit_ldloc (mb, loc_serialized_exc);
2983 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
2984 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
2985 mono_mb_emit_byte (mb, CEE_CASTCLASS);
2986 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.exception_class));
2987 mono_mb_emit_managed_call (mb, method_exc_fixexc, NULL);
2988 mono_mb_emit_byte (mb, CEE_THROW);
2989 mono_mb_patch_addr_s (mb, pos_noex, mb->pos - pos_noex - 1);
2991 /* copy back non-serialized output parameters */
2994 for (i = 0; i < sig->param_count; i++) {
2995 if (!sig->params [i]->byref || marshal_types [i] != MONO_MARSHAL_COPY) continue;
2996 mono_mb_emit_ldarg (mb, i + 1);
2997 mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
2998 mono_marshal_emit_xdomain_copy_value (mb, mono_class_from_mono_type (sig->params [i]));
2999 mono_mb_emit_byte (mb, CEE_STIND_REF);
3002 /* Deserialize out parameters */
3004 if (complex_out_count > 0) {
3005 mono_mb_emit_ldloc (mb, loc_serialized_data);
3006 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3007 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3008 mono_mb_emit_stloc (mb, loc_array);
3010 /* Copy back output parameters and return type */
3013 for (i = 0; i < sig->param_count; i++) {
3014 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
3015 if (sig->params[i]->byref) {
3016 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
3017 mono_mb_emit_ldarg (mb, i + 1);
3018 mono_mb_emit_ldloc (mb, loc_array);
3019 mono_mb_emit_icon (mb, j);
3020 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3021 if (pclass->valuetype) {
3022 mono_mb_emit_byte (mb, CEE_UNBOX);
3023 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
3024 mono_mb_emit_byte (mb, CEE_LDOBJ);
3025 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
3026 mono_mb_emit_byte (mb, CEE_STOBJ);
3027 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
3029 if (pclass != mono_defaults.object_class) {
3030 mono_mb_emit_byte (mb, CEE_CASTCLASS);
3031 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass));
3033 mono_mb_emit_byte (mb, CEE_STIND_REF);
3039 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
3040 mono_mb_emit_ldloc (mb, loc_array);
3041 mono_mb_emit_icon (mb, complex_count);
3042 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3043 if (ret_class->valuetype) {
3044 mono_mb_emit_byte (mb, CEE_UNBOX);
3045 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
3046 mono_mb_emit_byte (mb, CEE_LDOBJ);
3047 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
3050 } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
3051 mono_mb_emit_ldloc (mb, loc_serialized_data);
3052 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3053 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3054 if (ret_class->valuetype) {
3055 mono_mb_emit_byte (mb, CEE_UNBOX);
3056 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
3057 mono_mb_emit_byte (mb, CEE_LDOBJ);
3058 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
3059 } else if (ret_class != mono_defaults.object_class) {
3060 mono_mb_emit_byte (mb, CEE_CASTCLASS);
3061 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class));
3064 mono_mb_emit_ldloc (mb, loc_serialized_data);
3065 mono_mb_emit_byte (mb, CEE_DUP);
3066 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
3068 mono_mb_emit_byte (mb, 0);
3069 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3071 mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
3072 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3073 mono_mb_emit_byte (mb, CEE_POP);
3077 mono_mb_emit_ldloc (mb, loc_return);
3078 if (ret_marshal_type == MONO_MARSHAL_COPY)
3079 mono_marshal_emit_xdomain_copy_value (mb, ret_class);
3082 mono_mb_emit_byte (mb, CEE_RET);
3084 res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
3091 mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTarget target_type)
3093 if (target_type == MONO_REMOTING_TARGET_APPDOMAIN)
3094 return mono_marshal_get_xappdomain_invoke (method);
3096 return mono_marshal_get_remoting_invoke (method);
3099 G_GNUC_UNUSED static gpointer
3100 mono_marshal_load_remoting_wrapper (MonoRealProxy *rp, MonoMethod *method)
3102 if (rp->target_domain_id != -1)
3103 return mono_compile_method (mono_marshal_get_xappdomain_invoke (method));
3105 return mono_compile_method (mono_marshal_get_remoting_invoke (method));
3109 mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
3111 MonoMethodSignature *sig;
3112 MonoMethodBuilder *mb;
3113 MonoMethod *res, *native;
3114 int i, pos, pos_rem;
3118 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
3121 sig = signature_no_pinvoke (mono_method_signature (method));
3123 /* we cant remote methods without this pointer */
3124 g_assert (sig->hasthis);
3126 if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
3129 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
3131 for (i = 0; i <= sig->param_count; i++)
3132 mono_mb_emit_ldarg (mb, i);
3134 mono_mb_emit_ldarg (mb, 0);
3135 pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3137 if (mono_marshal_supports_fast_xdomain (method)) {
3138 mono_mb_emit_ldarg (mb, 0);
3139 pos_rem = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
3141 /* wrapper for cross app domain calls */
3142 native = mono_marshal_get_xappdomain_invoke (method);
3143 mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
3144 mono_mb_emit_byte (mb, CEE_RET);
3146 mono_mb_patch_addr (mb, pos_rem, mb->pos - (pos_rem + 4));
3148 /* wrapper for normal remote calls */
3149 native = mono_marshal_get_remoting_invoke (method);
3150 mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
3151 mono_mb_emit_byte (mb, CEE_RET);
3154 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3155 mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
3156 mono_mb_emit_byte (mb, CEE_RET);
3158 res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
3165 * the returned method invokes all methods in a multicast delegate
3168 mono_marshal_get_delegate_invoke (MonoMethod *method)
3170 MonoMethodSignature *sig, *static_sig;
3172 MonoMethodBuilder *mb;
3178 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
3179 !strcmp (method->name, "Invoke"));
3181 sig = signature_no_pinvoke (mono_method_signature (method));
3183 cache = method->klass->image->delegate_invoke_cache;
3184 if ((res = mono_marshal_find_in_cache (cache, sig)))
3187 static_sig = mono_metadata_signature_dup (sig);
3188 static_sig->hasthis = 0;
3190 name = mono_signature_to_name (sig, "invoke");
3191 mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_INVOKE);
3194 /* allocate local 0 (object) */
3195 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3197 g_assert (sig->hasthis);
3201 * prev.Invoke( args .. );
3202 * return this.<target>( args .. );
3205 /* this wrapper can be used in unmanaged-managed transitions */
3206 emit_thread_interrupt_checkpoint (mb);
3208 /* get this->prev */
3209 mono_mb_emit_ldarg (mb, 0);
3210 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
3211 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3212 mono_mb_emit_stloc (mb, 0);
3214 /* if prev != null */
3215 mono_mb_emit_ldloc (mb, 0);
3216 mono_mb_emit_byte (mb, CEE_BRFALSE);
3219 mono_mb_emit_i4 (mb, 0);
3222 mono_mb_emit_ldloc (mb, 0);
3223 for (i = 0; i < sig->param_count; i++)
3224 mono_mb_emit_ldarg (mb, i + 1);
3225 mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
3226 if (sig->ret->type != MONO_TYPE_VOID)
3227 mono_mb_emit_byte (mb, CEE_POP);
3229 /* continued or prev == null */
3230 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
3232 /* get this->target */
3233 mono_mb_emit_ldarg (mb, 0);
3234 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, target));
3235 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3236 mono_mb_emit_stloc (mb, 0);
3238 /* if target != null */
3239 mono_mb_emit_ldloc (mb, 0);
3240 mono_mb_emit_byte (mb, CEE_BRFALSE);
3242 mono_mb_emit_i4 (mb, 0);
3244 /* then call this->method_ptr nonstatic */
3245 mono_mb_emit_ldloc (mb, 0);
3246 for (i = 0; i < sig->param_count; ++i)
3247 mono_mb_emit_ldarg (mb, i + 1);
3248 mono_mb_emit_ldarg (mb, 0);
3249 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
3250 mono_mb_emit_byte (mb, CEE_LDIND_I );
3251 mono_mb_emit_byte (mb, CEE_CALLI);
3252 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
3254 mono_mb_emit_byte (mb, CEE_BR);
3256 mono_mb_emit_i4 (mb, 0);
3258 /* else [target == null] call this->method_ptr static */
3259 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
3261 for (i = 0; i < sig->param_count; ++i)
3262 mono_mb_emit_ldarg (mb, i + 1);
3263 mono_mb_emit_ldarg (mb, 0);
3264 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
3265 mono_mb_emit_byte (mb, CEE_LDIND_I );
3266 mono_mb_emit_byte (mb, CEE_CALLI);
3267 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
3270 mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
3271 mono_mb_emit_byte (mb, CEE_RET);
3273 res = mono_mb_create_and_cache (cache, sig,
3274 mb, sig, sig->param_count + 16);
3281 * signature_dup_add_this:
3283 * Make a copy of @sig, adding an explicit this argument.
3285 static MonoMethodSignature*
3286 signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass)
3288 MonoMethodSignature *res;
3291 res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1);
3292 memcpy (res, sig, sizeof (MonoMethodSignature));
3293 res->param_count = sig->param_count + 1;
3294 res->hasthis = FALSE;
3295 for (i = sig->param_count - 1; i >= 0; i --)
3296 res->params [i + 1] = sig->params [i];
3297 res->params [0] = &mono_ptr_class_get (&klass->byval_arg)->byval_arg;
3304 MonoMethodSignature *sig;
3310 * generates IL code for the runtime invoke function
3311 * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
3313 * we also catch exceptions if exc != null
3316 mono_marshal_get_runtime_invoke (MonoMethod *method)
3318 MonoMethodSignature *sig, *csig, *callsig;
3319 MonoExceptionClause *clause;
3320 MonoMethodHeader *header;
3321 MonoMethodBuilder *mb;
3322 GHashTable *cache = NULL;
3323 MonoClass *target_klass;
3324 MonoMethod *res = NULL;
3326 static MonoString *string_dummy = NULL;
3327 static MonoMethodSignature *dealy_abort_sig = NULL;
3333 target_klass = method->klass;
3335 mono_marshal_lock ();
3337 if (method->string_ctor) {
3338 static GSList *strsig_list = NULL;
3342 for (item = strsig_list; item; item = item->next) {
3344 if (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cs->ctor))) {
3350 callsig = mono_metadata_signature_dup (mono_method_signature (method));
3351 callsig->ret = &mono_defaults.string_class->byval_arg;
3352 cs = g_new (CtorSigPair, 1);
3355 strsig_list = g_slist_prepend (strsig_list, cs);
3358 if (method->klass->valuetype && mono_method_signature (method)->hasthis) {
3360 * Valuetype methods receive a managed pointer as the this argument.
3361 * Create a new signature to reflect this.
3363 callsig = signature_dup_add_this (mono_method_signature (method), method->klass);
3365 callsig = mono_method_signature (method);
3369 cache = method->klass->image->runtime_invoke_cache;
3371 /* from mono_marshal_find_in_cache */
3372 res = g_hash_table_lookup (cache, callsig);
3373 mono_marshal_unlock ();
3379 if (!dealy_abort_sig) {
3380 dealy_abort_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
3381 dealy_abort_sig->ret = &mono_defaults.void_class->byval_arg;
3382 dealy_abort_sig->pinvoke = 0;
3385 target_klass = mono_defaults.object_class;
3387 /* to make it work with our special string constructors */
3388 if (!string_dummy) {
3389 MONO_GC_REGISTER_ROOT (string_dummy);
3390 string_dummy = mono_string_new_wrapper ("dummy");
3393 sig = mono_method_signature (method);
3395 csig = mono_metadata_signature_alloc (method->klass->image, 4);
3397 csig->ret = &mono_defaults.object_class->byval_arg;
3398 if (method->klass->valuetype && mono_method_signature (method)->hasthis)
3399 csig->params [0] = callsig->params [0];
3401 csig->params [0] = &mono_defaults.object_class->byval_arg;
3402 csig->params [1] = &mono_defaults.int_class->byval_arg;
3403 csig->params [2] = &mono_defaults.int_class->byval_arg;
3404 csig->params [3] = &mono_defaults.int_class->byval_arg;
3406 name = mono_signature_to_name (callsig, "runtime_invoke");
3407 mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE);
3410 /* allocate local 0 (object) tmp */
3411 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3412 /* allocate local 1 (object) exc */
3413 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3415 /* cond set *exc to null */
3416 mono_mb_emit_byte (mb, CEE_LDARG_2);
3417 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
3418 mono_mb_emit_byte (mb, 3);
3419 mono_mb_emit_byte (mb, CEE_LDARG_2);
3420 mono_mb_emit_byte (mb, CEE_LDNULL);
3421 mono_mb_emit_byte (mb, CEE_STIND_I);
3423 emit_thread_force_interrupt_checkpoint (mb);
3426 if (method->string_ctor) {
3427 mono_mb_emit_ptr (mb, string_dummy);
3429 mono_mb_emit_ldarg (mb, 0);
3433 for (i = 0; i < sig->param_count; i++) {
3434 MonoType *t = sig->params [i];
3437 mono_mb_emit_ldarg (mb, 1);
3439 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
3440 mono_mb_emit_byte (mb, CEE_ADD);
3442 mono_mb_emit_byte (mb, CEE_LDIND_I);
3447 type = sig->params [i]->type;
3451 mono_mb_emit_byte (mb, CEE_LDIND_I1);
3453 case MONO_TYPE_BOOLEAN:
3455 mono_mb_emit_byte (mb, CEE_LDIND_U1);
3458 mono_mb_emit_byte (mb, CEE_LDIND_I2);
3461 case MONO_TYPE_CHAR:
3462 mono_mb_emit_byte (mb, CEE_LDIND_U2);
3466 mono_mb_emit_byte (mb, CEE_LDIND_I);
3469 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3472 mono_mb_emit_byte (mb, CEE_LDIND_U4);
3475 mono_mb_emit_byte (mb, CEE_LDIND_R4);
3478 mono_mb_emit_byte (mb, CEE_LDIND_R8);
3482 mono_mb_emit_byte (mb, CEE_LDIND_I8);
3484 case MONO_TYPE_STRING:
3485 case MONO_TYPE_CLASS:
3486 case MONO_TYPE_ARRAY:
3488 case MONO_TYPE_SZARRAY:
3489 case MONO_TYPE_OBJECT:
3492 case MONO_TYPE_VALUETYPE:
3493 if (t->data.klass->enumtype) {
3494 type = t->data.klass->enum_basetype->type;
3497 if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3498 /* Need to convert a boxed vtype to an mp to a Nullable struct */
3499 mono_mb_emit_byte (mb, CEE_UNBOX);
3500 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->params [i])));
3501 mono_mb_emit_byte (mb, CEE_LDOBJ);
3502 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->params [i])));
3504 mono_mb_emit_byte (mb, CEE_LDOBJ);
3505 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
3508 case MONO_TYPE_GENERICINST:
3509 t = &t->data.generic_class->container_class->byval_arg;
3513 g_assert_not_reached ();
3517 mono_mb_emit_ldarg (mb, 3);
3518 mono_mb_emit_calli (mb, callsig);
3520 if (sig->ret->byref) {
3522 g_assert_not_reached ();
3526 switch (sig->ret->type) {
3527 case MONO_TYPE_VOID:
3528 if (!method->string_ctor)
3529 mono_mb_emit_byte (mb, CEE_LDNULL);
3531 case MONO_TYPE_BOOLEAN:
3532 case MONO_TYPE_CHAR:
3545 case MONO_TYPE_VALUETYPE:
3546 case MONO_TYPE_TYPEDBYREF:
3547 case MONO_TYPE_GENERICINST:
3548 /* box value types */
3549 mono_mb_emit_byte (mb, CEE_BOX);
3550 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret)));
3552 case MONO_TYPE_STRING:
3553 case MONO_TYPE_CLASS:
3554 case MONO_TYPE_ARRAY:
3555 case MONO_TYPE_SZARRAY:
3556 case MONO_TYPE_OBJECT:
3561 g_assert_not_reached ();
3564 mono_mb_emit_stloc (mb, 0);
3566 mono_mb_emit_byte (mb, CEE_LEAVE);
3568 mono_mb_emit_i4 (mb, 0);
3570 clause = g_new0 (MonoExceptionClause, 1);
3571 clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
3572 clause->try_len = mb->pos;
3575 clause->data.filter_offset = mb->pos;
3577 mono_mb_emit_byte (mb, CEE_POP);
3578 mono_mb_emit_byte (mb, CEE_LDARG_2);
3579 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3580 mono_mb_emit_byte (mb, CEE_PREFIX1);
3581 mono_mb_emit_byte (mb, CEE_CGT_UN);
3582 mono_mb_emit_byte (mb, CEE_PREFIX1);
3583 mono_mb_emit_byte (mb, CEE_ENDFILTER);
3585 clause->handler_offset = mb->pos;
3588 /* store exception */
3589 mono_mb_emit_stloc (mb, 1);
3591 mono_mb_emit_byte (mb, CEE_LDARG_2);
3592 mono_mb_emit_ldloc (mb, 1);
3593 mono_mb_emit_byte (mb, CEE_STIND_I);
3595 mono_mb_emit_byte (mb, CEE_LDNULL);
3596 mono_mb_emit_stloc (mb, 0);
3598 /* Check for the abort exception */
3599 mono_mb_emit_ldloc (mb, 1);
3600 mono_mb_emit_byte (mb, CEE_ISINST);
3601 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.threadabortexception_class));
3602 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
3604 mono_mb_emit_byte (mb, 0);
3606 /* Delay the abort exception */
3607 mono_mb_emit_native_call (mb, dealy_abort_sig, ves_icall_System_Threading_Thread_ResetAbort);
3609 mono_mb_patch_addr_s (mb, posna, mb->pos - posna - 1);
3610 mono_mb_emit_byte (mb, CEE_LEAVE);
3611 mono_mb_emit_i4 (mb, 0);
3613 clause->handler_len = mb->pos - clause->handler_offset;
3616 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3617 mono_mb_emit_ldloc (mb, 0);
3618 mono_mb_emit_byte (mb, CEE_RET);
3620 /* taken from mono_mb_create_and_cache */
3621 mono_marshal_lock ();
3623 res = g_hash_table_lookup (cache, callsig);
3624 /* Somebody may have created it before us */
3626 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
3627 g_hash_table_insert (cache, callsig, res);
3628 g_hash_table_insert (wrapper_hash, res, callsig);
3631 mono_marshal_unlock ();
3632 /* end mono_mb_create_and_cache */
3636 header = ((MonoMethodNormal *)res)->header;
3637 header->num_clauses = 1;
3638 header->clauses = clause;
3644 mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
3646 char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
3647 klass->name_space, klass->name);
3649 mono_mb_emit_exception_marshal_directive (mb, msg);
3653 * mono_marshal_get_ldfld_remote_wrapper:
3654 * @klass: The return type
3656 * This method generates a wrapper for calling mono_load_remote_field_new with
3657 * the appropriate return type.
3660 mono_marshal_get_ldfld_remote_wrapper (MonoClass *klass)
3662 MonoMethodSignature *sig, *csig;
3663 MonoMethodBuilder *mb;
3665 static GHashTable *ldfld_hash = NULL;
3668 mono_marshal_lock ();
3670 ldfld_hash = g_hash_table_new (NULL, NULL);
3671 res = g_hash_table_lookup (ldfld_hash, klass);
3672 mono_marshal_unlock ();
3677 * This wrapper is similar to an icall wrapper but all the wrappers
3678 * call the same C function, but with a different signature.
3680 name = g_strdup_printf ("__mono_load_remote_field_new_wrapper_%s.%s", klass->name_space, klass->name);
3681 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD_REMOTE);
3684 mb->method->save_lmf = 1;
3686 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
3687 sig->params [0] = &mono_defaults.object_class->byval_arg;
3688 sig->params [1] = &mono_defaults.int_class->byval_arg;
3689 sig->params [2] = &mono_defaults.int_class->byval_arg;
3690 sig->ret = &klass->this_arg;
3692 mono_mb_emit_ldarg (mb, 0);
3693 mono_mb_emit_ldarg (mb, 1);
3694 mono_mb_emit_ldarg (mb, 2);
3696 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
3697 csig->params [0] = &mono_defaults.object_class->byval_arg;
3698 csig->params [1] = &mono_defaults.int_class->byval_arg;
3699 csig->params [2] = &mono_defaults.int_class->byval_arg;
3700 csig->ret = &klass->this_arg;
3703 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
3704 emit_thread_interrupt_checkpoint (mb);
3706 mono_mb_emit_byte (mb, CEE_RET);
3708 res = mono_mb_create_and_cache (ldfld_hash, klass,
3709 mb, sig, sig->param_count + 16);
3716 * mono_marshal_get_ldfld_wrapper:
3717 * @type: the type of the field
3719 * This method generates a function which can be use to load a field with type
3720 * @type from an object. The generated function has the following signature:
3721 * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
3724 mono_marshal_get_ldfld_wrapper (MonoType *type)
3726 MonoMethodSignature *sig;
3727 MonoMethodBuilder *mb;
3730 static GHashTable *ldfld_hash = NULL;
3732 int t, pos0, pos1 = 0;
3734 type = mono_type_get_underlying_type (type);
3739 if (type->type == MONO_TYPE_SZARRAY) {
3740 klass = mono_defaults.array_class;
3741 } else if (type->type == MONO_TYPE_VALUETYPE) {
3742 klass = type->data.klass;
3743 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
3744 klass = mono_defaults.object_class;
3745 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
3746 klass = mono_defaults.int_class;
3747 } else if (t == MONO_TYPE_GENERICINST) {
3748 if (mono_type_generic_inst_is_valuetype (type))
3749 klass = mono_class_from_mono_type (type);
3751 klass = mono_defaults.object_class;
3753 klass = mono_class_from_mono_type (type);
3756 klass = mono_defaults.int_class;
3759 mono_marshal_lock ();
3761 ldfld_hash = g_hash_table_new (NULL, NULL);
3762 res = g_hash_table_lookup (ldfld_hash, klass);
3763 mono_marshal_unlock ();
3767 /* we add the %p pointer value of klass because class names are not unique */
3768 name = g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name);
3769 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
3772 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
3773 sig->params [0] = &mono_defaults.object_class->byval_arg;
3774 sig->params [1] = &mono_defaults.int_class->byval_arg;
3775 sig->params [2] = &mono_defaults.int_class->byval_arg;
3776 sig->params [3] = &mono_defaults.int_class->byval_arg;
3777 sig->ret = &klass->byval_arg;
3779 mono_mb_emit_ldarg (mb, 0);
3780 pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3782 mono_mb_emit_ldarg (mb, 0);
3783 mono_mb_emit_ldarg (mb, 1);
3784 mono_mb_emit_ldarg (mb, 2);
3786 mono_mb_emit_managed_call (mb, mono_marshal_get_ldfld_remote_wrapper (klass), NULL);
3789 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
3790 csig->params [0] = &mono_defaults.object_class->byval_arg;
3791 csig->params [1] = &mono_defaults.int_class->byval_arg;
3792 csig->params [2] = &mono_defaults.int_class->byval_arg;
3793 csig->ret = &klass->this_arg;
3796 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
3797 emit_thread_interrupt_checkpoint (mb);
3800 if (klass->valuetype) {
3801 mono_mb_emit_byte (mb, CEE_UNBOX);
3802 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3803 mono_mb_emit_byte (mb, CEE_BR);
3805 mono_mb_emit_i4 (mb, 0);
3807 mono_mb_emit_byte (mb, CEE_RET);
3811 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
3813 mono_mb_emit_ldarg (mb, 0);
3814 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3815 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3816 mono_mb_emit_ldarg (mb, 3);
3817 mono_mb_emit_byte (mb, CEE_ADD);
3819 if (klass->valuetype)
3820 mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
3825 case MONO_TYPE_BOOLEAN:
3826 mono_mb_emit_byte (mb, CEE_LDIND_I1);
3828 case MONO_TYPE_CHAR:
3831 mono_mb_emit_byte (mb, CEE_LDIND_I2);
3835 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3839 mono_mb_emit_byte (mb, CEE_LDIND_I8);
3842 mono_mb_emit_byte (mb, CEE_LDIND_R4);
3845 mono_mb_emit_byte (mb, CEE_LDIND_R8);
3847 case MONO_TYPE_ARRAY:
3848 case MONO_TYPE_SZARRAY:
3849 case MONO_TYPE_OBJECT:
3850 case MONO_TYPE_CLASS:
3851 case MONO_TYPE_STRING:
3852 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3857 case MONO_TYPE_FNPTR:
3858 mono_mb_emit_byte (mb, CEE_LDIND_I);
3860 case MONO_TYPE_VALUETYPE:
3861 g_assert (!klass->enumtype);
3862 mono_mb_emit_byte (mb, CEE_LDOBJ);
3863 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3865 case MONO_TYPE_GENERICINST:
3866 if (mono_type_generic_inst_is_valuetype (type)) {
3867 mono_mb_emit_byte (mb, CEE_LDOBJ);
3868 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3870 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3874 g_warning ("type %x not implemented", type->type);
3875 g_assert_not_reached ();
3878 mono_mb_emit_byte (mb, CEE_RET);
3880 res = mono_mb_create_and_cache (ldfld_hash, klass,
3881 mb, sig, sig->param_count + 16);
3888 * mono_marshal_get_ldflda_wrapper:
3889 * @type: the type of the field
3891 * This method generates a function which can be used to load a field address
3892 * from an object. The generated function has the following signature:
3893 * gpointer ldflda_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset);
3896 mono_marshal_get_ldflda_wrapper (MonoType *type)
3898 MonoMethodSignature *sig;
3899 MonoMethodBuilder *mb;
3902 static GHashTable *ldflda_hash = NULL;
3906 type = mono_type_get_underlying_type (type);
3910 if (type->type == MONO_TYPE_SZARRAY) {
3911 klass = mono_defaults.array_class;
3912 } else if (type->type == MONO_TYPE_VALUETYPE) {
3913 klass = type->data.klass;
3914 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
3915 t == MONO_TYPE_CLASS) {
3916 klass = mono_defaults.object_class;
3917 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
3918 klass = mono_defaults.int_class;
3919 } else if (t == MONO_TYPE_GENERICINST) {
3920 if (mono_type_generic_inst_is_valuetype (type))
3921 klass = mono_class_from_mono_type (type);
3923 klass = mono_defaults.object_class;
3925 klass = mono_class_from_mono_type (type);
3928 klass = mono_defaults.int_class;
3931 mono_marshal_lock ();
3933 ldflda_hash = g_hash_table_new (NULL, NULL);
3934 res = g_hash_table_lookup (ldflda_hash, klass);
3935 mono_marshal_unlock ();
3939 /* we add the %p pointer value of klass because class names are not unique */
3940 name = g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass, klass->name_space, klass->name);
3941 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLDA);
3944 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
3945 sig->params [0] = &mono_defaults.object_class->byval_arg;
3946 sig->params [1] = &mono_defaults.int_class->byval_arg;
3947 sig->params [2] = &mono_defaults.int_class->byval_arg;
3948 sig->params [3] = &mono_defaults.int_class->byval_arg;
3949 sig->ret = &mono_defaults.int_class->byval_arg;
3951 mono_mb_emit_ldarg (mb, 0);
3952 pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3954 /* FIXME: Only throw this if the object is in another appdomain */
3955 mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain.");
3957 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
3959 mono_mb_emit_ldarg (mb, 0);
3960 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3961 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3962 mono_mb_emit_ldarg (mb, 3);
3963 mono_mb_emit_byte (mb, CEE_ADD);
3965 mono_mb_emit_byte (mb, CEE_RET);
3967 res = mono_mb_create_and_cache (ldflda_hash, klass,
3968 mb, sig, sig->param_count + 16);
3975 * mono_marshal_get_stfld_remote_wrapper:
3976 * klass: The type of the field
3978 * This function generates a wrapper for calling mono_store_remote_field_new
3979 * with the appropriate signature.
3982 mono_marshal_get_stfld_remote_wrapper (MonoClass *klass)
3984 MonoMethodSignature *sig, *csig;
3985 MonoMethodBuilder *mb;
3987 static GHashTable *stfld_hash = NULL;
3990 mono_marshal_lock ();
3992 stfld_hash = g_hash_table_new (NULL, NULL);
3993 res = g_hash_table_lookup (stfld_hash, klass);
3994 mono_marshal_unlock ();
3998 name = g_strdup_printf ("__mono_store_remote_field_new_wrapper_%s.%s", klass->name_space, klass->name);
3999 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD_REMOTE);
4002 mb->method->save_lmf = 1;
4004 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
4005 sig->params [0] = &mono_defaults.object_class->byval_arg;
4006 sig->params [1] = &mono_defaults.int_class->byval_arg;
4007 sig->params [2] = &mono_defaults.int_class->byval_arg;
4008 sig->params [3] = &klass->byval_arg;
4009 sig->ret = &mono_defaults.void_class->byval_arg;
4011 mono_mb_emit_ldarg (mb, 0);
4012 mono_mb_emit_ldarg (mb, 1);
4013 mono_mb_emit_ldarg (mb, 2);
4014 mono_mb_emit_ldarg (mb, 3);
4016 if (klass->valuetype) {
4017 mono_mb_emit_byte (mb, CEE_BOX);
4018 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4021 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
4022 csig->params [0] = &mono_defaults.object_class->byval_arg;
4023 csig->params [1] = &mono_defaults.int_class->byval_arg;
4024 csig->params [2] = &mono_defaults.int_class->byval_arg;
4025 csig->params [3] = &klass->byval_arg;
4026 csig->ret = &mono_defaults.void_class->byval_arg;
4029 mono_mb_emit_native_call (mb, csig, mono_store_remote_field_new);
4030 emit_thread_interrupt_checkpoint (mb);
4032 mono_mb_emit_byte (mb, CEE_RET);
4034 res = mono_mb_create_and_cache (stfld_hash, klass,
4035 mb, sig, sig->param_count + 16);
4042 * mono_marshal_get_stfld_wrapper:
4043 * @type: the type of the field
4045 * This method generates a function which can be use to store a field with type
4046 * @type. The generated function has the following signature:
4047 * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
4050 mono_marshal_get_stfld_wrapper (MonoType *type)
4052 MonoMethodSignature *sig;
4053 MonoMethodBuilder *mb;
4056 static GHashTable *stfld_hash = NULL;
4060 type = mono_type_get_underlying_type (type);
4064 if (type->type == MONO_TYPE_SZARRAY) {
4065 klass = mono_defaults.array_class;
4066 } else if (type->type == MONO_TYPE_VALUETYPE) {
4067 klass = type->data.klass;
4068 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
4069 klass = mono_defaults.object_class;
4070 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
4071 klass = mono_defaults.int_class;
4072 } else if (t == MONO_TYPE_GENERICINST) {
4073 if (mono_type_generic_inst_is_valuetype (type))
4074 klass = mono_class_from_mono_type (type);
4076 klass = mono_defaults.object_class;
4078 klass = mono_class_from_mono_type (type);
4081 klass = mono_defaults.int_class;
4084 mono_marshal_lock ();
4086 stfld_hash = g_hash_table_new (NULL, NULL);
4087 res = g_hash_table_lookup (stfld_hash, klass);
4088 mono_marshal_unlock ();
4092 /* we add the %p pointer value of klass because class names are not unique */
4093 name = g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name);
4094 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
4097 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
4098 sig->params [0] = &mono_defaults.object_class->byval_arg;
4099 sig->params [1] = &mono_defaults.int_class->byval_arg;
4100 sig->params [2] = &mono_defaults.int_class->byval_arg;
4101 sig->params [3] = &mono_defaults.int_class->byval_arg;
4102 sig->params [4] = &klass->byval_arg;
4103 sig->ret = &mono_defaults.void_class->byval_arg;
4105 mono_mb_emit_ldarg (mb, 0);
4106 pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
4108 mono_mb_emit_ldarg (mb, 0);
4109 mono_mb_emit_ldarg (mb, 1);
4110 mono_mb_emit_ldarg (mb, 2);
4111 mono_mb_emit_ldarg (mb, 4);
4113 mono_mb_emit_managed_call (mb, mono_marshal_get_stfld_remote_wrapper (klass), NULL);
4115 mono_mb_emit_byte (mb, CEE_RET);
4117 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4119 mono_mb_emit_ldarg (mb, 0);
4120 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4121 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4122 mono_mb_emit_ldarg (mb, 3);
4123 mono_mb_emit_byte (mb, CEE_ADD);
4124 mono_mb_emit_ldarg (mb, 4);
4129 case MONO_TYPE_BOOLEAN:
4130 mono_mb_emit_byte (mb, CEE_STIND_I1);
4132 case MONO_TYPE_CHAR:
4135 mono_mb_emit_byte (mb, CEE_STIND_I2);
4139 mono_mb_emit_byte (mb, CEE_STIND_I4);
4143 mono_mb_emit_byte (mb, CEE_STIND_I8);
4146 mono_mb_emit_byte (mb, CEE_STIND_R4);
4149 mono_mb_emit_byte (mb, CEE_STIND_R8);
4151 case MONO_TYPE_ARRAY:
4152 case MONO_TYPE_SZARRAY:
4153 case MONO_TYPE_OBJECT:
4154 case MONO_TYPE_CLASS:
4155 case MONO_TYPE_STRING:
4156 mono_mb_emit_byte (mb, CEE_STIND_REF);
4161 case MONO_TYPE_FNPTR:
4162 mono_mb_emit_byte (mb, CEE_STIND_I);
4164 case MONO_TYPE_VALUETYPE:
4165 g_assert (!klass->enumtype);
4166 mono_mb_emit_byte (mb, CEE_STOBJ);
4167 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4169 case MONO_TYPE_GENERICINST:
4170 mono_mb_emit_byte (mb, CEE_STOBJ);
4171 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4174 g_warning ("type %x not implemented", type->type);
4175 g_assert_not_reached ();
4178 mono_mb_emit_byte (mb, CEE_RET);
4180 res = mono_mb_create_and_cache (stfld_hash, klass,
4181 mb, sig, sig->param_count + 16);
4188 * generates IL code for the icall wrapper (the generated method
4189 * calls the unmanaged code in func)
4192 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func)
4194 MonoMethodSignature *csig;
4195 MonoMethodBuilder *mb;
4199 g_assert (sig->pinvoke);
4201 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
4203 mb->method->save_lmf = 1;
4205 /* we copy the signature, so that we can modify it */
4208 mono_mb_emit_byte (mb, CEE_LDARG_0);
4210 for (i = 0; i < sig->param_count; i++)
4211 mono_mb_emit_ldarg (mb, i + sig->hasthis);
4213 mono_mb_emit_native_call (mb, sig, (gpointer) func);
4214 emit_thread_interrupt_checkpoint (mb);
4215 mono_mb_emit_byte (mb, CEE_RET);
4217 csig = mono_metadata_signature_dup (sig);
4219 if (csig->call_convention == MONO_CALL_VARARG)
4220 csig->call_convention = 0;
4222 res = mono_mb_create_method (mb, csig, csig->param_count + 16);
4229 MonoMethodBuilder *mb;
4230 MonoMethodSignature *sig;
4231 MonoMethodPInvoke *piinfo;
4232 int *orig_conv_args; /* Locals containing the original values of byref args */
4234 MonoClass *retobj_class;
4235 } EmitMarshalContext;
4238 MARSHAL_ACTION_CONV_IN,
4239 MARSHAL_ACTION_PUSH,
4240 MARSHAL_ACTION_CONV_OUT,
4241 MARSHAL_ACTION_CONV_RESULT,
4242 MARSHAL_ACTION_MANAGED_CONV_IN,
4243 MARSHAL_ACTION_MANAGED_CONV_OUT,
4244 MARSHAL_ACTION_MANAGED_CONV_RESULT
4248 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
4249 MonoMarshalSpec *spec,
4250 int conv_arg, MonoType **conv_arg_type,
4251 MarshalAction action)
4255 static MonoClass *ICustomMarshaler = NULL;
4256 static MonoMethod *cleanup_native, *cleanup_managed;
4257 static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
4258 MonoMethod *get_instance;
4259 MonoMethodBuilder *mb = m->mb;
4260 char *exception_msg = NULL;
4264 if (!ICustomMarshaler) {
4265 ICustomMarshaler = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
4266 g_assert (ICustomMarshaler);
4268 cleanup_native = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpNativeData", 1);
4269 g_assert (cleanup_native);
4270 cleanup_managed = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpManagedData", 1);
4271 g_assert (cleanup_managed);
4272 marshal_managed_to_native = mono_class_get_method_from_name (ICustomMarshaler, "MarshalManagedToNative", 1);
4273 g_assert (marshal_managed_to_native);
4274 marshal_native_to_managed = mono_class_get_method_from_name (ICustomMarshaler, "MarshalNativeToManaged", 1);
4275 g_assert (marshal_native_to_managed);
4278 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, mb->method->klass->image);
4279 g_assert (mtype != NULL);
4280 mklass = mono_class_from_mono_type (mtype);
4281 g_assert (mklass != NULL);
4283 if (!mono_class_is_assignable_from (ICustomMarshaler, mklass))
4284 exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass->name);
4286 get_instance = mono_class_get_method_from_name_flags (mklass, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC);
4288 MonoMethodSignature *get_sig = mono_method_signature (get_instance);
4289 if ((get_sig->ret->type != MONO_TYPE_CLASS) ||
4290 (mono_class_from_mono_type (get_sig->ret) != ICustomMarshaler) ||
4291 (get_sig->params [0]->type != MONO_TYPE_STRING))
4292 get_instance = NULL;
4296 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);
4298 /* Throw exception and emit compensation code if neccesary */
4299 if (exception_msg) {
4301 case MARSHAL_ACTION_CONV_IN:
4302 case MARSHAL_ACTION_CONV_RESULT:
4303 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4304 if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT))
4305 mono_mb_emit_byte (mb, CEE_POP);
4307 mono_mb_emit_exception_full (mb, "System", "ApplicationException", exception_msg);
4308 g_free (exception_msg);
4311 case MARSHAL_ACTION_PUSH:
4312 mono_mb_emit_byte (mb, CEE_LDNULL);
4320 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
4321 /* FIXME: MS.NET throws an exception if GetInstance returns null */
4324 case MARSHAL_ACTION_CONV_IN:
4326 case MONO_TYPE_CLASS:
4327 case MONO_TYPE_OBJECT:
4328 case MONO_TYPE_STRING:
4329 case MONO_TYPE_ARRAY:
4330 case MONO_TYPE_SZARRAY:
4331 case MONO_TYPE_VALUETYPE:
4335 g_warning ("custom marshalling of type %x is currently not supported", t->type);
4336 g_assert_not_reached ();
4340 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4342 mono_mb_emit_byte (mb, CEE_LDNULL);
4343 mono_mb_emit_stloc (mb, conv_arg);
4345 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
4348 /* Check for null */
4349 mono_mb_emit_ldarg (mb, argnum);
4351 mono_mb_emit_byte (mb, CEE_LDIND_I);
4352 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4354 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4356 mono_mb_emit_byte (mb, CEE_CALL);
4357 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4359 mono_mb_emit_ldarg (mb, argnum);
4361 mono_mb_emit_byte (mb, CEE_LDIND_REF);
4363 if (t->type == MONO_TYPE_VALUETYPE) {
4365 * Since we can't determine the type of the argument, we
4366 * will assume the unmanaged function takes a pointer.
4368 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4370 mono_mb_emit_byte (mb, CEE_BOX);
4371 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (t)));
4374 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4375 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native));
4376 mono_mb_emit_stloc (mb, conv_arg);
4378 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4381 case MARSHAL_ACTION_CONV_OUT:
4382 /* Check for null */
4383 mono_mb_emit_ldloc (mb, conv_arg);
4384 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4387 mono_mb_emit_ldarg (mb, argnum);
4389 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4391 mono_mb_emit_byte (mb, CEE_CALL);
4392 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4394 mono_mb_emit_ldloc (mb, conv_arg);
4395 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4396 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
4397 mono_mb_emit_byte (mb, CEE_STIND_I);
4400 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4402 mono_mb_emit_byte (mb, CEE_CALL);
4403 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4405 mono_mb_emit_ldloc (mb, conv_arg);
4407 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4408 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native));
4410 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4413 case MARSHAL_ACTION_PUSH:
4415 mono_mb_emit_ldloc_addr (mb, conv_arg);
4417 mono_mb_emit_ldloc (mb, conv_arg);
4420 case MARSHAL_ACTION_CONV_RESULT:
4421 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4423 mono_mb_emit_stloc (mb, 3);
4425 mono_mb_emit_ldloc (mb, 3);
4426 mono_mb_emit_stloc (mb, loc1);
4428 /* Check for null */
4429 mono_mb_emit_ldloc (mb, 3);
4430 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4432 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4434 mono_mb_emit_byte (mb, CEE_CALL);
4435 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4436 mono_mb_emit_byte (mb, CEE_DUP);
4438 mono_mb_emit_ldloc (mb, 3);
4439 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4440 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
4441 mono_mb_emit_stloc (mb, 3);
4443 mono_mb_emit_ldloc (mb, loc1);
4444 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4445 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native));
4447 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4450 case MARSHAL_ACTION_MANAGED_CONV_IN:
4456 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4458 mono_mb_emit_byte (mb, CEE_LDNULL);
4459 mono_mb_emit_stloc (mb, conv_arg);
4461 /* Check for null */
4462 mono_mb_emit_ldarg (mb, argnum);
4463 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4465 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4466 mono_mb_emit_byte (mb, CEE_CALL);
4467 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4469 mono_mb_emit_ldarg (mb, argnum);
4471 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4472 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
4473 mono_mb_emit_stloc (mb, conv_arg);
4475 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4478 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4479 g_assert (!t->byref);
4481 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4483 mono_mb_emit_stloc (mb, 3);
4485 mono_mb_emit_ldloc (mb, 3);
4486 mono_mb_emit_stloc (mb, loc1);
4488 /* Check for null */
4489 mono_mb_emit_ldloc (mb, 3);
4490 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4492 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4493 mono_mb_emit_byte (mb, CEE_CALL);
4494 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4495 mono_mb_emit_byte (mb, CEE_DUP);
4497 mono_mb_emit_ldloc (mb, 3);
4498 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4499 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native));
4500 mono_mb_emit_stloc (mb, 3);
4502 mono_mb_emit_ldloc (mb, loc1);
4503 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4504 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_managed));
4506 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4509 case MARSHAL_ACTION_MANAGED_CONV_OUT:
4510 g_assert (!t->byref);
4512 /* Check for null */
4513 mono_mb_emit_ldloc (mb, conv_arg);
4514 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4516 /* Call CleanUpManagedData */
4517 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4519 mono_mb_emit_byte (mb, CEE_CALL);
4520 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
4522 mono_mb_emit_ldloc (mb, conv_arg);
4523 mono_mb_emit_byte (mb, CEE_CALLVIRT);
4524 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_managed));
4526 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4530 g_assert_not_reached ();
4537 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
4538 MonoMarshalSpec *spec,
4539 int conv_arg, MonoType **conv_arg_type,
4540 MarshalAction action)
4542 MonoMethodBuilder *mb = m->mb;
4545 case MARSHAL_ACTION_CONV_IN: {
4546 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
4548 g_assert (t->type == MONO_TYPE_OBJECT);
4549 g_assert (!t->byref);
4551 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4552 mono_mb_emit_ldarg (mb, argnum);
4553 mono_mb_emit_icon (mb, encoding);
4554 mono_mb_emit_icon (mb, t->attrs);
4555 mono_mb_emit_icall (mb, mono_marshal_asany);
4556 mono_mb_emit_stloc (mb, conv_arg);
4560 case MARSHAL_ACTION_PUSH:
4561 mono_mb_emit_ldloc (mb, conv_arg);
4564 case MARSHAL_ACTION_CONV_OUT: {
4565 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
4567 mono_mb_emit_ldarg (mb, argnum);
4568 mono_mb_emit_ldloc (mb, conv_arg);
4569 mono_mb_emit_icon (mb, encoding);
4570 mono_mb_emit_icon (mb, t->attrs);
4571 mono_mb_emit_icall (mb, mono_marshal_free_asany);
4576 g_assert_not_reached ();
4583 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
4584 MonoMarshalSpec *spec,
4585 int conv_arg, MonoType **conv_arg_type,
4586 MarshalAction action)
4588 MonoMethodBuilder *mb = m->mb;
4592 klass = t->data.klass;
4595 case MARSHAL_ACTION_CONV_IN:
4596 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4597 klass->blittable || klass->enumtype)
4600 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4602 /* store the address of the source into local variable 0 */
4604 mono_mb_emit_ldarg (mb, argnum);
4606 mono_mb_emit_ldarg_addr (mb, argnum);
4608 mono_mb_emit_stloc (mb, 0);
4610 /* allocate space for the native struct and
4611 * store the address into local variable 1 (dest) */
4612 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
4613 mono_mb_emit_byte (mb, CEE_PREFIX1);
4614 mono_mb_emit_byte (mb, CEE_LOCALLOC);
4615 mono_mb_emit_stloc (mb, conv_arg);
4618 mono_mb_emit_ldloc (mb, 0);
4619 mono_mb_emit_byte (mb, CEE_BRFALSE);
4621 mono_mb_emit_i4 (mb, 0);
4624 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
4626 mono_mb_emit_ldloc (mb, conv_arg);
4627 mono_mb_emit_byte (mb, CEE_STLOC_1);
4629 /* emit valuetype conversion code */
4630 emit_struct_conv (mb, klass, FALSE);
4634 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4637 case MARSHAL_ACTION_PUSH:
4638 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4639 klass->blittable || klass->enumtype) {
4640 mono_mb_emit_ldarg (mb, argnum);
4643 mono_mb_emit_ldloc (mb, conv_arg);
4645 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4646 mono_mb_emit_byte (mb, CEE_MONO_LDNATIVEOBJ);
4647 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4651 case MARSHAL_ACTION_CONV_OUT:
4652 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4653 klass->blittable || klass->enumtype)
4657 /* dst = argument */
4658 mono_mb_emit_ldarg (mb, argnum);
4659 mono_mb_emit_byte (mb, CEE_STLOC_1);
4661 mono_mb_emit_ldloc (mb, 1);
4662 mono_mb_emit_byte (mb, CEE_BRFALSE);
4664 mono_mb_emit_i4 (mb, 0);
4666 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
4667 /* src = tmp_locals [i] */
4668 mono_mb_emit_ldloc (mb, conv_arg);
4669 mono_mb_emit_stloc (mb, 0);
4671 /* emit valuetype conversion code */
4672 emit_struct_conv (mb, klass, TRUE);
4676 emit_struct_free (mb, klass, conv_arg);
4679 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4682 case MARSHAL_ACTION_CONV_RESULT:
4683 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4685 mono_mb_emit_stloc (mb, 3);
4688 /* load pointer to returned value type */
4689 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4690 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
4691 /* store the address of the source into local variable 0 */
4692 mono_mb_emit_stloc (mb, 0);
4694 mono_mb_emit_ldloc_addr (mb, 3);
4695 mono_mb_emit_byte (mb, CEE_STLOC_1);
4697 /* emit valuetype conversion code */
4698 emit_struct_conv (mb, klass, TRUE);
4701 case MARSHAL_ACTION_MANAGED_CONV_IN:
4702 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4703 klass->blittable || klass->enumtype) {
4708 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
4710 if (t->attrs & PARAM_ATTRIBUTE_OUT)
4714 mono_mb_emit_ldarg (mb, argnum);
4716 mono_mb_emit_ldarg_addr (mb, argnum);
4717 mono_mb_emit_stloc (mb, 0);
4720 mono_mb_emit_ldloc (mb, 0);
4721 mono_mb_emit_byte (mb, CEE_BRFALSE);
4723 mono_mb_emit_i4 (mb, 0);
4726 mono_mb_emit_ldloc_addr (mb, conv_arg);
4727 mono_mb_emit_byte (mb, CEE_STLOC_1);
4729 /* emit valuetype conversion code */
4730 emit_struct_conv (mb, klass, TRUE);
4733 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4736 case MARSHAL_ACTION_MANAGED_CONV_OUT:
4737 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4738 klass->blittable || klass->enumtype) {
4742 /* Check for null */
4743 mono_mb_emit_ldarg (mb, argnum);
4744 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4747 mono_mb_emit_ldloc_addr (mb, conv_arg);
4748 mono_mb_emit_stloc (mb, 0);
4751 mono_mb_emit_ldarg (mb, argnum);
4752 mono_mb_emit_byte (mb, CEE_STLOC_1);
4754 /* emit valuetype conversion code */
4755 emit_struct_conv (mb, klass, FALSE);
4757 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4760 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4761 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
4762 klass->blittable || klass->enumtype) {
4763 mono_mb_emit_stloc (mb, 3);
4768 /* load pointer to returned value type */
4769 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4770 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
4772 /* store the address of the source into local variable 0 */
4773 mono_mb_emit_stloc (mb, 0);
4774 /* allocate space for the native struct and
4775 * store the address into dst_ptr */
4776 m->retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4777 m->retobj_class = klass;
4778 g_assert (m->retobj_var);
4779 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
4780 mono_mb_emit_byte (mb, CEE_CONV_I);
4781 mono_mb_emit_icall (mb, mono_marshal_alloc);
4782 mono_mb_emit_byte (mb, CEE_STLOC_1);
4783 mono_mb_emit_ldloc (mb, 1);
4784 mono_mb_emit_stloc (mb, m->retobj_var);
4786 /* emit valuetype conversion code */
4787 emit_struct_conv (mb, klass, FALSE);
4791 g_assert_not_reached ();
4798 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
4799 MonoMarshalSpec *spec,
4800 int conv_arg, MonoType **conv_arg_type,
4801 MarshalAction action)
4803 MonoMethodBuilder *mb = m->mb;
4804 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
4805 MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
4809 case MARSHAL_ACTION_CONV_IN:
4810 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4811 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4814 if (t->attrs & PARAM_ATTRIBUTE_OUT)
4817 mono_mb_emit_ldarg (mb, argnum);
4818 mono_mb_emit_byte (mb, CEE_LDIND_I);
4820 mono_mb_emit_ldarg (mb, argnum);
4824 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
4825 MonoException *exc = mono_get_exception_not_implemented (msg);
4828 mono_raise_exception (exc);
4831 mono_mb_emit_icall (mb, conv_to_icall (conv));
4833 mono_mb_emit_stloc (mb, conv_arg);
4836 case MARSHAL_ACTION_CONV_OUT:
4837 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4838 mono_mb_emit_ldarg (mb, argnum);
4839 mono_mb_emit_ldloc (mb, conv_arg);
4840 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
4841 mono_mb_emit_byte (mb, CEE_STIND_I);
4843 if (mono_marshal_need_free (t, m->piinfo, spec)) {
4844 mono_mb_emit_ldloc (mb, conv_arg);
4845 mono_mb_emit_icall (mb, mono_marshal_free);
4850 case MARSHAL_ACTION_CONV_RESULT:
4851 mono_mb_emit_stloc (mb, 0);
4853 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
4855 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
4856 mono_mb_emit_exception_marshal_directive (mb, msg);
4860 mono_mb_emit_ldloc (mb, 0);
4861 mono_mb_emit_icall (mb, conv_to_icall (conv));
4862 mono_mb_emit_stloc (mb, 3);
4864 /* free the string */
4865 mono_mb_emit_ldloc (mb, 0);
4866 mono_mb_emit_icall (mb, g_free);
4869 case MARSHAL_ACTION_MANAGED_CONV_IN:
4875 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4876 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4878 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
4880 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
4881 mono_mb_emit_exception_marshal_directive (mb, msg);
4885 mono_mb_emit_ldarg (mb, argnum);
4886 mono_mb_emit_icall (mb, conv_to_icall (conv));
4887 mono_mb_emit_stloc (mb, conv_arg);
4890 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4891 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPSTR));
4892 mono_mb_emit_stloc (mb, 3);
4896 g_assert_not_reached ();
4903 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
4904 MonoMarshalSpec *spec,
4905 int conv_arg, MonoType **conv_arg_type,
4906 MarshalAction action)
4908 MonoMethodBuilder *mb = m->mb;
4909 MonoClass *klass = t->data.klass;
4912 if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
4913 mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
4917 case MARSHAL_ACTION_CONV_IN:
4918 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4919 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4921 m->orig_conv_args [argnum] = 0;
4923 if (klass->delegate) {
4924 g_assert (!t->byref);
4925 mono_mb_emit_ldarg (mb, argnum);
4926 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
4927 mono_mb_emit_stloc (mb, conv_arg);
4928 } else if (klass == mono_defaults.stringbuilder_class) {
4929 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
4930 MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
4932 g_assert (!t->byref);
4933 mono_mb_emit_ldarg (mb, argnum);
4936 mono_mb_emit_icall (mb, conv_to_icall (conv));
4938 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
4939 MonoException *exc = mono_get_exception_not_implemented (msg);
4942 mono_raise_exception (exc);
4945 mono_mb_emit_stloc (mb, conv_arg);
4946 } else if (klass->blittable) {
4947 mono_mb_emit_ldarg (mb, argnum);
4948 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4949 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4950 mono_mb_emit_icon (mb, sizeof (MonoObject));
4951 mono_mb_emit_byte (mb, CEE_ADD);
4952 mono_mb_emit_stloc (mb, conv_arg);
4955 mono_mb_emit_byte (mb, CEE_LDNULL);
4956 mono_mb_emit_stloc (mb, conv_arg);
4959 /* we dont need any conversions for out parameters */
4960 if (t->attrs & PARAM_ATTRIBUTE_OUT)
4963 mono_mb_emit_ldarg (mb, argnum);
4964 mono_mb_emit_byte (mb, CEE_LDIND_I);
4967 mono_mb_emit_ldarg (mb, argnum);
4968 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4969 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4972 /* store the address of the source into local variable 0 */
4973 mono_mb_emit_stloc (mb, 0);
4974 mono_mb_emit_ldloc (mb, 0);
4975 mono_mb_emit_byte (mb, CEE_BRFALSE);
4977 mono_mb_emit_i4 (mb, 0);
4979 /* allocate space for the native struct and store the address */
4980 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
4981 mono_mb_emit_byte (mb, CEE_PREFIX1);
4982 mono_mb_emit_byte (mb, CEE_LOCALLOC);
4983 mono_mb_emit_stloc (mb, conv_arg);
4986 /* Need to store the original buffer so we can free it later */
4987 m->orig_conv_args [argnum] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4988 mono_mb_emit_ldloc (mb, conv_arg);
4989 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
4992 /* set the src_ptr */
4993 mono_mb_emit_ldloc (mb, 0);
4994 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4995 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4996 mono_mb_emit_icon (mb, sizeof (MonoObject));
4997 mono_mb_emit_byte (mb, CEE_ADD);
4998 mono_mb_emit_stloc (mb, 0);
5001 mono_mb_emit_ldloc (mb, conv_arg);
5002 mono_mb_emit_byte (mb, CEE_STLOC_1);
5004 /* emit valuetype conversion code */
5005 emit_struct_conv (mb, klass, FALSE);
5007 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5011 case MARSHAL_ACTION_CONV_OUT:
5012 if (klass == mono_defaults.stringbuilder_class) {
5014 MonoMarshalNative encoding;
5015 MonoMarshalConv conv;
5017 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5018 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
5020 g_assert (!t->byref);
5021 g_assert (encoding != -1);
5023 mono_mb_emit_ldarg (mb, argnum);
5024 mono_mb_emit_ldloc (mb, conv_arg);
5026 mono_mb_emit_icall (mb, conv_to_icall (conv));
5029 mono_mb_emit_ldloc (mb, conv_arg);
5030 mono_mb_emit_icall (mb, mono_marshal_free);
5035 if (klass->delegate)
5038 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
5039 /* allocate a new object */
5040 mono_mb_emit_ldarg (mb, argnum);
5041 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5042 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
5043 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
5044 mono_mb_emit_byte (mb, CEE_STIND_I);
5047 /* dst = *argument */
5048 mono_mb_emit_ldarg (mb, argnum);
5051 mono_mb_emit_byte (mb, CEE_LDIND_I);
5053 mono_mb_emit_byte (mb, CEE_STLOC_1);
5055 mono_mb_emit_ldloc (mb, 1);
5056 mono_mb_emit_byte (mb, CEE_BRFALSE);
5058 mono_mb_emit_i4 (mb, 0);
5060 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
5061 mono_mb_emit_ldloc (mb, 1);
5062 mono_mb_emit_icon (mb, sizeof (MonoObject));
5063 mono_mb_emit_byte (mb, CEE_ADD);
5064 mono_mb_emit_byte (mb, CEE_STLOC_1);
5066 /* src = tmp_locals [i] */
5067 mono_mb_emit_ldloc (mb, conv_arg);
5068 mono_mb_emit_stloc (mb, 0);
5070 /* emit valuetype conversion code */
5071 emit_struct_conv (mb, t->data.klass, TRUE);
5073 /* Free the structure returned by the native code */
5074 emit_struct_free (mb, klass, conv_arg);
5076 if (m->orig_conv_args [argnum]) {
5078 * If the native function changed the pointer, then free
5079 * the original structure plus the new pointer.
5081 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
5082 mono_mb_emit_ldloc (mb, conv_arg);
5083 mono_mb_emit_byte (mb, CEE_BEQ);
5085 mono_mb_emit_i4 (mb, 0);
5087 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
5088 g_assert (m->orig_conv_args [argnum]);
5090 emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
5093 mono_mb_emit_ldloc (mb, conv_arg);
5094 mono_mb_emit_icall (mb, g_free);
5096 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
5100 /* Free the original structure passed to native code */
5101 emit_struct_free (mb, klass, conv_arg);
5103 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5106 case MARSHAL_ACTION_CONV_RESULT:
5107 if (klass->delegate) {
5108 g_assert (!t->byref);
5109 mono_mb_emit_stloc (mb, 0);
5110 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5111 mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
5112 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
5113 mono_mb_emit_ldloc (mb, 0);
5114 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
5115 mono_mb_emit_stloc (mb, 3);
5118 mono_mb_emit_stloc (mb, 0);
5120 /* Make a copy since emit_conv modifies local 0 */
5121 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5122 mono_mb_emit_ldloc (mb, 0);
5123 mono_mb_emit_stloc (mb, loc);
5125 mono_mb_emit_byte (mb, CEE_LDNULL);
5126 mono_mb_emit_stloc (mb, 3);
5128 mono_mb_emit_ldloc (mb, 0);
5129 mono_mb_emit_byte (mb, CEE_BRFALSE);
5131 mono_mb_emit_i4 (mb, 0);
5133 /* allocate result object */
5135 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5136 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
5137 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
5138 mono_mb_emit_stloc (mb, 3);
5142 mono_mb_emit_ldloc (mb, 3);
5143 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5144 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5145 mono_mb_emit_icon (mb, sizeof (MonoObject));
5146 mono_mb_emit_byte (mb, CEE_ADD);
5147 mono_mb_emit_byte (mb, CEE_STLOC_1);
5149 /* emit conversion code */
5150 emit_struct_conv (mb, klass, TRUE);
5152 emit_struct_free (mb, klass, loc);
5154 /* Free the pointer allocated by unmanaged code */
5155 mono_mb_emit_ldloc (mb, loc);
5156 mono_mb_emit_icall (mb, g_free);
5157 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5161 case MARSHAL_ACTION_MANAGED_CONV_IN:
5162 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
5164 if (klass->delegate) {
5165 g_assert (!t->byref);
5166 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5167 mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
5168 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
5169 mono_mb_emit_ldarg (mb, argnum);
5170 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
5171 mono_mb_emit_stloc (mb, conv_arg);
5175 /* The class can not have an automatic layout */
5176 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5177 mono_mb_emit_auto_layout_exception (mb, klass);
5181 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
5182 mono_mb_emit_byte (mb, CEE_LDNULL);
5183 mono_mb_emit_stloc (mb, conv_arg);
5188 mono_mb_emit_ldarg (mb, argnum);
5192 /* Check for NULL and raise an exception */
5193 mono_mb_emit_byte (mb, CEE_BRTRUE);
5195 mono_mb_emit_i4 (mb, 0);
5197 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
5199 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
5200 mono_mb_emit_ldarg (mb, argnum);
5201 mono_mb_emit_byte (mb, CEE_LDIND_I);
5204 mono_mb_emit_stloc (mb, 0);
5206 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5207 mono_mb_emit_stloc (mb, conv_arg);
5209 mono_mb_emit_ldloc (mb, 0);
5210 mono_mb_emit_byte (mb, CEE_BRFALSE);
5212 mono_mb_emit_i4 (mb, 0);
5214 /* Create and set dst */
5215 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5216 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
5217 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
5218 mono_mb_emit_stloc (mb, conv_arg);
5219 mono_mb_emit_ldloc (mb, conv_arg);
5220 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5221 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5222 mono_mb_emit_icon (mb, sizeof (MonoObject));
5223 mono_mb_emit_byte (mb, CEE_ADD);
5224 mono_mb_emit_byte (mb, CEE_STLOC_1);
5226 /* emit valuetype conversion code */
5227 emit_struct_conv (mb, klass, TRUE);
5229 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5232 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5233 /* Check for null */
5234 mono_mb_emit_ldloc (mb, conv_arg);
5235 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
5236 mono_mb_emit_ldarg (mb, argnum);
5237 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5238 mono_mb_emit_byte (mb, CEE_STIND_I);
5239 pos2 = mono_mb_emit_branch (mb, CEE_BR);
5241 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5244 mono_mb_emit_ldloc (mb, conv_arg);
5245 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5246 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5247 mono_mb_emit_icon (mb, sizeof (MonoObject));
5248 mono_mb_emit_byte (mb, CEE_ADD);
5249 mono_mb_emit_stloc (mb, 0);
5251 /* Allocate and set dest */
5252 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5253 mono_mb_emit_byte (mb, CEE_CONV_I);
5254 mono_mb_emit_icall (mb, mono_marshal_alloc);
5255 mono_mb_emit_byte (mb, CEE_STLOC_1);
5257 /* Update argument pointer */
5258 mono_mb_emit_ldarg (mb, argnum);
5259 mono_mb_emit_ldloc (mb, 1);
5260 mono_mb_emit_byte (mb, CEE_STIND_I);
5262 /* emit valuetype conversion code */
5263 emit_struct_conv (mb, klass, FALSE);
5265 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
5268 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5269 if (klass->delegate) {
5270 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
5271 mono_mb_emit_stloc (mb, 3);
5275 /* The class can not have an automatic layout */
5276 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5277 mono_mb_emit_auto_layout_exception (mb, klass);
5281 mono_mb_emit_stloc (mb, 0);
5282 /* Check for null */
5283 mono_mb_emit_ldloc (mb, 0);
5284 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
5285 mono_mb_emit_byte (mb, CEE_LDNULL);
5286 mono_mb_emit_stloc (mb, 3);
5287 pos2 = mono_mb_emit_branch (mb, CEE_BR);
5289 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5292 mono_mb_emit_ldloc (mb, 0);
5293 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5294 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5295 mono_mb_emit_icon (mb, sizeof (MonoObject));
5296 mono_mb_emit_byte (mb, CEE_ADD);
5297 mono_mb_emit_stloc (mb, 0);
5299 /* Allocate and set dest */
5300 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5301 mono_mb_emit_byte (mb, CEE_CONV_I);
5302 mono_mb_emit_icall (mb, mono_marshal_alloc);
5303 mono_mb_emit_byte (mb, CEE_DUP);
5304 mono_mb_emit_byte (mb, CEE_STLOC_1);
5305 mono_mb_emit_stloc (mb, 3);
5307 emit_struct_conv (mb, klass, FALSE);
5309 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
5313 g_assert_not_reached ();
5320 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
5321 MonoMarshalSpec *spec,
5322 int conv_arg, MonoType **conv_arg_type,
5323 MarshalAction action)
5325 MonoMethodBuilder *mb = m->mb;
5326 MonoClass *klass = mono_class_from_mono_type (t);
5327 gboolean need_convert, need_free;
5328 MonoMarshalNative encoding;
5330 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5333 case MARSHAL_ACTION_CONV_IN:
5334 *conv_arg_type = &mono_defaults.object_class->byval_arg;
5335 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5337 if (klass->element_class->blittable) {
5338 mono_mb_emit_ldarg (mb, argnum);
5340 mono_mb_emit_byte (mb, CEE_LDIND_I);
5341 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
5342 mono_mb_emit_stloc (mb, conv_arg);
5345 guint32 label1, label2, label3;
5346 int index_var, src_var, dest_ptr, esize;
5347 MonoMarshalConv conv;
5348 gboolean is_string = FALSE;
5350 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5352 eklass = klass->element_class;
5354 if (eklass == mono_defaults.string_class) {
5356 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
5358 else if (eklass == mono_defaults.stringbuilder_class) {
5360 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
5365 src_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5366 mono_mb_emit_ldarg (mb, argnum);
5368 mono_mb_emit_byte (mb, CEE_LDIND_I);
5369 mono_mb_emit_stloc (mb, src_var);
5372 mono_mb_emit_ldloc (mb, src_var);
5373 mono_mb_emit_stloc (mb, conv_arg);
5374 mono_mb_emit_ldloc (mb, src_var);
5375 mono_mb_emit_byte (mb, CEE_BRFALSE);
5377 mono_mb_emit_i4 (mb, 0);
5381 char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
5382 MonoException *exc = mono_get_exception_not_implemented (msg);
5385 mono_raise_exception (exc);
5390 esize = sizeof (gpointer);
5392 esize = mono_class_native_size (eklass, NULL);
5394 /* allocate space for the native struct and store the address */
5395 mono_mb_emit_icon (mb, esize);
5396 mono_mb_emit_ldloc (mb, src_var);
5397 mono_mb_emit_byte (mb, CEE_LDLEN);
5399 if (eklass == mono_defaults.string_class) {
5400 /* Make the array bigger for the terminating null */
5401 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
5402 mono_mb_emit_byte (mb, CEE_ADD);
5404 mono_mb_emit_byte (mb, CEE_MUL);
5405 mono_mb_emit_byte (mb, CEE_PREFIX1);
5406 mono_mb_emit_byte (mb, CEE_LOCALLOC);
5407 mono_mb_emit_stloc (mb, conv_arg);
5409 mono_mb_emit_ldloc (mb, conv_arg);
5410 mono_mb_emit_stloc (mb, dest_ptr);
5412 /* Emit marshalling loop */
5413 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5414 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5415 mono_mb_emit_stloc (mb, index_var);
5417 mono_mb_emit_ldloc (mb, index_var);
5418 mono_mb_emit_ldloc (mb, src_var);
5419 mono_mb_emit_byte (mb, CEE_LDLEN);
5420 mono_mb_emit_byte (mb, CEE_BGE);
5422 mono_mb_emit_i4 (mb, 0);
5424 /* Emit marshalling code */
5427 mono_mb_emit_ldloc (mb, dest_ptr);
5428 mono_mb_emit_ldloc (mb, src_var);
5429 mono_mb_emit_ldloc (mb, index_var);
5430 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
5431 mono_mb_emit_icall (mb, conv_to_icall (conv));
5432 mono_mb_emit_byte (mb, CEE_STIND_I);
5434 /* set the src_ptr */
5435 mono_mb_emit_ldloc (mb, src_var);
5436 mono_mb_emit_ldloc (mb, index_var);
5437 mono_mb_emit_byte (mb, CEE_LDELEMA);
5438 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
5439 mono_mb_emit_stloc (mb, 0);
5442 mono_mb_emit_ldloc (mb, dest_ptr);
5443 mono_mb_emit_byte (mb, CEE_STLOC_1);
5445 /* emit valuetype conversion code */
5446 emit_struct_conv (mb, eklass, FALSE);
5449 mono_mb_emit_add_to_local (mb, index_var, 1);
5450 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
5452 mono_mb_emit_byte (mb, CEE_BR);
5453 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
5455 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
5457 if (eklass == mono_defaults.string_class) {
5458 /* Null terminate */
5459 mono_mb_emit_ldloc (mb, dest_ptr);
5460 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5461 mono_mb_emit_byte (mb, CEE_STIND_REF);
5464 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
5469 case MARSHAL_ACTION_CONV_OUT:
5470 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
5471 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);
5472 need_free = mono_marshal_need_free (&klass->element_class->byval_arg,
5475 if (need_convert || need_free) {
5476 /* FIXME: Optimize blittable case */
5478 guint32 label1, label2, label3;
5479 int index_var, src_ptr, loc, esize;
5481 eklass = klass->element_class;
5482 if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
5483 esize = sizeof (gpointer);
5485 esize = mono_class_native_size (eklass, NULL);
5486 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5487 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5490 mono_mb_emit_ldarg (mb, argnum);
5492 mono_mb_emit_byte (mb, CEE_LDIND_I);
5493 mono_mb_emit_byte (mb, CEE_BRFALSE);
5495 mono_mb_emit_i4 (mb, 0);
5497 mono_mb_emit_ldloc (mb, conv_arg);
5498 mono_mb_emit_stloc (mb, src_ptr);
5500 /* Emit marshalling loop */
5501 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5502 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5503 mono_mb_emit_stloc (mb, index_var);
5505 mono_mb_emit_ldloc (mb, index_var);
5506 mono_mb_emit_ldarg (mb, argnum);
5508 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5509 mono_mb_emit_byte (mb, CEE_LDLEN);
5510 mono_mb_emit_byte (mb, CEE_BGE);
5512 mono_mb_emit_i4 (mb, 0);
5514 /* Emit marshalling code */
5516 if (eklass == mono_defaults.stringbuilder_class) {
5517 gboolean need_free2;
5518 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
5520 g_assert (conv != -1);
5523 mono_mb_emit_ldarg (mb, argnum);
5525 mono_mb_emit_byte (mb, CEE_LDIND_I);
5526 mono_mb_emit_ldloc (mb, index_var);
5527 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
5530 mono_mb_emit_ldloc (mb, src_ptr);
5531 mono_mb_emit_byte (mb, CEE_LDIND_I);
5533 mono_mb_emit_icall (mb, conv_to_icall (conv));
5537 mono_mb_emit_ldloc (mb, src_ptr);
5538 mono_mb_emit_byte (mb, CEE_LDIND_I);
5540 mono_mb_emit_icall (mb, mono_marshal_free);
5543 else if (eklass == mono_defaults.string_class) {
5546 mono_mb_emit_ldloc (mb, src_ptr);
5547 mono_mb_emit_byte (mb, CEE_LDIND_I);
5549 mono_mb_emit_icall (mb, mono_marshal_free);
5554 /* set the src_ptr */
5555 mono_mb_emit_ldloc (mb, src_ptr);
5556 mono_mb_emit_stloc (mb, 0);
5559 mono_mb_emit_ldarg (mb, argnum);
5561 mono_mb_emit_byte (mb, CEE_LDIND_I);
5562 mono_mb_emit_ldloc (mb, index_var);
5563 mono_mb_emit_byte (mb, CEE_LDELEMA);
5564 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
5565 mono_mb_emit_byte (mb, CEE_STLOC_1);
5567 /* emit valuetype conversion code */
5568 emit_struct_conv (mb, eklass, TRUE);
5572 mono_mb_emit_ldloc (mb, src_ptr);
5573 mono_mb_emit_stloc (mb, loc);
5574 mono_mb_emit_ldloc (mb, loc);
5576 emit_struct_free (mb, eklass, loc);
5580 mono_mb_emit_add_to_local (mb, index_var, 1);
5581 mono_mb_emit_add_to_local (mb, src_ptr, esize);
5583 mono_mb_emit_byte (mb, CEE_BR);
5584 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
5586 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
5587 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
5591 case MARSHAL_ACTION_CONV_RESULT:
5592 /* fixme: we need conversions here */
5593 mono_mb_emit_stloc (mb, 3);
5596 case MARSHAL_ACTION_MANAGED_CONV_IN: {
5598 guint32 label1, label2, label3;
5599 int index_var, src_ptr, loc, esize, param_num, num_elem;
5600 MonoMarshalConv conv;
5601 gboolean is_string = FALSE;
5603 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5604 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5607 char *msg = g_strdup ("Byref array marshalling to managed code is not implemented.");
5608 mono_mb_emit_exception_marshal_directive (mb, msg);
5611 if (spec->native != MONO_NATIVE_LPARRAY) {
5612 char *msg = g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
5613 mono_mb_emit_exception_marshal_directive (mb, msg);
5617 /* FIXME: t is from the method which is wrapped, not the delegate type */
5618 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
5620 param_num = spec->data.array_data.param_num;
5621 num_elem = spec->data.array_data.num_elem;
5622 if (spec->data.array_data.elem_mult == 0)
5623 /* param_num is not specified */
5626 if (param_num == -1) {
5627 if (num_elem <= 0) {
5628 char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
5629 mono_mb_emit_exception_marshal_directive (mb, msg);
5634 /* FIXME: Optimize blittable case */
5636 eklass = klass->element_class;
5637 if (eklass == mono_defaults.string_class) {
5639 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
5641 else if (eklass == mono_defaults.stringbuilder_class) {
5643 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
5648 mono_marshal_load_type_info (eklass);
5651 esize = sizeof (gpointer);
5653 esize = mono_class_native_size (eklass, NULL);
5654 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5655 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5657 mono_mb_emit_byte (mb, CEE_LDNULL);
5658 mono_mb_emit_stloc (mb, conv_arg);
5660 /* Check param index */
5661 if (param_num != -1) {
5662 if (param_num >= m->sig->param_count) {
5663 char *msg = g_strdup ("Array size control parameter index is out of range.");
5664 mono_mb_emit_exception_marshal_directive (mb, msg);
5667 switch (m->sig->params [param_num]->type) {
5680 char *msg = g_strdup ("Array size control parameter must be an integral type.");
5681 mono_mb_emit_exception_marshal_directive (mb, msg);
5688 mono_mb_emit_ldarg (mb, argnum);
5689 mono_mb_emit_byte (mb, CEE_BRFALSE);
5691 mono_mb_emit_i4 (mb, 0);
5693 mono_mb_emit_ldarg (mb, argnum);
5694 mono_mb_emit_stloc (mb, src_ptr);
5696 /* Create managed array */
5698 * The LPArray marshalling spec says that sometimes param_num starts
5699 * from 1, sometimes it starts from 0. But MS seems to allways start
5703 if (param_num == -1)
5704 mono_mb_emit_icon (mb, num_elem);
5706 /* FIXME: Add the two together */
5707 mono_mb_emit_ldarg (mb, param_num);
5709 mono_mb_emit_icon (mb, num_elem);
5710 mono_mb_emit_byte (mb, CEE_ADD);
5714 mono_mb_emit_byte (mb, CEE_NEWARR);
5715 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
5716 mono_mb_emit_stloc (mb, conv_arg);
5718 if (eklass->blittable) {
5719 mono_mb_emit_ldloc (mb, conv_arg);
5720 mono_mb_emit_byte (mb, CEE_CONV_I);
5721 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
5722 mono_mb_emit_byte (mb, CEE_ADD);
5723 mono_mb_emit_ldarg (mb, argnum);
5724 mono_mb_emit_ldloc (mb, conv_arg);
5725 mono_mb_emit_byte (mb, CEE_LDLEN);
5726 mono_mb_emit_icon (mb, esize);
5727 mono_mb_emit_byte (mb, CEE_MUL);
5728 mono_mb_emit_byte (mb, CEE_PREFIX1);
5729 mono_mb_emit_byte (mb, CEE_CPBLK);
5733 /* Emit marshalling loop */
5734 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5735 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5736 mono_mb_emit_stloc (mb, index_var);
5738 mono_mb_emit_ldloc (mb, index_var);
5739 mono_mb_emit_ldloc (mb, conv_arg);
5740 mono_mb_emit_byte (mb, CEE_LDLEN);
5741 mono_mb_emit_byte (mb, CEE_BGE);
5743 mono_mb_emit_i4 (mb, 0);
5745 /* Emit marshalling code */
5747 g_assert (conv != -1);
5749 mono_mb_emit_ldloc (mb, conv_arg);
5750 mono_mb_emit_ldloc (mb, index_var);
5752 mono_mb_emit_ldloc (mb, src_ptr);
5753 mono_mb_emit_byte (mb, CEE_LDIND_I);
5755 mono_mb_emit_icall (mb, conv_to_icall (conv));
5756 mono_mb_emit_byte (mb, CEE_STELEM_REF);
5759 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
5760 mono_mb_emit_exception_marshal_directive (mb, msg);
5764 mono_mb_emit_add_to_local (mb, index_var, 1);
5765 mono_mb_emit_add_to_local (mb, src_ptr, esize);
5767 mono_mb_emit_byte (mb, CEE_BR);
5768 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
5770 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
5771 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
5775 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
5777 guint32 label1, label2, label3;
5778 int index_var, dest_ptr, loc, esize, param_num, num_elem;
5779 MonoMarshalConv conv;
5780 gboolean is_string = FALSE;
5782 /* These are already checked in CONV_IN */
5783 g_assert (!t->byref);
5784 g_assert (spec->native == MONO_NATIVE_LPARRAY);
5785 g_assert (t->attrs & PARAM_ATTRIBUTE_OUT);
5787 param_num = spec->data.array_data.param_num;
5788 num_elem = spec->data.array_data.num_elem;
5790 if (spec->data.array_data.elem_mult == 0)
5791 /* param_num is not specified */
5794 if (param_num == -1) {
5795 if (num_elem <= 0) {
5796 g_assert_not_reached ();
5800 /* FIXME: Optimize blittable case */
5802 eklass = klass->element_class;
5803 if (eklass == mono_defaults.string_class) {
5805 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
5807 else if (eklass == mono_defaults.stringbuilder_class) {
5809 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
5814 mono_marshal_load_type_info (eklass);
5817 esize = sizeof (gpointer);
5819 esize = mono_class_native_size (eklass, NULL);
5821 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5822 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5825 mono_mb_emit_ldloc (mb, conv_arg);
5826 mono_mb_emit_byte (mb, CEE_BRFALSE);
5828 mono_mb_emit_i4 (mb, 0);
5830 mono_mb_emit_ldarg (mb, argnum);
5831 mono_mb_emit_stloc (mb, dest_ptr);
5833 if (eklass->blittable) {
5835 mono_mb_emit_ldarg (mb, argnum);
5837 mono_mb_emit_ldloc (mb, conv_arg);
5838 mono_mb_emit_byte (mb, CEE_CONV_I);
5839 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
5840 mono_mb_emit_byte (mb, CEE_ADD);
5842 mono_mb_emit_ldloc (mb, conv_arg);
5843 mono_mb_emit_byte (mb, CEE_LDLEN);
5844 mono_mb_emit_icon (mb, esize);
5845 mono_mb_emit_byte (mb, CEE_MUL);
5846 mono_mb_emit_byte (mb, CEE_PREFIX1);
5847 mono_mb_emit_byte (mb, CEE_CPBLK);
5851 /* Emit marshalling loop */
5852 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5853 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5854 mono_mb_emit_stloc (mb, index_var);
5856 mono_mb_emit_ldloc (mb, index_var);
5857 mono_mb_emit_ldloc (mb, conv_arg);
5858 mono_mb_emit_byte (mb, CEE_LDLEN);
5859 mono_mb_emit_byte (mb, CEE_BGE);
5861 mono_mb_emit_i4 (mb, 0);
5863 /* Emit marshalling code */
5865 g_assert (conv != -1);
5868 mono_mb_emit_ldloc (mb, dest_ptr);
5871 mono_mb_emit_ldloc (mb, conv_arg);
5872 mono_mb_emit_ldloc (mb, index_var);
5874 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
5876 mono_mb_emit_icall (mb, conv_to_icall (conv));
5877 mono_mb_emit_byte (mb, CEE_STIND_I);
5880 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
5881 mono_mb_emit_exception_marshal_directive (mb, msg);
5885 mono_mb_emit_add_to_local (mb, index_var, 1);
5886 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
5888 mono_mb_emit_byte (mb, CEE_BR);
5889 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
5891 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
5892 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
5896 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
5898 guint32 label1, label2, label3;
5899 int index_var, src, dest, esize;
5900 MonoMarshalConv conv = -1;
5901 gboolean is_string = FALSE;
5903 g_assert (!t->byref);
5905 eklass = klass->element_class;
5907 mono_marshal_load_type_info (eklass);
5909 if (eklass == mono_defaults.string_class) {
5911 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
5914 g_assert_not_reached ();
5918 esize = sizeof (gpointer);
5920 esize = mono_class_native_size (eklass, NULL);
5922 src = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5923 dest = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5925 mono_mb_emit_stloc (mb, src);
5926 mono_mb_emit_ldloc (mb, src);
5927 mono_mb_emit_stloc (mb, 3);
5929 /* Check for null */
5930 mono_mb_emit_ldloc (mb, src);
5931 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5933 /* Allocate native array */
5934 mono_mb_emit_icon (mb, esize);
5935 mono_mb_emit_ldloc (mb, src);
5936 mono_mb_emit_byte (mb, CEE_LDLEN);
5938 if (eklass == mono_defaults.string_class) {
5939 /* Make the array bigger for the terminating null */
5940 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
5941 mono_mb_emit_byte (mb, CEE_ADD);
5943 mono_mb_emit_byte (mb, CEE_MUL);
5944 mono_mb_emit_icall (mb, mono_marshal_alloc);
5945 mono_mb_emit_stloc (mb, dest);
5946 mono_mb_emit_ldloc (mb, dest);
5947 mono_mb_emit_stloc (mb, 3);
5949 /* Emit marshalling loop */
5950 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5951 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5952 mono_mb_emit_stloc (mb, index_var);
5954 mono_mb_emit_ldloc (mb, index_var);
5955 mono_mb_emit_ldloc (mb, src);
5956 mono_mb_emit_byte (mb, CEE_LDLEN);
5957 label3 = mono_mb_emit_branch (mb, CEE_BGE);
5959 /* Emit marshalling code */
5961 g_assert (conv != -1);
5964 mono_mb_emit_ldloc (mb, dest);
5967 mono_mb_emit_ldloc (mb, src);
5968 mono_mb_emit_ldloc (mb, index_var);
5970 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
5972 mono_mb_emit_icall (mb, conv_to_icall (conv));
5973 mono_mb_emit_byte (mb, CEE_STIND_I);
5976 char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
5977 mono_mb_emit_exception_marshal_directive (mb, msg);
5981 mono_mb_emit_add_to_local (mb, index_var, 1);
5982 mono_mb_emit_add_to_local (mb, dest, esize);
5984 mono_mb_emit_byte (mb, CEE_BR);
5985 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
5987 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
5988 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
5992 g_assert_not_reached ();
5999 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
6000 MonoMarshalSpec *spec,
6001 int conv_arg, MonoType **conv_arg_type,
6002 MarshalAction action)
6004 MonoMethodBuilder *mb = m->mb;
6007 case MARSHAL_ACTION_CONV_IN: {
6008 MonoType *local_type;
6009 int variant_bool = 0;
6013 local_type = &mono_defaults.int32_class->byval_arg;
6015 switch (spec->native) {
6016 case MONO_NATIVE_I1:
6017 local_type = &mono_defaults.byte_class->byval_arg;
6019 case MONO_NATIVE_VARIANTBOOL:
6020 local_type = &mono_defaults.int16_class->byval_arg;
6024 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
6025 local_type = &mono_defaults.int32_class->byval_arg;
6029 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6030 conv_arg = mono_mb_add_local (mb, local_type);
6031 mono_mb_emit_ldarg (mb, argnum);
6032 mono_mb_emit_byte (mb, CEE_LDIND_I1);
6034 mono_mb_emit_byte (mb, CEE_NEG);
6035 mono_mb_emit_stloc (mb, conv_arg);
6039 case MARSHAL_ACTION_CONV_RESULT:
6040 /* maybe we need to make sure that it fits within 8 bits */
6041 mono_mb_emit_stloc (mb, 3);
6045 g_assert_not_reached ();
6052 emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t,
6053 MonoMarshalSpec *spec, int conv_arg,
6054 MonoType **conv_arg_type, MarshalAction action)
6057 case MARSHAL_ACTION_CONV_IN:
6058 if (MONO_TYPE_ISSTRUCT (t->data.type)) {
6059 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
6060 mono_mb_emit_exception_marshal_directive (m->mb, msg);
6071 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
6072 MonoMarshalSpec *spec, int conv_arg,
6073 MonoType **conv_arg_type, MarshalAction action)
6075 /* Ensure that we have marshalling info for this param */
6076 mono_marshal_load_type_info (mono_class_from_mono_type (t));
6078 if (spec && spec->native == MONO_NATIVE_CUSTOM)
6079 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6081 if (spec && spec->native == MONO_NATIVE_ASANY)
6082 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6085 case MONO_TYPE_VALUETYPE:
6086 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6087 case MONO_TYPE_STRING:
6088 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6089 case MONO_TYPE_CLASS:
6090 case MONO_TYPE_OBJECT:
6091 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6092 case MONO_TYPE_ARRAY:
6093 case MONO_TYPE_SZARRAY:
6094 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6095 case MONO_TYPE_BOOLEAN:
6096 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6098 return emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action);
6105 * mono_marshal_emit_native_wrapper:
6106 * @sig: The signature of the native function
6107 * @piinfo: Marshalling information
6108 * @mspecs: Marshalling information
6109 * @func: the native function to call
6111 * generates IL code for the pinvoke wrapper, the generated code calls @func.
6114 mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
6116 EmitMarshalContext m;
6117 MonoMethodSignature *csig;
6119 int i, argnum, *tmp_locals;
6125 /* we copy the signature, so that we can set pinvoke to 0 */
6126 csig = mono_metadata_signature_dup (sig);
6129 /* we allocate local for use with emit_struct_conv() */
6130 /* allocate local 0 (pointer) src_ptr */
6131 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6132 /* allocate local 1 (pointer) dst_ptr */
6133 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6134 /* allocate local 2 (boolean) delete_old */
6135 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
6137 /* delete_old = FALSE */
6138 mono_mb_emit_icon (mb, 0);
6139 mono_mb_emit_stloc (mb, 2);
6141 if (!MONO_TYPE_IS_VOID(sig->ret)) {
6142 /* allocate local 3 to store the return value */
6143 mono_mb_add_local (mb, sig->ret);
6146 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
6147 /* Return type custom marshaling */
6149 * Since we can't determine the return type of the unmanaged function,
6150 * we assume it returns a pointer, and pass that pointer to
6151 * MarshalNativeToManaged.
6153 csig->ret = &mono_defaults.int_class->byval_arg;
6156 /* we first do all conversions */
6157 tmp_locals = alloca (sizeof (int) * sig->param_count);
6158 m.orig_conv_args = alloca (sizeof (int) * (sig->param_count + 1));
6160 for (i = 0; i < sig->param_count; i ++) {
6161 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
6164 /* push all arguments */
6167 mono_mb_emit_byte (mb, CEE_LDARG_0);
6169 for (i = 0; i < sig->param_count; i++) {
6170 MonoType *t = sig->params [i];
6171 MonoMarshalSpec *spec = mspecs [i + 1];
6173 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY)))
6174 emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
6176 argnum = i + sig->hasthis;
6179 case MONO_TYPE_BOOLEAN:
6181 g_assert (tmp_locals [i]);
6182 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
6184 mono_mb_emit_ldarg (mb, argnum);
6199 case MONO_TYPE_FNPTR:
6200 mono_mb_emit_ldarg (mb, argnum);
6202 case MONO_TYPE_VALUETYPE:
6203 emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
6205 case MONO_TYPE_STRING:
6206 case MONO_TYPE_CLASS:
6207 case MONO_TYPE_OBJECT:
6208 case MONO_TYPE_ARRAY:
6209 case MONO_TYPE_SZARRAY:
6210 g_assert (tmp_locals [i]);
6212 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
6214 mono_mb_emit_ldloc (mb, tmp_locals [i]);
6216 case MONO_TYPE_CHAR:
6217 /* fixme: dont know how to marshal that. We cant simply
6218 * convert it to a one byte UTF8 character, because an
6219 * unicode character may need more that one byte in UTF8 */
6220 mono_mb_emit_ldarg (mb, argnum);
6222 case MONO_TYPE_TYPEDBYREF:
6224 g_warning ("type 0x%02x unknown", t->type);
6225 g_assert_not_reached ();
6230 /* call the native method */
6231 mono_mb_emit_native_call (mb, csig, func);
6233 /* Set LastError if needed */
6234 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
6235 mono_mb_emit_icall (mb, mono_marshal_set_last_error);
6238 /* convert the result */
6239 if (!sig->ret->byref) {
6240 MonoMarshalSpec *spec = mspecs [0];
6241 type = sig->ret->type;
6243 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
6244 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
6249 case MONO_TYPE_VOID:
6264 case MONO_TYPE_FNPTR:
6265 /* no conversions necessary */
6266 mono_mb_emit_stloc (mb, 3);
6268 case MONO_TYPE_VALUETYPE:
6269 klass = sig->ret->data.klass;
6270 if (klass->enumtype) {
6271 type = sig->ret->data.klass->enum_basetype->type;
6274 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
6276 case MONO_TYPE_STRING:
6277 case MONO_TYPE_CLASS:
6278 case MONO_TYPE_OBJECT:
6279 case MONO_TYPE_BOOLEAN:
6280 case MONO_TYPE_ARRAY:
6281 case MONO_TYPE_SZARRAY:
6282 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
6284 case MONO_TYPE_CHAR:
6285 /* fixme: we need conversions here */
6286 mono_mb_emit_stloc (mb, 3);
6288 case MONO_TYPE_TYPEDBYREF:
6290 g_warning ("return type 0x%02x unknown", sig->ret->type);
6291 g_assert_not_reached ();
6295 mono_mb_emit_stloc (mb, 3);
6299 * Need to call this after converting the result since MONO_VTADDR needs
6300 * to be adjacent to the call instruction.
6302 emit_thread_interrupt_checkpoint (mb);
6304 /* we need to convert byref arguments back and free string arrays */
6305 for (i = 0; i < sig->param_count; i++) {
6306 MonoType *t = sig->params [i];
6307 MonoMarshalSpec *spec = mspecs [i + 1];
6309 argnum = i + sig->hasthis;
6311 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
6312 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
6317 case MONO_TYPE_STRING:
6318 case MONO_TYPE_VALUETYPE:
6319 case MONO_TYPE_CLASS:
6320 case MONO_TYPE_OBJECT:
6321 case MONO_TYPE_SZARRAY:
6322 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
6324 case MONO_TYPE_BOOLEAN:
6327 mono_mb_emit_ldarg (mb, argnum);
6328 mono_mb_emit_ldloc (mb, tmp_locals [i]);
6329 if (mspecs [i + 1] != NULL && mspecs [i + 1]->native == MONO_NATIVE_VARIANTBOOL)
6330 mono_mb_emit_byte (mb, CEE_NEG);
6331 mono_mb_emit_byte (mb, CEE_STIND_I1);
6335 if (!MONO_TYPE_IS_VOID(sig->ret))
6336 mono_mb_emit_ldloc (mb, 3);
6338 mono_mb_emit_byte (mb, CEE_RET);
6342 * mono_marshal_get_native_wrapper:
6343 * @method: The MonoMethod to wrap.
6345 * generates IL code for the pinvoke wrapper (the generated method
6346 * calls the unmanaged code in piinfo->addr)
6349 mono_marshal_get_native_wrapper (MonoMethod *method)
6351 MonoMethodSignature *sig, *csig;
6352 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
6353 MonoMethodBuilder *mb;
6354 MonoMarshalSpec **mspecs;
6357 gboolean pinvoke = FALSE;
6359 const char *exc_class = "MissingMethodException";
6360 const char *exc_arg = NULL;
6362 g_assert (method != NULL);
6363 g_assert (mono_method_signature (method)->pinvoke);
6365 cache = method->klass->image->native_wrapper_cache;
6366 if ((res = mono_marshal_find_in_cache (cache, method)))
6369 sig = mono_method_signature (method);
6371 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
6372 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
6375 if (!piinfo->addr) {
6377 mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
6379 piinfo->addr = mono_lookup_internal_call (method);
6382 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
6384 mb->method->save_lmf = 1;
6386 if (!piinfo->addr) {
6387 mono_mb_emit_exception (mb, exc_class, exc_arg);
6388 csig = mono_metadata_signature_dup (sig);
6390 res = mono_mb_create_and_cache (cache, method,
6391 mb, csig, csig->param_count + 16);
6396 /* internal calls: we simply push all arguments and call the method (no conversions) */
6397 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
6399 /* hack - string constructors returns a value */
6400 if (method->string_ctor) {
6401 csig = mono_metadata_signature_dup (sig);
6402 csig->ret = &mono_defaults.string_class->byval_arg;
6407 mono_mb_emit_byte (mb, CEE_LDARG_0);
6409 for (i = 0; i < sig->param_count; i++)
6410 mono_mb_emit_ldarg (mb, i + sig->hasthis);
6412 g_assert (piinfo->addr);
6413 mono_mb_emit_native_call (mb, csig, piinfo->addr);
6414 emit_thread_interrupt_checkpoint (mb);
6415 mono_mb_emit_byte (mb, CEE_RET);
6417 csig = mono_metadata_signature_dup (csig);
6419 res = mono_mb_create_and_cache (cache, method,
6420 mb, csig, csig->param_count + 16);
6427 mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
6428 mono_method_get_marshal_info (method, mspecs);
6430 mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, piinfo->addr);
6432 csig = mono_metadata_signature_dup (sig);
6434 res = mono_mb_create_and_cache (cache, method,
6435 mb, csig, csig->param_count + 16);
6438 for (i = sig->param_count; i >= 0; i--)
6440 mono_metadata_free_marshal_spec (mspecs [i]);
6443 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
6449 * mono_marshal_get_native_func_wrapper:
6450 * @sig: The signature of the function
6451 * @func: The native function to wrap
6453 * Returns a wrapper method around native functions, similar to the pinvoke
6457 mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig,
6458 MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
6460 MonoMethodSignature *csig;
6462 MonoMethodBuilder *mb;
6467 cache = mono_defaults.corlib->native_wrapper_cache;
6468 if ((res = mono_marshal_find_in_cache (cache, func)))
6471 name = g_strdup_printf ("wrapper_native_%p", func);
6472 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
6473 mb->method->save_lmf = 1;
6475 mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, func);
6477 csig = mono_metadata_signature_dup (sig);
6479 res = mono_mb_create_and_cache (cache, func,
6480 mb, csig, csig->param_count + 16);
6483 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
6489 * generates IL code to call managed methods from unmanaged code
6492 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
6494 static MonoClass *UnmanagedFunctionPointerAttribute;
6495 MonoMethodSignature *sig, *csig, *invoke_sig;
6496 MonoMethodBuilder *mb;
6497 MonoMethod *res, *invoke;
6498 MonoMarshalSpec **mspecs;
6499 MonoMethodPInvoke piinfo;
6502 EmitMarshalContext m;
6504 g_assert (method != NULL);
6505 g_assert (!mono_method_signature (method)->pinvoke);
6508 * FIXME: Should cache the method+delegate type pair, since the same method
6509 * could be called with different delegates, thus different marshalling
6512 cache = method->klass->image->managed_wrapper_cache;
6513 if (!this && (res = mono_marshal_find_in_cache (cache, method)))
6516 invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
6517 invoke_sig = mono_method_signature (invoke);
6519 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
6520 mono_method_get_marshal_info (invoke, mspecs);
6522 sig = mono_method_signature (method);
6524 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
6526 /* allocate local 0 (pointer) src_ptr */
6527 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6528 /* allocate local 1 (pointer) dst_ptr */
6529 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6530 /* allocate local 2 (boolean) delete_old */
6531 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
6533 if (!MONO_TYPE_IS_VOID(sig->ret)) {
6534 /* allocate local 3 to store the return value */
6535 mono_mb_add_local (mb, sig->ret);
6538 mono_mb_emit_icon (mb, 0);
6539 mono_mb_emit_stloc (mb, 2);
6541 /* we copy the signature, so that we can modify it */
6542 csig = mono_metadata_signature_dup (sig);
6551 #ifdef PLATFORM_WIN32
6553 * Under windows, delegates passed to native code must use the STDCALL
6554 * calling convention.
6556 csig->call_convention = MONO_CALL_STDCALL;
6559 /* Change default calling convention if needed */
6560 /* Why is this a modopt ? */
6561 if (invoke_sig->ret && invoke_sig->ret->num_mods) {
6562 for (i = 0; i < invoke_sig->ret->num_mods; ++i) {
6563 MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token);
6564 g_assert (cmod_class);
6565 if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
6566 if (!strcmp (cmod_class->name, "CallConvCdecl"))
6567 csig->call_convention = MONO_CALL_C;
6568 else if (!strcmp (cmod_class->name, "CallConvStdcall"))
6569 csig->call_convention = MONO_CALL_STDCALL;
6570 else if (!strcmp (cmod_class->name, "CallConvFastcall"))
6571 csig->call_convention = MONO_CALL_FASTCALL;
6572 else if (!strcmp (cmod_class->name, "CallConvThiscall"))
6573 csig->call_convention = MONO_CALL_THISCALL;
6578 /* Handle the UnmanagedFunctionPointerAttribute */
6579 if (!UnmanagedFunctionPointerAttribute)
6580 UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
6582 /* The attribute is only available in Net 2.0 */
6583 if (UnmanagedFunctionPointerAttribute) {
6584 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
6585 MonoCustomAttrInfo *cinfo;
6588 * The pinvoke attributes are stored in a real custom attribute so we have to
6591 cinfo = mono_custom_attrs_from_class (delegate_klass);
6593 attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
6595 memset (&piinfo, 0, sizeof (piinfo));
6597 piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
6599 csig->call_convention = attr->call_conv - 1;
6602 mono_custom_attrs_free (cinfo);
6606 /* fixme: howto handle this ? */
6609 mono_mb_emit_ptr (mb, this);
6612 g_assert_not_reached ();
6616 /* we first do all conversions */
6617 tmp_locals = alloca (sizeof (int) * sig->param_count);
6618 for (i = 0; i < sig->param_count; i ++) {
6619 MonoType *t = sig->params [i];
6622 case MONO_TYPE_OBJECT:
6623 case MONO_TYPE_CLASS:
6624 case MONO_TYPE_VALUETYPE:
6625 case MONO_TYPE_ARRAY:
6626 case MONO_TYPE_SZARRAY:
6627 case MONO_TYPE_STRING:
6628 tmp_locals [i] = emit_marshal (&m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
6637 emit_thread_interrupt_checkpoint (mb);
6639 for (i = 0; i < sig->param_count; i++) {
6640 MonoType *t = sig->params [i];
6642 if (tmp_locals [i]) {
6644 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
6646 mono_mb_emit_ldloc (mb, tmp_locals [i]);
6649 mono_mb_emit_ldarg (mb, i);
6652 mono_mb_emit_managed_call (mb, method, NULL);
6654 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
6655 emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
6658 if (!sig->ret->byref) {
6659 switch (sig->ret->type) {
6660 case MONO_TYPE_VOID:
6662 case MONO_TYPE_BOOLEAN:
6676 case MONO_TYPE_OBJECT:
6677 mono_mb_emit_stloc (mb, 3);
6679 case MONO_TYPE_STRING:
6680 csig->ret = &mono_defaults.int_class->byval_arg;
6681 emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
6683 case MONO_TYPE_VALUETYPE:
6684 case MONO_TYPE_CLASS:
6685 case MONO_TYPE_SZARRAY:
6686 emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
6689 g_warning ("return type 0x%02x unknown", sig->ret->type);
6690 g_assert_not_reached ();
6693 mono_mb_emit_stloc (mb, 3);
6696 /* Convert byref arguments back */
6697 for (i = 0; i < sig->param_count; i ++) {
6698 MonoType *t = sig->params [i];
6699 MonoMarshalSpec *spec = mspecs [i + 1];
6701 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
6702 emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
6704 else if (t->byref) {
6706 case MONO_TYPE_CLASS:
6707 case MONO_TYPE_VALUETYPE:
6708 emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
6712 else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
6713 /* The [Out] information is encoded in the delegate signature */
6715 case MONO_TYPE_SZARRAY:
6716 emit_marshal (&m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
6719 g_assert_not_reached ();
6725 mono_mb_emit_ldloc (mb, m.retobj_var);
6726 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6727 mono_mb_emit_byte (mb, CEE_MONO_RETOBJ);
6728 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, m.retobj_class));
6731 if (!MONO_TYPE_IS_VOID(sig->ret))
6732 mono_mb_emit_ldloc (mb, 3);
6733 mono_mb_emit_byte (mb, CEE_RET);
6737 res = mono_mb_create_and_cache (cache, method,
6738 mb, csig, sig->param_count + 16);
6740 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
6745 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
6747 mono_metadata_free_marshal_spec (mspecs [i]);
6750 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
6755 static MonoReflectionType *
6756 type_from_handle (MonoType *handle)
6758 MonoDomain *domain = mono_domain_get ();
6759 MonoClass *klass = mono_class_from_mono_type (handle);
6761 MONO_ARCH_SAVE_REGS;
6763 mono_class_init (klass);
6764 return mono_type_get_object (domain, handle);
6768 * mono_marshal_get_isinst:
6769 * @klass: the type of the field
6771 * This method generates a function which can be used to check if an object is
6772 * an instance of the given type, icluding the case where the object is a proxy.
6773 * The generated function has the following signature:
6774 * MonoObject* __isinst_wrapper_ (MonoObject *obj)
6777 mono_marshal_get_isinst (MonoClass *klass)
6779 static MonoMethodSignature *isint_sig = NULL;
6780 static GHashTable *isinst_hash = NULL;
6782 int pos_was_ok, pos_failed, pos_end, pos_end2;
6784 MonoMethodBuilder *mb;
6786 mono_marshal_lock ();
6788 isinst_hash = g_hash_table_new (NULL, NULL);
6790 res = g_hash_table_lookup (isinst_hash, klass);
6791 mono_marshal_unlock ();
6796 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
6797 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
6798 isint_sig->ret = &mono_defaults.object_class->byval_arg;
6799 isint_sig->pinvoke = 0;
6802 name = g_strdup_printf ("__isinst_wrapper_%s", klass->name);
6803 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
6806 mb->method->save_lmf = 1;
6808 /* check if the object is a proxy that needs special cast */
6809 mono_mb_emit_ldarg (mb, 0);
6810 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6811 mono_mb_emit_byte (mb, CEE_MONO_CISINST);
6812 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
6814 /* The result of MONO_ISINST can be:
6815 0) the type check succeeded
6816 1) the type check did not succeed
6817 2) a CanCastTo call is needed */
6819 mono_mb_emit_byte (mb, CEE_DUP);
6820 pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
6822 mono_mb_emit_byte (mb, CEE_LDC_I4_2);
6823 pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
6825 /* get the real proxy from the transparent proxy*/
6827 mono_mb_emit_ldarg (mb, 0);
6828 mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
6829 pos_end = mono_mb_emit_branch (mb, CEE_BR);
6833 mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
6834 mono_mb_emit_byte (mb, CEE_LDNULL);
6835 pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
6839 mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
6840 mono_mb_emit_byte (mb, CEE_POP);
6841 mono_mb_emit_ldarg (mb, 0);
6845 mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
6846 mono_mb_patch_addr (mb, pos_end2, mb->pos - (pos_end2 + 4));
6847 mono_mb_emit_byte (mb, CEE_RET);
6849 res = mono_mb_create_and_cache (isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
6856 * mono_marshal_get_castclass:
6857 * @klass: the type of the field
6859 * This method generates a function which can be used to cast an object to
6860 * an instance of the given type, icluding the case where the object is a proxy.
6861 * The generated function has the following signature:
6862 * MonoObject* __castclass_wrapper_ (MonoObject *obj)
6865 mono_marshal_get_castclass (MonoClass *klass)
6867 static MonoMethodSignature *castclass_sig = NULL;
6868 static GHashTable *castclass_hash = NULL;
6870 int pos_was_ok, pos_was_ok2;
6872 MonoMethodBuilder *mb;
6874 mono_marshal_lock ();
6875 if (!castclass_hash)
6876 castclass_hash = g_hash_table_new (NULL, NULL);
6878 res = g_hash_table_lookup (castclass_hash, klass);
6879 mono_marshal_unlock ();
6883 if (!castclass_sig) {
6884 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
6885 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
6886 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
6887 castclass_sig->pinvoke = 0;
6890 name = g_strdup_printf ("__castclass_wrapper_%s", klass->name);
6891 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
6894 mb->method->save_lmf = 1;
6896 /* check if the object is a proxy that needs special cast */
6897 mono_mb_emit_ldarg (mb, 0);
6898 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6899 mono_mb_emit_byte (mb, CEE_MONO_CCASTCLASS);
6900 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
6902 /* The result of MONO_ISINST can be:
6903 0) the cast is valid
6904 1) cast of unknown proxy type
6905 or an exception if the cast is is invalid
6908 pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
6910 /* get the real proxy from the transparent proxy*/
6912 mono_mb_emit_ldarg (mb, 0);
6913 mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
6914 pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
6917 mono_mb_emit_exception (mb, "InvalidCastException", NULL);
6920 mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
6921 mono_mb_patch_addr (mb, pos_was_ok2, mb->pos - (pos_was_ok2 + 4));
6922 mono_mb_emit_ldarg (mb, 0);
6925 mono_mb_emit_byte (mb, CEE_RET);
6927 res = mono_mb_create_and_cache (castclass_hash, klass, mb, castclass_sig, castclass_sig->param_count + 16);
6934 mono_marshal_get_proxy_cancast (MonoClass *klass)
6936 static MonoMethodSignature *isint_sig = NULL;
6937 static GHashTable *proxy_isinst_hash = NULL;
6939 int pos_failed, pos_end;
6941 MonoMethod *can_cast_to;
6942 MonoMethodDesc *desc;
6943 MonoMethodBuilder *mb;
6945 mono_marshal_lock ();
6946 if (!proxy_isinst_hash)
6947 proxy_isinst_hash = g_hash_table_new (NULL, NULL);
6949 res = g_hash_table_lookup (proxy_isinst_hash, klass);
6950 mono_marshal_unlock ();
6955 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
6956 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
6957 isint_sig->ret = &mono_defaults.object_class->byval_arg;
6958 isint_sig->pinvoke = 0;
6961 name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name);
6962 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
6965 mb->method->save_lmf = 1;
6967 /* get the real proxy from the transparent proxy*/
6968 mono_mb_emit_ldarg (mb, 0);
6969 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
6970 mono_mb_emit_byte (mb, CEE_LDIND_REF);
6972 /* get the reflection type from the type handle */
6973 mono_mb_emit_ptr (mb, &klass->byval_arg);
6974 mono_mb_emit_icall (mb, type_from_handle);
6976 mono_mb_emit_ldarg (mb, 0);
6978 /* make the call to CanCastTo (type, ob) */
6979 desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
6980 can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
6981 g_assert (can_cast_to);
6982 mono_method_desc_free (desc);
6983 mono_mb_emit_byte (mb, CEE_CALLVIRT);
6984 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, can_cast_to));
6987 pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
6989 /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
6990 mono_mb_emit_ptr (mb, &klass->byval_arg);
6991 mono_mb_emit_icall (mb, type_from_handle);
6992 mono_mb_emit_ldarg (mb, 0);
6994 mono_mb_emit_icall (mb, mono_upgrade_remote_class_wrapper);
6995 emit_thread_interrupt_checkpoint (mb);
6997 mono_mb_emit_ldarg (mb, 0);
6998 pos_end = mono_mb_emit_branch (mb, CEE_BR);
7002 mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
7003 mono_mb_emit_byte (mb, CEE_LDNULL);
7007 mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
7008 mono_mb_emit_byte (mb, CEE_RET);
7010 res = mono_mb_create_and_cache (proxy_isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
7017 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
7020 MonoDomain *domain = ((MonoObject*)tproxy)->vtable->domain;
7021 klass = mono_class_from_mono_type (rtype->type);
7022 mono_upgrade_remote_class (domain, (MonoObject*)tproxy, klass);
7026 * mono_marshal_get_struct_to_ptr:
7029 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
7032 mono_marshal_get_struct_to_ptr (MonoClass *klass)
7034 MonoMethodBuilder *mb;
7035 static MonoMethod *stoptr = NULL;
7038 g_assert (klass != NULL);
7040 mono_marshal_load_type_info (klass);
7042 if (klass->marshal_info->str_to_ptr)
7043 return klass->marshal_info->str_to_ptr;
7046 stoptr = mono_class_get_method_from_name (mono_defaults.marshal_class, "StructureToPtr", 3);
7049 mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
7051 if (klass->blittable) {
7052 mono_mb_emit_byte (mb, CEE_LDARG_1);
7053 mono_mb_emit_byte (mb, CEE_LDARG_0);
7054 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7055 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
7056 mono_mb_emit_byte (mb, CEE_PREFIX1);
7057 mono_mb_emit_byte (mb, CEE_CPBLK);
7060 /* allocate local 0 (pointer) src_ptr */
7061 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7062 /* allocate local 1 (pointer) dst_ptr */
7063 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7064 /* allocate local 2 (boolean) delete_old */
7065 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
7066 mono_mb_emit_byte (mb, CEE_LDARG_2);
7067 mono_mb_emit_stloc (mb, 2);
7069 /* initialize src_ptr to point to the start of object data */
7070 mono_mb_emit_byte (mb, CEE_LDARG_0);
7071 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7072 mono_mb_emit_stloc (mb, 0);
7074 /* initialize dst_ptr */
7075 mono_mb_emit_byte (mb, CEE_LDARG_1);
7076 mono_mb_emit_byte (mb, CEE_STLOC_1);
7078 emit_struct_conv (mb, klass, FALSE);
7081 mono_mb_emit_byte (mb, CEE_RET);
7083 res = mono_mb_create_method (mb, mono_method_signature (stoptr), 0);
7086 klass->marshal_info->str_to_ptr = res;
7091 * mono_marshal_get_ptr_to_struct:
7094 * generates IL code for PtrToStructure (IntPtr src, object structure)
7097 mono_marshal_get_ptr_to_struct (MonoClass *klass)
7099 MonoMethodBuilder *mb;
7100 static MonoMethodSignature *ptostr = NULL;
7103 g_assert (klass != NULL);
7105 mono_marshal_load_type_info (klass);
7107 if (klass->marshal_info->ptr_to_str)
7108 return klass->marshal_info->ptr_to_str;
7111 /* Create the signature corresponding to
7112 static void PtrToStructure (IntPtr ptr, object structure);
7113 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
7114 ptostr = mono_create_icall_signature ("void ptr object");
7116 mb = mono_mb_new (klass, "PtrToStructure", MONO_WRAPPER_UNKNOWN);
7118 if (klass->blittable) {
7119 mono_mb_emit_byte (mb, CEE_LDARG_1);
7120 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7121 mono_mb_emit_byte (mb, CEE_LDARG_0);
7122 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
7123 mono_mb_emit_byte (mb, CEE_PREFIX1);
7124 mono_mb_emit_byte (mb, CEE_CPBLK);
7127 /* allocate local 0 (pointer) src_ptr */
7128 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7129 /* allocate local 1 (pointer) dst_ptr */
7130 mono_mb_add_local (mb, &klass->this_arg);
7132 /* initialize src_ptr to point to the start of object data */
7133 mono_mb_emit_byte (mb, CEE_LDARG_0);
7134 mono_mb_emit_stloc (mb, 0);
7136 /* initialize dst_ptr */
7137 mono_mb_emit_byte (mb, CEE_LDARG_1);
7138 mono_mb_emit_byte (mb, CEE_UNBOX);
7139 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
7140 mono_mb_emit_stloc (mb, 1);
7142 emit_struct_conv (mb, klass, TRUE);
7145 mono_mb_emit_byte (mb, CEE_RET);
7147 res = mono_mb_create_method (mb, ptostr, 0);
7150 klass->marshal_info->ptr_to_str = res;
7155 * generates IL code for the synchronized wrapper: the generated method
7156 * calls METHOD while locking 'this' or the parent type.
7159 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
7161 static MonoMethod *enter_method, *exit_method;
7162 MonoMethodSignature *sig;
7163 MonoExceptionClause *clause;
7164 MonoMethodHeader *header;
7165 MonoMethodBuilder *mb;
7168 int i, pos, this_local, ret_local = 0;
7172 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
7175 cache = method->klass->image->synchronized_cache;
7176 if ((res = mono_marshal_find_in_cache (cache, method)))
7179 sig = signature_no_pinvoke (mono_method_signature (method));
7181 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
7184 if (!MONO_TYPE_IS_VOID (sig->ret))
7185 ret_local = mono_mb_add_local (mb, sig->ret);
7188 this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7190 clause = g_new0 (MonoExceptionClause, 1);
7191 clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
7193 if (!enter_method) {
7194 MonoMethodDesc *desc;
7196 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
7197 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
7198 g_assert (enter_method);
7199 mono_method_desc_free (desc);
7200 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
7201 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
7202 g_assert (exit_method);
7203 mono_method_desc_free (desc);
7206 /* Push this or the type object */
7207 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
7209 * GetTypeFromHandle isn't called as a managed method because it has
7210 * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
7211 * transformed into something else by the JIT.
7213 mono_mb_emit_ptr (mb, &method->klass->byval_arg);
7214 mono_mb_emit_icall (mb, type_from_handle);
7217 mono_mb_emit_ldarg (mb, 0);
7218 mono_mb_emit_stloc (mb, this_local);
7220 /* Call Monitor::Enter() */
7221 mono_mb_emit_ldloc (mb, this_local);
7222 mono_mb_emit_managed_call (mb, enter_method, NULL);
7224 clause->try_offset = mb->pos;
7226 /* Call the method */
7228 mono_mb_emit_ldarg (mb, 0);
7229 for (i = 0; i < sig->param_count; i++)
7230 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
7232 /* this is needed to avoid recursion */
7233 mono_mb_emit_byte (mb, CEE_PREFIX1);
7234 mono_mb_emit_byte (mb, CEE_LDFTN);
7235 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
7236 mono_mb_emit_calli (mb, mono_method_signature (method));
7238 if (!MONO_TYPE_IS_VOID (sig->ret))
7239 mono_mb_emit_stloc (mb, ret_local);
7241 mono_mb_emit_byte (mb, CEE_LEAVE);
7243 mono_mb_emit_i4 (mb, 0);
7245 clause->try_len = mb->pos - clause->try_offset;
7246 clause->handler_offset = mb->pos;
7248 /* Call Monitor::Exit() */
7249 mono_mb_emit_ldloc (mb, this_local);
7250 /* mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */
7251 mono_mb_emit_managed_call (mb, exit_method, NULL);
7252 mono_mb_emit_byte (mb, CEE_ENDFINALLY);
7254 clause->handler_len = mb->pos - clause->handler_offset;
7256 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
7257 if (!MONO_TYPE_IS_VOID (sig->ret))
7258 mono_mb_emit_ldloc (mb, ret_local);
7259 mono_mb_emit_byte (mb, CEE_RET);
7261 res = mono_mb_create_and_cache (cache, method,
7262 mb, sig, sig->param_count + 16);
7265 header = ((MonoMethodNormal *)res)->header;
7266 header->num_clauses = 1;
7267 header->clauses = clause;
7274 * the returned method calls 'method' unboxing the this argument
7277 mono_marshal_get_unbox_wrapper (MonoMethod *method)
7279 MonoMethodSignature *sig = mono_method_signature (method);
7281 MonoMethodBuilder *mb;
7285 cache = method->klass->image->unbox_wrapper_cache;
7286 if ((res = mono_marshal_find_in_cache (cache, method)))
7289 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNBOX);
7291 g_assert (sig->hasthis);
7293 mono_mb_emit_ldarg (mb, 0);
7294 mono_mb_emit_icon (mb, sizeof (MonoObject));
7295 mono_mb_emit_byte (mb, CEE_ADD);
7296 for (i = 0; i < sig->param_count; ++i)
7297 mono_mb_emit_ldarg (mb, i + 1);
7298 mono_mb_emit_managed_call (mb, method, NULL);
7299 mono_mb_emit_byte (mb, CEE_RET);
7301 res = mono_mb_create_and_cache (cache, method,
7302 mb, sig, sig->param_count + 16);
7305 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
7311 mono_marshal_get_stelemref ()
7313 static MonoMethod* ret = NULL;
7314 MonoMethodSignature *sig;
7315 MonoMethodBuilder *mb;
7317 guint32 b1, b2, b3, b4;
7320 int array_slot_addr;
7325 mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
7328 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
7330 /* void stelemref (void* array, int idx, void* value) */
7331 sig->ret = &mono_defaults.void_class->byval_arg;
7332 sig->params [0] = &mono_defaults.object_class->byval_arg;
7333 sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
7334 sig->params [2] = &mono_defaults.object_class->byval_arg;
7336 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7337 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7338 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
7342 <ldelema (bound check)>
7346 aklass = array->vtable->klass->element_class;
7347 vklass = value->vtable->klass;
7349 if (vklass->idepth < aklass->idepth)
7352 if (vklass->supertypes [aklass->idepth - 1] != aklass)
7356 *array_slot_addr = value;
7360 if (mono_object_isinst (value, aklass))
7363 throw new ArrayTypeMismatchException ();
7366 /* ldelema (implicit bound check) */
7367 mono_mb_emit_ldarg (mb, 0);
7368 mono_mb_emit_ldarg (mb, 1);
7369 mono_mb_emit_byte (mb, CEE_LDELEMA);
7370 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.object_class));
7371 mono_mb_emit_stloc (mb, array_slot_addr);
7373 /* if (!value) goto do_store */
7374 mono_mb_emit_ldarg (mb, 2);
7375 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7377 /* aklass = array->vtable->klass->element_class */
7378 mono_mb_emit_ldarg (mb, 0);
7379 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
7380 mono_mb_emit_byte (mb, CEE_LDIND_I);
7381 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
7382 mono_mb_emit_byte (mb, CEE_LDIND_I);
7383 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
7384 mono_mb_emit_byte (mb, CEE_LDIND_I);
7385 mono_mb_emit_stloc (mb, aklass);
7387 /* vklass = value->vtable->klass */
7388 mono_mb_emit_ldarg (mb, 2);
7389 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
7390 mono_mb_emit_byte (mb, CEE_LDIND_I);
7391 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
7392 mono_mb_emit_byte (mb, CEE_LDIND_I);
7393 mono_mb_emit_stloc (mb, vklass);
7395 /* if (vklass->idepth < aklass->idepth) goto failue */
7396 mono_mb_emit_ldloc (mb, vklass);
7397 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
7398 mono_mb_emit_byte (mb, CEE_LDIND_U2);
7400 mono_mb_emit_ldloc (mb, aklass);
7401 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
7402 mono_mb_emit_byte (mb, CEE_LDIND_U2);
7404 b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
7406 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
7407 mono_mb_emit_ldloc (mb, vklass);
7408 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
7409 mono_mb_emit_byte (mb, CEE_LDIND_I);
7411 mono_mb_emit_ldloc (mb, aklass);
7412 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
7413 mono_mb_emit_byte (mb, CEE_LDIND_U2);
7414 mono_mb_emit_icon (mb, 1);
7415 mono_mb_emit_byte (mb, CEE_SUB);
7416 mono_mb_emit_icon (mb, sizeof (void*));
7417 mono_mb_emit_byte (mb, CEE_MUL);
7418 mono_mb_emit_byte (mb, CEE_ADD);
7419 mono_mb_emit_byte (mb, CEE_LDIND_I);
7421 mono_mb_emit_ldloc (mb, aklass);
7423 b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
7427 mono_mb_patch_addr (mb, b1, mb->pos - (b1 + 4));
7428 mono_mb_emit_ldloc (mb, array_slot_addr);
7429 mono_mb_emit_ldarg (mb, 2);
7430 mono_mb_emit_byte (mb, CEE_STIND_REF);
7432 mono_mb_emit_byte (mb, CEE_RET);
7435 mono_mb_patch_addr (mb, b2, mb->pos - (b2 + 4));
7436 mono_mb_patch_addr (mb, b3, mb->pos - (b3 + 4));
7438 mono_mb_emit_ldarg (mb, 2);
7439 mono_mb_emit_ldloc (mb, aklass);
7440 mono_mb_emit_icall (mb, mono_object_isinst);
7442 b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
7443 mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
7444 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
7446 mono_mb_emit_byte (mb, CEE_RET);
7447 ret = mono_mb_create_method (mb, sig, 4);
7453 mono_marshal_alloc (gulong size)
7457 #ifdef PLATFORM_WIN32
7458 res = CoTaskMemAlloc (size);
7460 res = g_try_malloc ((gulong)size);
7462 mono_gc_out_of_memory ((gulong)size);
7468 mono_marshal_free (gpointer ptr)
7470 #ifdef PLATFORM_WIN32
7471 CoTaskMemFree (ptr);
7478 mono_marshal_free_array (gpointer *ptr, int size)
7485 for (i = 0; i < size; i++)
7491 mono_marshal_realloc (gpointer ptr, gpointer size)
7493 MONO_ARCH_SAVE_REGS;
7495 return g_try_realloc (ptr, (gulong)size);
7499 mono_marshal_string_to_utf16 (MonoString *s)
7501 return s ? mono_string_chars (s) : NULL;
7505 * mono_marshal_set_last_error:
7507 * This function is invoked to set the last error value from a P/Invoke call
7508 * which has SetLastError set.
7511 mono_marshal_set_last_error (void)
7514 TlsSetValue (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
7516 TlsSetValue (last_error_tls_id, GINT_TO_POINTER (errno));
7521 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
7522 gpointer dest, gint32 length)
7527 MONO_ARCH_SAVE_REGS;
7529 MONO_CHECK_ARG_NULL (src);
7530 MONO_CHECK_ARG_NULL (dest);
7532 g_assert (src->obj.vtable->klass->rank == 1);
7533 g_assert (start_index >= 0);
7534 g_assert (length >= 0);
7535 g_assert (start_index + length <= mono_array_length (src));
7537 element_size = mono_array_element_size (src->obj.vtable->klass);
7539 /* no references should be involved */
7540 source_addr = mono_array_addr_with_size (src, element_size, start_index);
7542 memcpy (dest, source_addr, length * element_size);
7546 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
7547 MonoArray *dest, gint32 length)
7552 MONO_ARCH_SAVE_REGS;
7554 MONO_CHECK_ARG_NULL (src);
7555 MONO_CHECK_ARG_NULL (dest);
7557 g_assert (dest->obj.vtable->klass->rank == 1);
7558 g_assert (start_index >= 0);
7559 g_assert (length >= 0);
7560 g_assert (start_index + length <= mono_array_length (dest));
7562 element_size = mono_array_element_size (dest->obj.vtable->klass);
7564 /* no references should be involved */
7565 dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
7567 memcpy (dest_addr, src, length * element_size);
7570 #if NO_UNALIGNED_ACCESS
7571 #define RETURN_UNALIGNED(type, addr) \
7574 memcpy(&val, p + offset, sizeof(val)); \
7577 #define WRITE_UNALIGNED(type, addr, val) \
7578 memcpy(addr, &val, sizeof(type))
7580 #define RETURN_UNALIGNED(type, addr) \
7581 return *(type*)(p + offset);
7582 #define WRITE_UNALIGNED(type, addr, val) \
7583 (*(type *)(addr) = (val))
7587 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
7591 MONO_ARCH_SAVE_REGS;
7593 RETURN_UNALIGNED(gpointer, p + offset);
7597 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
7601 MONO_ARCH_SAVE_REGS;
7603 return *(unsigned char*)(p + offset);
7607 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
7611 MONO_ARCH_SAVE_REGS;
7613 RETURN_UNALIGNED(gint16, p + offset);
7617 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
7621 MONO_ARCH_SAVE_REGS;
7623 RETURN_UNALIGNED(gint32, p + offset);
7627 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
7631 MONO_ARCH_SAVE_REGS;
7633 RETURN_UNALIGNED(gint64, p + offset);
7637 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
7641 MONO_ARCH_SAVE_REGS;
7643 *(unsigned char*)(p + offset) = val;
7647 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
7651 MONO_ARCH_SAVE_REGS;
7653 WRITE_UNALIGNED(gpointer, p + offset, val);
7657 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
7661 MONO_ARCH_SAVE_REGS;
7663 WRITE_UNALIGNED(gint16, p + offset, val);
7667 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
7671 MONO_ARCH_SAVE_REGS;
7673 WRITE_UNALIGNED(gint32, p + offset, val);
7677 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
7681 MONO_ARCH_SAVE_REGS;
7683 WRITE_UNALIGNED(gint64, p + offset, val);
7687 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
7689 MONO_ARCH_SAVE_REGS;
7694 return mono_string_new (mono_domain_get (), ptr);
7698 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
7700 MONO_ARCH_SAVE_REGS;
7703 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
7704 g_assert_not_reached ();
7707 return mono_string_new_len (mono_domain_get (), ptr, len);
7711 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
7713 MonoDomain *domain = mono_domain_get ();
7717 MONO_ARCH_SAVE_REGS;
7725 return mono_string_new_utf16 (domain, ptr, len);
7729 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
7731 MonoDomain *domain = mono_domain_get ();
7733 MONO_ARCH_SAVE_REGS;
7736 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
7737 g_assert_not_reached ();
7740 return mono_string_new_utf16 (domain, ptr, len);
7744 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
7746 MONO_ARCH_SAVE_REGS;
7748 g_warning ("PtrToStringBSTR not implemented");
7749 g_assert_not_reached ();
7755 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
7757 MONO_ARCH_SAVE_REGS;
7759 return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id)));
7763 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
7769 MONO_ARCH_SAVE_REGS;
7771 MONO_CHECK_ARG_NULL (rtype);
7774 klass = mono_class_from_mono_type (type);
7775 layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
7777 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
7781 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
7782 exc = mono_get_exception_argument ("t", msg);
7784 mono_raise_exception (exc);
7788 return mono_class_native_size (klass, NULL);
7792 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
7797 MONO_ARCH_SAVE_REGS;
7799 MONO_CHECK_ARG_NULL (obj);
7800 MONO_CHECK_ARG_NULL (dst);
7802 method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
7806 pa [2] = &delete_old;
7808 mono_runtime_invoke (method, NULL, pa, NULL);
7812 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
7817 MONO_ARCH_SAVE_REGS;
7819 MONO_CHECK_ARG_NULL (src);
7820 MONO_CHECK_ARG_NULL (dst);
7822 method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
7827 mono_runtime_invoke (method, NULL, pa, NULL);
7831 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
7833 MonoDomain *domain = mono_domain_get ();
7836 MONO_ARCH_SAVE_REGS;
7838 MONO_CHECK_ARG_NULL (src);
7839 MONO_CHECK_ARG_NULL (type);
7841 res = mono_object_new (domain, mono_class_from_mono_type (type->type));
7843 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res);
7849 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
7851 MonoMarshalType *info;
7854 int match_index = -1;
7856 MONO_ARCH_SAVE_REGS;
7858 MONO_CHECK_ARG_NULL (type);
7859 MONO_CHECK_ARG_NULL (field_name);
7861 fname = mono_string_to_utf8 (field_name);
7862 klass = mono_class_from_mono_type (type->type);
7864 while (klass && match_index == -1) {
7865 MonoClassField* field;
7867 gpointer iter = NULL;
7868 while ((field = mono_class_get_fields (klass, &iter))) {
7869 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
7871 if (!strcmp (fname, field->name)) {
7878 if (match_index == -1)
7879 klass = klass->parent;
7884 if(match_index == -1) {
7888 /* Get back original class instance */
7889 klass = mono_class_from_mono_type (type->type);
7891 tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
7892 exc = mono_get_exception_argument ("fieldName", tmp);
7895 mono_raise_exception ((MonoException*)exc);
7898 info = mono_marshal_load_type_info (klass);
7899 return info->fields [match_index].offset;
7903 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
7905 MONO_ARCH_SAVE_REGS;
7907 return mono_string_to_utf8 (string);
7911 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
7913 MONO_ARCH_SAVE_REGS;
7918 gunichar2 *res = g_malloc ((mono_string_length (string) + 1) * 2);
7919 memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
7920 res [mono_string_length (string)] = 0;
7926 mono_struct_delete_old (MonoClass *klass, char *ptr)
7928 MonoMarshalType *info;
7931 info = mono_marshal_load_type_info (klass);
7933 for (i = 0; i < info->num_fields; i++) {
7934 MonoMarshalNative ntype;
7935 MonoMarshalConv conv;
7936 MonoType *ftype = info->fields [i].field->type;
7939 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
7942 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE,
7943 klass->unicode, &conv);
7945 cpos = ptr + info->fields [i].offset;
7948 case MONO_MARSHAL_CONV_NONE:
7949 if (MONO_TYPE_ISSTRUCT (ftype)) {
7950 mono_struct_delete_old (ftype->data.klass, cpos);
7954 case MONO_MARSHAL_CONV_STR_LPWSTR:
7955 /* We assume this field points inside a MonoString */
7957 case MONO_MARSHAL_CONV_STR_LPSTR:
7958 case MONO_MARSHAL_CONV_STR_LPTSTR:
7959 case MONO_MARSHAL_CONV_STR_BSTR:
7960 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
7961 case MONO_MARSHAL_CONV_STR_TBSTR:
7962 mono_marshal_free (*(gpointer *)cpos);
7971 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
7975 MONO_ARCH_SAVE_REGS;
7977 MONO_CHECK_ARG_NULL (src);
7978 MONO_CHECK_ARG_NULL (type);
7980 klass = mono_class_from_mono_type (type->type);
7982 mono_struct_delete_old (klass, (char *)src);
7986 /* FIXME: on win32 we should probably use GlobalAlloc(). */
7988 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
7992 MONO_ARCH_SAVE_REGS;
7994 if ((gulong)size == 0)
7995 /* This returns a valid pointer for size 0 on MS.NET */
7998 res = g_try_malloc ((gulong)size);
8000 mono_gc_out_of_memory ((gulong)size);
8006 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
8008 MONO_ARCH_SAVE_REGS;
8014 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
8016 MONO_ARCH_SAVE_REGS;
8018 #ifdef PLATFORM_WIN32
8019 return CoTaskMemAlloc (size);
8021 return g_try_malloc ((gulong)size);
8026 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
8028 MONO_ARCH_SAVE_REGS;
8030 #ifdef PLATFORM_WIN32
8031 CoTaskMemFree (ptr);
8038 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
8040 return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
8044 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type)
8046 return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn);
8050 mono_marshal_load_type_info (MonoClass* klass)
8053 guint32 native_size = 0, min_align = 1;
8054 MonoMarshalType *info;
8055 MonoClassField* field;
8059 g_assert (klass != NULL);
8061 if (klass->marshal_info)
8062 return klass->marshal_info;
8065 mono_class_init (klass);
8068 while ((field = mono_class_get_fields (klass, &iter))) {
8069 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
8071 if (mono_field_is_deleted (field))
8076 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
8078 klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
8079 info->num_fields = count;
8081 /* Try to find a size for this type in metadata */
8082 mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
8084 if (klass->parent) {
8085 int parent_size = mono_class_native_size (klass->parent, NULL);
8087 /* Add parent size to real size */
8088 native_size += parent_size;
8089 info->native_size = parent_size;
8094 while ((field = mono_class_get_fields (klass, &iter))) {
8098 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
8101 if (mono_field_is_deleted (field))
8103 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
8104 mono_metadata_field_info (klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1,
8105 NULL, NULL, &info->fields [j].mspec);
8107 info->fields [j].field = field;
8109 if ((mono_class_num_fields (klass) == 1) && (klass->instance_size == sizeof (MonoObject)) &&
8110 (strcmp (field->name, "$PRIVATE$") == 0)) {
8111 /* This field is a hack inserted by MCS to empty structures */
8116 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
8117 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
8118 size = mono_marshal_type_size (field->type, info->fields [j].mspec,
8119 &align, TRUE, klass->unicode);
8120 align = klass->packing_size ? MIN (klass->packing_size, align): align;
8121 min_align = MAX (align, min_align);
8122 info->fields [j].offset = info->native_size;
8123 info->fields [j].offset += align - 1;
8124 info->fields [j].offset &= ~(align - 1);
8125 info->native_size = info->fields [j].offset + size;
8127 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
8128 size = mono_marshal_type_size (field->type, info->fields [j].mspec,
8129 &align, TRUE, klass->unicode);
8130 align = klass->packing_size ? MIN (klass->packing_size, align): align;
8131 min_align = MAX (align, min_align);
8132 info->fields [j].offset = field->offset - sizeof (MonoObject);
8133 info->native_size = MAX (info->native_size, info->fields [j].offset + size);
8139 if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
8140 info->native_size = MAX (native_size, info->native_size);
8143 if (info->native_size & (min_align - 1)) {
8144 info->native_size += min_align - 1;
8145 info->native_size &= ~(min_align - 1);
8148 /* Update the class's blittable info, if the layouts don't match */
8149 if (info->native_size != mono_class_value_size (klass, NULL))
8150 klass->blittable = FALSE;
8152 /* If this is an array type, ensure that we have element info */
8153 if (klass->element_class) {
8154 mono_marshal_load_type_info (klass->element_class);
8157 return klass->marshal_info;
8161 * mono_class_native_size:
8164 * Returns: the native size of an object instance (when marshaled
8165 * to unmanaged code)
8168 mono_class_native_size (MonoClass *klass, guint32 *align)
8170 if (!klass->marshal_info)
8171 mono_marshal_load_type_info (klass);
8174 *align = klass->min_align;
8176 return klass->marshal_info->native_size;
8180 * mono_type_native_stack_size:
8181 * @t: the type to return the size it uses on the stack
8183 * Returns: the number of bytes required to hold an instance of this
8184 * type on the native stack
8187 mono_type_native_stack_size (MonoType *t, guint32 *align)
8191 g_assert (t != NULL);
8202 case MONO_TYPE_BOOLEAN:
8203 case MONO_TYPE_CHAR:
8212 case MONO_TYPE_STRING:
8213 case MONO_TYPE_OBJECT:
8214 case MONO_TYPE_CLASS:
8215 case MONO_TYPE_SZARRAY:
8217 case MONO_TYPE_FNPTR:
8218 case MONO_TYPE_ARRAY:
8219 case MONO_TYPE_TYPEDBYREF:
8230 case MONO_TYPE_VALUETYPE: {
8233 if (t->data.klass->enumtype)
8234 return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
8236 size = mono_class_native_size (t->data.klass, align);
8237 *align = *align + 3;
8247 g_error ("type 0x%02x unknown", t->type);
8252 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
8253 the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
8254 but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
8255 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
8258 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
8259 gboolean as_field, gboolean unicode)
8261 MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
8264 switch (native_type) {
8265 case MONO_NATIVE_BOOLEAN:
8268 case MONO_NATIVE_I1:
8269 case MONO_NATIVE_U1:
8272 case MONO_NATIVE_I2:
8273 case MONO_NATIVE_U2:
8274 case MONO_NATIVE_VARIANTBOOL:
8277 case MONO_NATIVE_I4:
8278 case MONO_NATIVE_U4:
8279 case MONO_NATIVE_ERROR:
8282 case MONO_NATIVE_I8:
8283 case MONO_NATIVE_U8:
8284 *align = ALIGNMENT(guint64);
8286 case MONO_NATIVE_R4:
8289 case MONO_NATIVE_R8:
8290 *align = ALIGNMENT(double);
8292 case MONO_NATIVE_INT:
8293 case MONO_NATIVE_UINT:
8294 case MONO_NATIVE_LPSTR:
8295 case MONO_NATIVE_LPWSTR:
8296 case MONO_NATIVE_LPTSTR:
8297 case MONO_NATIVE_BSTR:
8298 case MONO_NATIVE_ANSIBSTR:
8299 case MONO_NATIVE_TBSTR:
8300 case MONO_NATIVE_LPARRAY:
8301 case MONO_NATIVE_SAFEARRAY:
8302 case MONO_NATIVE_IUNKNOWN:
8303 case MONO_NATIVE_IDISPATCH:
8304 case MONO_NATIVE_INTERFACE:
8305 case MONO_NATIVE_ASANY:
8306 case MONO_NATIVE_FUNC:
8307 case MONO_NATIVE_LPSTRUCT:
8308 *align = ALIGNMENT(gpointer);
8309 return sizeof (gpointer);
8310 case MONO_NATIVE_STRUCT:
8311 klass = mono_class_from_mono_type (type);
8312 return mono_class_native_size (klass, align);
8313 case MONO_NATIVE_BYVALTSTR: {
8314 int esize = unicode ? 2: 1;
8317 return mspec->data.array_data.num_elem * esize;
8319 case MONO_NATIVE_BYVALARRAY: {
8321 klass = mono_class_from_mono_type (type);
8322 esize = mono_class_native_size (klass->element_class, align);
8324 return mspec->data.array_data.num_elem * esize;
8326 case MONO_NATIVE_CUSTOM:
8327 g_assert_not_reached ();
8329 case MONO_NATIVE_CURRENCY:
8330 case MONO_NATIVE_VBBYREFSTR:
8332 g_error ("native type %02x not implemented", native_type);
8335 g_assert_not_reached ();
8340 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
8348 t = &o->vtable->klass->byval_arg;
8355 case MONO_TYPE_BOOLEAN:
8358 case MONO_TYPE_CHAR:
8363 return mono_object_unbox (o);
8365 case MONO_TYPE_STRING:
8366 switch (string_encoding) {
8367 case MONO_NATIVE_LPWSTR:
8368 return mono_string_to_utf16 ((MonoString*)o);
8370 case MONO_NATIVE_LPSTR:
8371 return mono_string_to_lpstr ((MonoString*)o);
8374 g_warning ("marshaling conversion %d not implemented", string_encoding);
8375 g_assert_not_reached ();
8378 case MONO_TYPE_CLASS:
8379 case MONO_TYPE_VALUETYPE: {
8383 MonoBoolean delete_old = FALSE;
8385 klass = t->data.klass;
8387 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
8390 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
8391 klass->blittable || klass->enumtype))
8392 return mono_object_unbox (o);
8394 res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
8396 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
8397 method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
8401 pa [2] = &delete_old;
8403 mono_runtime_invoke (method, NULL, pa, NULL);
8410 mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
8416 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
8424 t = &o->vtable->klass->byval_arg;
8426 case MONO_TYPE_STRING:
8427 switch (string_encoding) {
8428 case MONO_NATIVE_LPWSTR:
8429 case MONO_NATIVE_LPSTR:
8430 mono_marshal_free (ptr);
8433 g_warning ("marshaling conversion %d not implemented", string_encoding);
8434 g_assert_not_reached ();
8437 case MONO_TYPE_CLASS:
8438 case MONO_TYPE_VALUETYPE: {
8439 klass = t->data.klass;
8441 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
8442 klass->blittable || klass->enumtype))
8445 if (param_attrs & PARAM_ATTRIBUTE_OUT) {
8446 MonoMethod *method = mono_marshal_get_ptr_to_struct (o->vtable->klass);
8452 mono_runtime_invoke (method, NULL, pa, NULL);
8455 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
8456 mono_struct_delete_old (klass, ptr);
8459 mono_marshal_free (ptr);