2004-11-04 Ben Maurer <bmaurer@ximian.com>
[mono-project.git] / mono / metadata / marshal.c
bloba4733cfc868896e500a34fb8fe95ea677e8c3bd0
1 /*
2 * marshal.c: Routines for marshaling complex types in P/Invoke methods.
3 *
4 * Author:
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2002 Ximian, Inc. http://www.ximian.com
9 */
11 #include "config.h"
12 #include "object.h"
13 #include "loader.h"
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>
27 #include <string.h>
28 #include <errno.h>
30 /* #define DEBUG_RUNTIME_CODE */
32 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
33 a = i,
35 enum {
36 #include "mono/cil/opcode.def"
37 LAST = 0xff
39 #undef OPDEF
41 struct _MonoMethodBuilder {
42 MonoMethod *method;
43 GList *locals_list;
44 int locals;
45 guint32 code_size, pos;
46 unsigned char *code;
49 static void
50 delegate_hash_table_add (MonoDelegate *d);
52 static void
53 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
55 #ifdef DEBUG_RUNTIME_CODE
56 static char*
57 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
59 return g_strdup (" ");
62 static MonoDisHelper marshal_dh = {
63 "\n",
64 "IL_%04x: ",
65 "IL_%04x",
66 indenter,
67 NULL,
68 NULL
70 #endif
72 /* This mutex protects the various marshalling related caches in MonoImage */
73 static CRITICAL_SECTION marshal_mutex;
75 /* Maps wrapper methods to the methods they wrap */
76 static MonoGHashTable *wrapper_hash;
78 static guint32 last_error_tls_id;
80 static void mono_struct_delete_old (MonoClass *klass, char *ptr);
81 void * mono_marshal_string_to_utf16 (MonoString *s);
83 static gpointer mono_string_to_lpstr (MonoString *string_obj);
85 static void
86 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
88 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
90 mono_register_jit_icall (func, name, sig, save);
93 void
94 mono_marshal_init (void)
96 static gboolean module_initialized = FALSE;
98 if (!module_initialized) {
99 module_initialized = TRUE;
100 InitializeCriticalSection (&marshal_mutex);
101 MONO_GC_REGISTER_ROOT (wrapper_hash);
102 wrapper_hash = mono_g_hash_table_new (NULL, NULL);
103 last_error_tls_id = TlsAlloc ();
105 register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
106 register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
107 register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
108 register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
109 register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
110 register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
111 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
112 register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
113 register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
114 register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
115 register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
116 register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
117 register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
118 register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
119 register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32", FALSE);
120 register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32", FALSE);
121 register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
122 register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
123 register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
124 register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
125 register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
126 register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
127 register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
128 register_icall (g_free, "g_free", "void ptr", FALSE);
129 register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
130 register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
134 gpointer
135 mono_delegate_to_ftnptr (MonoDelegate *delegate)
137 MonoMethod *method, *wrapper, *invoke;
138 MonoMarshalSpec **mspecs;
139 MonoClass *klass;
140 int i;
142 if (!delegate)
143 return NULL;
145 if (delegate->delegate_trampoline)
146 return delegate->delegate_trampoline;
148 klass = ((MonoObject *)delegate)->vtable->klass;
149 g_assert (klass->delegate);
151 method = delegate->method_info->method;
152 invoke = mono_find_method_by_name (klass, "Invoke", method->signature->param_count);
154 mspecs = g_new (MonoMarshalSpec*, invoke->signature->param_count + 1);
155 mono_method_get_marshal_info (invoke, mspecs);
157 wrapper = mono_marshal_get_managed_wrapper (method, delegate->target, mspecs);
159 for (i = invoke->signature->param_count; i >= 0; i--)
160 if (mspecs [i])
161 mono_metadata_free_marshal_spec (mspecs [i]);
162 g_free (mspecs);
164 delegate->delegate_trampoline = mono_compile_method (wrapper);
166 // Add the delegate to the delegate hash table
167 delegate_hash_table_add (delegate);
169 return delegate->delegate_trampoline;
172 static GHashTable *delegate_hash_table;
174 static GHashTable *
175 delegate_hash_table_new (void) {
176 return g_hash_table_new (NULL, NULL);
179 static void
180 delegate_hash_table_remove (MonoDelegate *d)
182 EnterCriticalSection (&marshal_mutex);
183 if (delegate_hash_table == NULL)
184 delegate_hash_table = delegate_hash_table_new ();
185 g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
186 LeaveCriticalSection (&marshal_mutex);
189 void
190 delegate_hash_table_add (MonoDelegate *d)
192 EnterCriticalSection (&marshal_mutex);
193 if (delegate_hash_table == NULL)
194 delegate_hash_table = delegate_hash_table_new ();
195 g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d);
196 LeaveCriticalSection (&marshal_mutex);
199 MonoDelegate*
200 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
202 MonoDelegate *d;
204 EnterCriticalSection (&marshal_mutex);
205 if (delegate_hash_table == NULL)
206 delegate_hash_table = delegate_hash_table_new ();
208 d = g_hash_table_lookup (delegate_hash_table, ftn);
209 LeaveCriticalSection (&marshal_mutex);
210 if (d == NULL)
211 mono_raise_exception (mono_get_exception_argument (NULL, "Additional information: Function pointer was not created by a delegate."));
212 return d;
215 void
216 mono_delegate_free_ftnptr (MonoDelegate *delegate)
218 MonoJitInfo *ji;
219 void *ptr, *ptr2;
221 delegate_hash_table_remove (delegate);
222 ptr2 = delegate->delegate_trampoline;
224 ptr = InterlockedExchangePointer (&delegate->delegate_trampoline, NULL);
225 ji = mono_jit_info_table_find (mono_domain_get (), ptr);
226 g_assert (ji);
228 if (!delegate->target) {
229 /* The wrapper method is shared between delegates -> no need to free it */
230 return;
233 mono_runtime_free_method (ji->method);
236 gpointer
237 mono_array_to_savearray (MonoArray *array)
239 if (!array)
240 return NULL;
242 g_assert_not_reached ();
243 return NULL;
246 gpointer
247 mono_array_to_lparray (MonoArray *array)
249 if (!array)
250 return NULL;
252 /* fixme: maybe we need to make a copy */
253 return array->vector;
256 void
257 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
259 GError *error = NULL;
260 guint16 *ut;
261 glong items_written;
262 int l;
264 if (!sb || !text)
265 return;
267 l = strlen (text);
269 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
271 if (items_written > mono_stringbuilder_capacity (sb))
272 items_written = mono_stringbuilder_capacity (sb);
274 if (!error) {
275 memcpy (mono_string_chars (sb->str), ut, items_written * 2);
276 sb->length = items_written;
277 } else
278 g_error_free (error);
280 g_free (ut);
283 void
284 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
286 guint32 len;
288 if (!sb || !text)
289 return;
291 g_assert (mono_string_chars (sb->str) == text);
293 for (len = 0; text [len] != 0; ++len)
296 sb->length = len;
299 gpointer
300 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
302 GError *error = NULL;
303 glong *res;
304 gchar *tmp;
306 if (!sb)
307 return NULL;
309 res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
311 tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error);
312 if (error) {
313 g_error_free (error);
314 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
316 else {
317 memcpy (res, tmp, sb->length + 1);
318 g_free (tmp);
321 return res;
324 gpointer
325 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
327 if (!sb)
328 return NULL;
330 return mono_string_chars (sb->str);
333 static gpointer
334 mono_string_to_lpstr (MonoString *s)
336 #ifdef PLATFORM_WIN32
337 char *as, *tmp;
338 glong len;
339 GError *error = NULL;
341 if (s == NULL)
342 return NULL;
344 if (!s->length) {
345 as = CoTaskMemAlloc (1);
346 as [0] = '\0';
347 return as;
350 tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
351 if (error) {
352 g_warning (error->message);
353 g_error_free (error);
354 return NULL;
356 else {
357 as = CoTaskMemAlloc (len + 1);
358 memcpy (as, tmp, len + 1);
359 return as;
361 #else
362 return mono_string_to_utf8 (s);
363 #endif
366 gpointer
367 mono_string_to_ansibstr (MonoString *string_obj)
369 g_error ("implement me");
370 return NULL;
373 gpointer
374 mono_string_to_bstr (MonoString *string_obj)
376 g_error ("implement me");
377 return NULL;
380 void
381 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
383 char *s;
384 int len;
386 g_assert (dst != NULL);
387 g_assert (size > 0);
389 memset (dst, 0, size);
391 if (!src)
392 return;
394 s = mono_string_to_utf8 (src);
395 len = MIN (size, strlen (s));
396 memcpy (dst, s, len);
397 g_free (s);
399 *((char *)dst + size - 1) = 0;
402 void
403 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
405 int len;
407 g_assert (dst != NULL);
408 g_assert (size > 1);
410 if (!src) {
411 memset (dst, 0, size);
412 return;
415 len = MIN (size, (mono_string_length (src) * 2));
416 memcpy (dst, mono_string_chars (src), len);
418 *((char *)dst + size - 1) = 0;
419 *((char *)dst + size - 2) = 0;
422 void
423 mono_mb_free (MonoMethodBuilder *mb)
425 g_list_free (mb->locals_list);
426 g_free (mb);
429 MonoMethodBuilder *
430 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
432 MonoMethodBuilder *mb;
433 MonoMethod *m;
435 g_assert (klass != NULL);
436 g_assert (name != NULL);
438 mb = g_new0 (MonoMethodBuilder, 1);
440 mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
442 m->klass = klass;
443 m->name = g_strdup (name);
444 m->inline_info = 1;
445 m->inline_count = -1;
446 m->wrapper_type = type;
448 mb->code_size = 256;
449 mb->code = g_malloc (mb->code_size);
451 return mb;
455 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
457 int res = mb->locals;
459 g_assert (mb != NULL);
460 g_assert (type != NULL);
462 mb->locals_list = g_list_append (mb->locals_list, type);
463 mb->locals++;
465 return res;
468 MonoMethod *
469 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
471 MonoMethodHeader *header;
472 GList *l;
473 int i;
475 g_assert (mb != NULL);
477 ((MonoMethodNormal *)mb->method)->header = header = (MonoMethodHeader *)
478 g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
480 if (max_stack < 8)
481 max_stack = 8;
483 header->max_stack = max_stack;
485 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
486 header->locals [i] = (MonoType *)l->data;
489 mb->method->signature = signature;
490 header->code = mb->code;
491 header->code_size = mb->pos;
492 header->num_locals = mb->locals;
494 #ifdef DEBUG_RUNTIME_CODE
495 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (mb->method, TRUE));
496 printf ("%s\n", mono_disasm_code (&marshal_dh, mb->method, mb->code, mb->code + mb->pos));
497 #endif
499 return mb->method;
502 guint32
503 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
505 MonoMethodWrapper *mw;
507 g_assert (mb != NULL);
509 mw = (MonoMethodWrapper *)mb->method;
511 mw->data = g_list_append (mw->data, data);
513 return g_list_length (mw->data);
516 void
517 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
519 mb->code [pos] = value & 0xff;
520 mb->code [pos + 1] = (value >> 8) & 0xff;
521 mb->code [pos + 2] = (value >> 16) & 0xff;
522 mb->code [pos + 3] = (value >> 24) & 0xff;
525 void
526 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
528 *((gint8 *)(&mb->code [pos])) = value;
531 void
532 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
534 if (mb->pos >= mb->code_size) {
535 mb->code_size += 64;
536 mb->code = g_realloc (mb->code, mb->code_size);
539 mb->code [mb->pos++] = op;
542 void
543 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
545 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
546 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
548 if (offset) {
549 mono_mb_emit_icon (mb, offset);
550 mono_mb_emit_byte (mb, CEE_ADD);
554 static int
555 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
557 int pos;
558 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
559 mono_mb_emit_byte (mb, CEE_LDIND_I);
560 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
561 mono_mb_emit_byte (mb, CEE_ADD);
562 mono_mb_emit_byte (mb, CEE_LDIND_I);
563 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
564 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
565 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
566 mono_mb_emit_byte (mb, branch_code);
567 pos = mb->pos;
568 mono_mb_emit_i4 (mb, 0);
569 return pos;
572 void
573 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
575 if ((mb->pos + 4) >= mb->code_size) {
576 mb->code_size += 64;
577 mb->code = g_realloc (mb->code, mb->code_size);
580 mono_mb_patch_addr (mb, mb->pos, data);
581 mb->pos += 4;
584 void
585 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
587 if ((mb->pos + 2) >= mb->code_size) {
588 mb->code_size += 64;
589 mb->code = g_realloc (mb->code, mb->code_size);
592 mb->code [mb->pos] = data & 0xff;
593 mb->code [mb->pos + 1] = (data >> 8) & 0xff;
594 mb->pos += 2;
597 void
598 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
600 mono_mb_emit_byte (mb, CEE_LDSTR);
601 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, str));
605 void
606 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
608 if (argnum < 4) {
609 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
610 } else if (argnum < 256) {
611 mono_mb_emit_byte (mb, CEE_LDARG_S);
612 mono_mb_emit_byte (mb, argnum);
613 } else {
614 mono_mb_emit_byte (mb, CEE_PREFIX1);
615 mono_mb_emit_byte (mb, CEE_LDARG);
616 mono_mb_emit_i2 (mb, argnum);
620 void
621 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
623 if (argnum < 256) {
624 mono_mb_emit_byte (mb, CEE_LDARGA_S);
625 mono_mb_emit_byte (mb, argnum);
626 } else {
627 mono_mb_emit_byte (mb, CEE_PREFIX1);
628 mono_mb_emit_byte (mb, CEE_LDARGA);
629 mono_mb_emit_i2 (mb, argnum);
633 void
634 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
636 if (locnum < 256) {
637 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
638 mono_mb_emit_byte (mb, locnum);
639 } else {
640 mono_mb_emit_byte (mb, CEE_PREFIX1);
641 mono_mb_emit_byte (mb, CEE_LDLOCA);
642 mono_mb_emit_i2 (mb, locnum);
646 void
647 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
649 if (num < 4) {
650 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
651 } else if (num < 256) {
652 mono_mb_emit_byte (mb, CEE_LDLOC_S);
653 mono_mb_emit_byte (mb, num);
654 } else {
655 mono_mb_emit_byte (mb, CEE_PREFIX1);
656 mono_mb_emit_byte (mb, CEE_LDLOC);
657 mono_mb_emit_i2 (mb, num);
661 void
662 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
664 if (num < 4) {
665 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
666 } else if (num < 256) {
667 mono_mb_emit_byte (mb, CEE_STLOC_S);
668 mono_mb_emit_byte (mb, num);
669 } else {
670 mono_mb_emit_byte (mb, CEE_PREFIX1);
671 mono_mb_emit_byte (mb, CEE_STLOC);
672 mono_mb_emit_i2 (mb, num);
676 void
677 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
679 if (value >= -1 && value < 8) {
680 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
681 } else if (value >= -128 && value <= 127) {
682 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
683 mono_mb_emit_byte (mb, value);
684 } else {
685 mono_mb_emit_byte (mb, CEE_LDC_I4);
686 mono_mb_emit_i4 (mb, value);
690 guint32
691 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
693 guint32 res;
694 mono_mb_emit_byte (mb, op);
695 res = mb->pos;
696 mono_mb_emit_i4 (mb, 0);
697 return res;
700 static void
701 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
703 mono_mb_emit_byte (mb, CEE_CALLI);
704 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
707 void
708 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
710 mono_mb_emit_byte (mb, CEE_PREFIX1);
711 mono_mb_emit_byte (mb, CEE_LDFTN);
712 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
713 mono_mb_emit_calli (mb, opt_sig ? opt_sig : method->signature);
716 void
717 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
719 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
720 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
721 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
722 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
723 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
724 mono_mb_emit_calli (mb, sig);
725 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
726 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
729 static void
730 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
732 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
733 mono_mb_emit_byte (mb, CEE_MONO_ICALL);
734 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
737 void
738 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
740 /* fixme: we need a better way to throw exception,
741 * supporting several exception types and messages */
742 MonoMethod *ctor = NULL;
744 MonoClass *mme = mono_class_from_name (mono_defaults.corlib, "System", exc_name);
745 int i;
746 mono_class_init (mme);
747 for (i = 0; i < mme->method.count; ++i) {
748 if (strcmp (mme->methods [i]->name, ".ctor") == 0 && mme->methods [i]->signature->param_count == 0) {
749 ctor = mme->methods [i];
750 break;
753 g_assert (ctor);
754 mono_mb_emit_byte (mb, CEE_NEWOBJ);
755 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ctor));
756 if (msg != NULL) {
757 mono_mb_emit_byte (mb, CEE_DUP);
758 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message));
759 mono_mb_emit_ldstr (mb, (char*)msg);
760 mono_mb_emit_byte (mb, CEE_STIND_I);
762 mono_mb_emit_byte (mb, CEE_THROW);
765 void
766 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
768 mono_mb_emit_ldloc (mb, local);
769 mono_mb_emit_icon (mb, incr);
770 mono_mb_emit_byte (mb, CEE_ADD);
771 mono_mb_emit_stloc (mb, local);
774 static void
775 emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv,
776 int usize, int msize, MonoMarshalSpec *mspec)
778 switch (conv) {
779 case MONO_MARSHAL_CONV_BOOL_I4:
780 mono_mb_emit_byte (mb, CEE_LDLOC_1);
781 mono_mb_emit_byte (mb, CEE_LDLOC_0);
782 mono_mb_emit_byte (mb, CEE_LDIND_I4);
783 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
784 mono_mb_emit_byte (mb, 3);
785 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
786 mono_mb_emit_byte (mb, CEE_BR_S);
787 mono_mb_emit_byte (mb, 1);
788 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
789 mono_mb_emit_byte (mb, CEE_STIND_I1);
790 break;
791 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
792 mono_mb_emit_byte (mb, CEE_LDLOC_1);
793 mono_mb_emit_byte (mb, CEE_LDLOC_0);
794 mono_mb_emit_byte (mb, CEE_LDIND_I2);
795 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
796 mono_mb_emit_byte (mb, 3);
797 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
798 mono_mb_emit_byte (mb, CEE_BR_S);
799 mono_mb_emit_byte (mb, 1);
800 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
801 mono_mb_emit_byte (mb, CEE_STIND_I1);
802 break;
803 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
804 MonoClass *eclass = NULL;
805 int esize;
807 if (type->type == MONO_TYPE_SZARRAY) {
808 eclass = type->data.klass;
809 } else {
810 g_assert_not_reached ();
813 if (eclass->valuetype)
814 esize = mono_class_instance_size (eclass) - sizeof (MonoObject);
815 else
816 esize = sizeof (gpointer);
818 /* create a new array */
819 mono_mb_emit_byte (mb, CEE_LDLOC_1);
820 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
821 mono_mb_emit_byte (mb, CEE_NEWARR);
822 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass));
823 mono_mb_emit_byte (mb, CEE_STIND_I);
825 /* copy the elements */
826 mono_mb_emit_byte (mb, CEE_LDLOC_1);
827 mono_mb_emit_byte (mb, CEE_LDIND_I);
828 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
829 mono_mb_emit_byte (mb, CEE_ADD);
830 mono_mb_emit_byte (mb, CEE_LDLOC_0);
831 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
832 mono_mb_emit_byte (mb, CEE_PREFIX1);
833 mono_mb_emit_byte (mb, CEE_CPBLK);
835 break;
837 case MONO_MARSHAL_CONV_STR_BYVALSTR:
838 mono_mb_emit_byte (mb, CEE_LDLOC_1);
839 mono_mb_emit_byte (mb, CEE_LDLOC_0);
840 mono_mb_emit_icall (mb, mono_string_new_wrapper);
841 mono_mb_emit_byte (mb, CEE_STIND_I);
842 break;
843 case MONO_MARSHAL_CONV_STR_LPTSTR:
844 case MONO_MARSHAL_CONV_STR_LPSTR:
845 mono_mb_emit_byte (mb, CEE_LDLOC_1);
846 mono_mb_emit_byte (mb, CEE_LDLOC_0);
847 mono_mb_emit_byte (mb, CEE_LDIND_I);
848 mono_mb_emit_icall (mb, mono_string_new_wrapper);
849 mono_mb_emit_byte (mb, CEE_STIND_I);
850 break;
851 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
852 MonoClass *klass = mono_class_from_mono_type (type);
853 int src_var, dst_var;
855 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
856 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
858 /* *dst = new object */
859 mono_mb_emit_byte (mb, CEE_LDLOC_1);
860 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
861 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
862 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
863 mono_mb_emit_byte (mb, CEE_STIND_I);
865 /* save the old src pointer */
866 mono_mb_emit_byte (mb, CEE_LDLOC_0);
867 mono_mb_emit_stloc (mb, src_var);
868 /* save the old dst pointer */
869 mono_mb_emit_byte (mb, CEE_LDLOC_1);
870 mono_mb_emit_stloc (mb, dst_var);
872 /* dst = pointer to newly created object data */
873 mono_mb_emit_byte (mb, CEE_LDLOC_1);
874 mono_mb_emit_byte (mb, CEE_LDIND_I);
875 mono_mb_emit_icon (mb, sizeof (MonoObject));
876 mono_mb_emit_byte (mb, CEE_ADD);
877 mono_mb_emit_byte (mb, CEE_STLOC_1);
879 emit_struct_conv (mb, klass, TRUE);
881 /* restore the old src pointer */
882 mono_mb_emit_ldloc (mb, src_var);
883 mono_mb_emit_byte (mb, CEE_STLOC_0);
884 /* restore the old dst pointer */
885 mono_mb_emit_ldloc (mb, dst_var);
886 mono_mb_emit_byte (mb, CEE_STLOC_1);
887 break;
889 case MONO_MARSHAL_CONV_DEL_FTN: {
890 /* fixme: we never convert functions back to delegates, dont
891 // know if thats the correct behaviour
893 break;
895 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
896 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
897 break;
898 case MONO_MARSHAL_CONV_STR_LPWSTR:
899 case MONO_MARSHAL_CONV_STR_BSTR:
900 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
901 case MONO_MARSHAL_CONV_STR_TBSTR:
902 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
903 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
904 default:
905 g_warning ("marshaling conversion %d not implemented", conv);
906 g_assert_not_reached ();
910 static gpointer
911 conv_to_icall (MonoMarshalConv conv)
913 switch (conv) {
914 case MONO_MARSHAL_CONV_STR_LPWSTR:
915 return mono_marshal_string_to_utf16;
916 case MONO_MARSHAL_CONV_LPWSTR_STR:
917 return mono_string_from_utf16;
918 case MONO_MARSHAL_CONV_LPSTR_STR:
919 return mono_string_new_wrapper;
920 case MONO_MARSHAL_CONV_STR_LPTSTR:
921 case MONO_MARSHAL_CONV_STR_LPSTR:
922 return mono_string_to_lpstr;
923 case MONO_MARSHAL_CONV_STR_BSTR:
924 return mono_string_to_bstr;
925 case MONO_MARSHAL_CONV_STR_TBSTR:
926 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
927 return mono_string_to_ansibstr;
928 case MONO_MARSHAL_CONV_SB_LPSTR:
929 case MONO_MARSHAL_CONV_SB_LPTSTR:
930 return mono_string_builder_to_utf8;
931 case MONO_MARSHAL_CONV_SB_LPWSTR:
932 return mono_string_builder_to_utf16;
933 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
934 return mono_array_to_savearray;
935 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
936 return mono_array_to_lparray;
937 case MONO_MARSHAL_CONV_DEL_FTN:
938 return mono_delegate_to_ftnptr;
939 case MONO_MARSHAL_CONV_FTN_DEL:
940 return mono_ftnptr_to_delegate;
941 case MONO_MARSHAL_CONV_LPSTR_SB:
942 case MONO_MARSHAL_CONV_LPTSTR_SB:
943 return mono_string_utf8_to_builder;
944 case MONO_MARSHAL_CONV_LPWSTR_SB:
945 return mono_string_utf16_to_builder;
946 case MONO_MARSHAL_FREE_ARRAY:
947 return mono_marshal_free_array;
948 case MONO_MARSHAL_CONV_STR_BYVALSTR:
949 return mono_string_to_byvalstr;
950 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
951 return mono_string_to_byvalwstr;
952 default:
953 g_assert_not_reached ();
956 return NULL;
959 static void
960 emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, int usize, int msize,
961 MonoMarshalSpec *mspec)
963 int pos;
965 switch (conv) {
966 case MONO_MARSHAL_CONV_BOOL_I4:
967 mono_mb_emit_byte (mb, CEE_LDLOC_1);
968 mono_mb_emit_byte (mb, CEE_LDLOC_0);
969 mono_mb_emit_byte (mb, CEE_LDIND_U1);
970 mono_mb_emit_byte (mb, CEE_STIND_I4);
971 break;
972 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
973 mono_mb_emit_byte (mb, CEE_LDLOC_1);
974 mono_mb_emit_byte (mb, CEE_LDLOC_0);
975 mono_mb_emit_byte (mb, CEE_LDIND_U1);
976 mono_mb_emit_byte (mb, CEE_NEG);
977 mono_mb_emit_byte (mb, CEE_STIND_I2);
978 break;
979 case MONO_MARSHAL_CONV_STR_LPWSTR:
980 case MONO_MARSHAL_CONV_STR_LPSTR:
981 case MONO_MARSHAL_CONV_STR_LPTSTR:
982 case MONO_MARSHAL_CONV_STR_BSTR:
983 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
984 case MONO_MARSHAL_CONV_STR_TBSTR: {
985 int pos;
987 /* free space if free == true */
988 mono_mb_emit_byte (mb, CEE_LDLOC_2);
989 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
990 pos = mb->pos;
991 mono_mb_emit_byte (mb, 0);
992 mono_mb_emit_byte (mb, CEE_LDLOC_1);
993 mono_mb_emit_byte (mb, CEE_LDIND_I);
994 mono_mb_emit_icall (mb, g_free);
995 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
997 mono_mb_emit_byte (mb, CEE_LDLOC_1);
998 mono_mb_emit_byte (mb, CEE_LDLOC_0);
999 mono_mb_emit_byte (mb, CEE_LDIND_I);
1000 mono_mb_emit_icall (mb, conv_to_icall (conv));
1001 mono_mb_emit_byte (mb, CEE_STIND_I);
1002 break;
1004 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1005 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1006 case MONO_MARSHAL_CONV_DEL_FTN:
1007 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1008 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1009 mono_mb_emit_byte (mb, CEE_LDIND_I);
1010 mono_mb_emit_icall (mb, conv_to_icall (conv));
1011 mono_mb_emit_byte (mb, CEE_STIND_I);
1012 break;
1013 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1014 case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
1015 if (!usize)
1016 break;
1018 mono_mb_emit_byte (mb, CEE_LDLOC_1); /* dst */
1019 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1020 mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */
1021 mono_mb_emit_icon (mb, usize);
1022 mono_mb_emit_icall (mb, conv_to_icall (conv));
1023 break;
1025 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1026 MonoClass *eclass = NULL;
1027 int esize;
1029 if (type->type == MONO_TYPE_SZARRAY) {
1030 eclass = type->data.klass;
1031 } else {
1032 g_assert_not_reached ();
1035 if (eclass->valuetype)
1036 esize = mono_class_native_size (eclass, NULL);
1037 else
1038 esize = sizeof (gpointer);
1040 if (!usize)
1041 break;
1043 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1044 mono_mb_emit_byte (mb, CEE_LDIND_I);
1045 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1046 pos = mb->pos;
1047 mono_mb_emit_byte (mb, 0);
1049 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1050 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1051 mono_mb_emit_byte (mb, CEE_LDIND_I);
1052 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1053 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1054 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
1055 mono_mb_emit_byte (mb, CEE_ADD);
1056 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1057 mono_mb_emit_byte (mb, CEE_PREFIX1);
1058 mono_mb_emit_byte (mb, CEE_CPBLK);
1059 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1060 break;
1062 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1063 int src_var, dst_var;
1065 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1066 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1068 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1069 mono_mb_emit_byte (mb, CEE_LDIND_I);
1070 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1071 pos = mb->pos;
1072 mono_mb_emit_byte (mb, 0);
1074 /* save the old src pointer */
1075 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1076 mono_mb_emit_stloc (mb, src_var);
1077 /* save the old dst pointer */
1078 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1079 mono_mb_emit_stloc (mb, dst_var);
1081 /* src = pointer to object data */
1082 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1083 mono_mb_emit_byte (mb, CEE_LDIND_I);
1084 mono_mb_emit_icon (mb, sizeof (MonoObject));
1085 mono_mb_emit_byte (mb, CEE_ADD);
1086 mono_mb_emit_byte (mb, CEE_STLOC_0);
1088 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
1090 /* restore the old src pointer */
1091 mono_mb_emit_ldloc (mb, src_var);
1092 mono_mb_emit_byte (mb, CEE_STLOC_0);
1093 /* restore the old dst pointer */
1094 mono_mb_emit_ldloc (mb, dst_var);
1095 mono_mb_emit_byte (mb, CEE_STLOC_1);
1097 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1098 break;
1100 default: {
1101 char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
1102 MonoException *exc = mono_get_exception_not_implemented (msg);
1103 g_warning (msg);
1104 g_free (msg);
1105 mono_raise_exception (exc);
1110 static void
1111 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
1113 MonoMarshalType *info;
1114 int i;
1116 if (klass->parent)
1117 emit_struct_conv(mb, klass->parent, to_object);
1119 info = mono_marshal_load_type_info (klass);
1121 if (info->native_size == 0)
1122 return;
1124 if (klass->blittable) {
1125 int msize = mono_class_value_size (klass, NULL);
1126 g_assert (msize == info->native_size);
1127 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1128 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1129 mono_mb_emit_icon (mb, msize);
1130 mono_mb_emit_byte (mb, CEE_PREFIX1);
1131 mono_mb_emit_byte (mb, CEE_CPBLK);
1133 mono_mb_emit_add_to_local (mb, 0, msize);
1134 mono_mb_emit_add_to_local (mb, 1, msize);
1135 return;
1138 for (i = 0; i < info->num_fields; i++) {
1139 MonoMarshalNative ntype;
1140 MonoMarshalConv conv;
1141 MonoType *ftype = info->fields [i].field->type;
1142 int msize = 0;
1143 int usize = 0;
1144 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
1146 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
1147 continue;
1149 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
1151 if (last_field) {
1152 msize = klass->instance_size - info->fields [i].field->offset;
1153 usize = info->native_size - info->fields [i].offset;
1154 } else {
1155 msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
1156 usize = info->fields [i + 1].offset - info->fields [i].offset;
1158 if ((msize < 0) || (usize < 0))
1159 /* This happens with GC aware auto layout */
1160 g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg));
1162 g_assert ((msize >= 0) && (usize >= 0));
1164 switch (conv) {
1165 case MONO_MARSHAL_CONV_NONE: {
1166 int t;
1168 if (ftype->byref || ftype->type == MONO_TYPE_I ||
1169 ftype->type == MONO_TYPE_U) {
1170 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1171 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1172 mono_mb_emit_byte (mb, CEE_LDIND_I);
1173 mono_mb_emit_byte (mb, CEE_STIND_I);
1174 break;
1177 t = ftype->type;
1178 handle_enum:
1179 switch (t) {
1180 case MONO_TYPE_I4:
1181 case MONO_TYPE_U4:
1182 #if SIZEOF_VOID_P == 4
1183 case MONO_TYPE_PTR:
1184 #endif
1185 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1186 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1187 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1188 mono_mb_emit_byte (mb, CEE_STIND_I4);
1189 break;
1190 case MONO_TYPE_I1:
1191 case MONO_TYPE_U1:
1192 case MONO_TYPE_BOOLEAN:
1193 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1194 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1195 mono_mb_emit_byte (mb, CEE_LDIND_I1);
1196 mono_mb_emit_byte (mb, CEE_STIND_I1);
1197 break;
1198 case MONO_TYPE_I2:
1199 case MONO_TYPE_U2:
1200 case MONO_TYPE_CHAR:
1201 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1202 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1203 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1204 mono_mb_emit_byte (mb, CEE_STIND_I2);
1205 break;
1206 case MONO_TYPE_I8:
1207 case MONO_TYPE_U8:
1208 #if SIZEOF_VOID_P == 8
1209 case MONO_TYPE_PTR:
1210 #endif
1211 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1212 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1213 mono_mb_emit_byte (mb, CEE_LDIND_I8);
1214 mono_mb_emit_byte (mb, CEE_STIND_I8);
1215 break;
1216 case MONO_TYPE_R4:
1217 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1218 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1219 mono_mb_emit_byte (mb, CEE_LDIND_R4);
1220 mono_mb_emit_byte (mb, CEE_STIND_R4);
1221 break;
1222 case MONO_TYPE_R8:
1223 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1224 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1225 mono_mb_emit_byte (mb, CEE_LDIND_R8);
1226 mono_mb_emit_byte (mb, CEE_STIND_R8);
1227 break;
1228 case MONO_TYPE_VALUETYPE:
1229 if (ftype->data.klass->enumtype) {
1230 t = ftype->data.klass->enum_basetype->type;
1231 goto handle_enum;
1233 emit_struct_conv (mb, ftype->data.klass, to_object);
1234 continue;
1235 default:
1236 g_warning ("marshaling type %02x not implemented", ftype->type);
1237 g_assert_not_reached ();
1239 break;
1241 default:
1242 if (to_object)
1243 emit_ptr_to_str_conv (mb, ftype, conv, usize, msize, info->fields [i].mspec);
1244 else
1245 emit_str_to_ptr_conv (mb, ftype, conv, usize, msize, info->fields [i].mspec);
1248 if (to_object) {
1249 mono_mb_emit_add_to_local (mb, 0, usize);
1250 mono_mb_emit_add_to_local (mb, 1, msize);
1251 } else {
1252 mono_mb_emit_add_to_local (mb, 0, msize);
1253 mono_mb_emit_add_to_local (mb, 1, usize);
1258 static void
1259 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
1261 /* Call DestroyStructure */
1262 /* FIXME: Only do this if needed */
1263 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1264 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1265 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
1266 mono_mb_emit_ldloc (mb, struct_var);
1267 mono_mb_emit_icall (mb, mono_struct_delete_old);
1270 static void
1271 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoint_func)
1273 static MonoMethodSignature *state_check_sig = NULL;
1274 int pos_noabort;
1276 if (!state_check_sig) {
1277 state_check_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
1278 state_check_sig->ret = &mono_defaults.void_class->byval_arg;
1279 state_check_sig->pinvoke = 0;
1282 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1283 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1284 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, (gpointer) mono_thread_interruption_request_flag ()));
1285 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1286 pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
1288 mono_mb_emit_native_call (mb, state_check_sig, checkpoint_func);
1290 mono_mb_patch_addr (mb, pos_noabort, mb->pos - (pos_noabort + 4));
1293 static void
1294 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
1296 emit_thread_interrupt_checkpoint_call (mb, mono_thread_interruption_checkpoint);
1299 static void
1300 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
1302 emit_thread_interrupt_checkpoint_call (mb, mono_thread_force_interruption_checkpoint);
1305 static MonoAsyncResult *
1306 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
1308 MonoMethodMessage *msg;
1309 MonoDelegate *async_callback;
1310 MonoObject *state;
1311 MonoMethod *im;
1312 MonoClass *klass;
1313 MonoMethod *method = NULL;
1314 int i;
1316 g_assert (delegate);
1318 if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
1320 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
1321 if (!tp->remote_class->proxy_class->contextbound || tp->rp->context != (MonoObject *) mono_context_get ()) {
1323 /* If the target is a proxy, make a direct call. Is proxy's work
1324 // to make the call asynchronous.
1326 MonoAsyncResult *ares;
1327 MonoObject *exc;
1328 MonoArray *out_args;
1329 HANDLE handle;
1330 method = delegate->method_info->method;
1332 msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
1333 handle = CreateEvent (NULL, TRUE, FALSE, NULL);
1334 ares = mono_async_result_new (mono_domain_get (), handle, state, handle);
1335 ares->async_delegate = (MonoObject *)delegate;
1336 ares->async_callback = (MonoObject *)async_callback;
1337 msg->async_result = ares;
1338 msg->call_type = CallType_BeginInvoke;
1340 mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
1341 return ares;
1345 klass = delegate->object.vtable->klass;
1347 method = mono_get_delegate_invoke (klass);
1348 for (i = 0; i < klass->method.count; ++i) {
1349 if (klass->methods [i]->name[0] == 'B' &&
1350 !strcmp ("BeginInvoke", klass->methods [i]->name)) {
1351 method = klass->methods [i];
1352 break;
1356 g_assert (method != NULL);
1358 im = mono_get_delegate_invoke (method->klass);
1359 msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
1361 return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
1364 static int
1365 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
1367 int i, params_var, tmp_var;
1369 /* allocate local (pointer) *params[] */
1370 params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1371 /* allocate local (pointer) tmp */
1372 tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1374 /* alloate space on stack to store an array of pointers to the arguments */
1375 mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
1376 mono_mb_emit_byte (mb, CEE_PREFIX1);
1377 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1378 mono_mb_emit_stloc (mb, params_var);
1380 /* tmp = params */
1381 mono_mb_emit_ldloc (mb, params_var);
1382 mono_mb_emit_stloc (mb, tmp_var);
1384 if (save_this && sig->hasthis) {
1385 mono_mb_emit_ldloc (mb, tmp_var);
1386 mono_mb_emit_ldarg_addr (mb, 0);
1387 mono_mb_emit_byte (mb, CEE_STIND_I);
1388 /* tmp = tmp + sizeof (gpointer) */
1389 if (sig->param_count)
1390 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
1394 for (i = 0; i < sig->param_count; i++) {
1395 mono_mb_emit_ldloc (mb, tmp_var);
1396 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
1397 mono_mb_emit_byte (mb, CEE_STIND_I);
1398 /* tmp = tmp + sizeof (gpointer) */
1399 if (i < (sig->param_count - 1))
1400 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
1403 return params_var;
1406 static char*
1407 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
1409 int i;
1410 char *result;
1411 GString *res = g_string_new ("");
1413 if (prefix) {
1414 g_string_append (res, prefix);
1415 g_string_append_c (res, '_');
1418 mono_type_get_desc (res, sig->ret, FALSE);
1420 for (i = 0; i < sig->param_count; ++i) {
1421 g_string_append_c (res, '_');
1422 mono_type_get_desc (res, sig->params [i], FALSE);
1424 result = res->str;
1425 g_string_free (res, FALSE);
1426 return result;
1430 * mono_marshal_get_string_encoding:
1432 * Return the string encoding which should be used for a given parameter.
1434 static MonoMarshalNative
1435 mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1437 /* First try the parameter marshal info */
1438 if (spec) {
1439 if (spec->native == MONO_NATIVE_LPARRAY) {
1440 if (spec->data.array_data.elem_type != 0)
1441 return spec->data.array_data.elem_type;
1443 else
1444 return spec->native;
1447 if (!piinfo)
1448 return MONO_NATIVE_LPSTR;
1450 /* Then try the method level marshal info */
1451 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
1452 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
1453 return MONO_NATIVE_LPSTR;
1454 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
1455 return MONO_NATIVE_LPWSTR;
1456 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
1457 return MONO_NATIVE_LPTSTR;
1458 default:
1459 return MONO_NATIVE_LPSTR;
1463 static MonoMarshalConv
1464 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1466 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1468 switch (encoding) {
1469 case MONO_NATIVE_LPWSTR:
1470 return MONO_MARSHAL_CONV_STR_LPWSTR;
1471 case MONO_NATIVE_LPSTR:
1472 return MONO_MARSHAL_CONV_STR_LPSTR;
1473 case MONO_NATIVE_LPTSTR:
1474 return MONO_MARSHAL_CONV_STR_LPTSTR;
1475 default:
1476 return -1;
1480 static MonoMarshalConv
1481 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1483 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1485 switch (encoding) {
1486 case MONO_NATIVE_LPWSTR:
1487 return MONO_MARSHAL_CONV_SB_LPWSTR;
1488 break;
1489 case MONO_NATIVE_LPSTR:
1490 return MONO_MARSHAL_CONV_SB_LPSTR;
1491 break;
1492 case MONO_NATIVE_LPTSTR:
1493 return MONO_MARSHAL_CONV_SB_LPTSTR;
1494 break;
1495 default:
1496 return -1;
1500 static MonoMarshalConv
1501 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
1503 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1505 *need_free = TRUE;
1507 switch (encoding) {
1508 case MONO_NATIVE_LPWSTR:
1510 * mono_string_builder_to_utf16 does not allocate a
1511 * new buffer, so no need to free it.
1513 *need_free = FALSE;
1514 return MONO_MARSHAL_CONV_LPWSTR_SB;
1515 case MONO_NATIVE_LPSTR:
1516 return MONO_MARSHAL_CONV_LPSTR_SB;
1517 break;
1518 case MONO_NATIVE_LPTSTR:
1519 return MONO_MARSHAL_CONV_LPTSTR_SB;
1520 break;
1521 default:
1522 return -1;
1527 * Return whenever a field of a native structure or an array member needs to
1528 * be freed.
1530 static gboolean
1531 mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1533 MonoMarshalNative encoding;
1534 MonoMarshalConv conv;
1536 switch (t->type) {
1537 case MONO_TYPE_VALUETYPE:
1538 /* FIXME: Optimize this */
1539 return TRUE;
1540 case MONO_TYPE_OBJECT:
1541 case MONO_TYPE_CLASS:
1542 if (t->data.klass == mono_defaults.stringbuilder_class) {
1543 gboolean need_free;
1544 conv = mono_marshal_get_ptr_to_stringbuilder_conv (piinfo, spec, &need_free);
1545 return need_free;
1547 return FALSE;
1548 case MONO_TYPE_STRING:
1549 encoding = mono_marshal_get_string_encoding (piinfo, spec);
1550 return (encoding == MONO_NATIVE_LPWSTR) ? FALSE : TRUE;
1551 default:
1552 return FALSE;
1556 static inline MonoMethod*
1557 mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
1559 MonoMethod *res;
1561 EnterCriticalSection (&marshal_mutex);
1562 res = g_hash_table_lookup (cache, key);
1563 LeaveCriticalSection (&marshal_mutex);
1564 return res;
1567 /* Create the method from the builder and place it in the cache */
1568 static inline MonoMethod*
1569 mono_mb_create_and_cache (GHashTable *cache, gpointer key,
1570 MonoMethodBuilder *mb, MonoMethodSignature *sig,
1571 int max_stack)
1573 MonoMethod *res;
1575 EnterCriticalSection (&marshal_mutex);
1576 res = g_hash_table_lookup (cache, key);
1577 if (!res) {
1578 /* This does not acquire any locks */
1579 res = mono_mb_create_method (mb, sig, max_stack);
1580 g_hash_table_insert (cache, key, res);
1581 mono_g_hash_table_insert (wrapper_hash, res, key);
1583 else
1584 /* Somebody created it before us */
1586 LeaveCriticalSection (&marshal_mutex);
1588 return res;
1591 MonoMethod *
1592 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
1594 MonoMethod *res;
1596 if (wrapper->wrapper_type == MONO_WRAPPER_NONE)
1597 return wrapper;
1599 EnterCriticalSection (&marshal_mutex);
1600 res = mono_g_hash_table_lookup (wrapper_hash, wrapper);
1601 LeaveCriticalSection (&marshal_mutex);
1603 if (res && wrapper->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
1604 /* See mono_marshal_get_remoting_invoke_with_check */
1605 return (MonoMethod*)((char*)res - 1);
1606 else
1607 return res;
1610 MonoMethod *
1611 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
1613 MonoMethodSignature *sig;
1614 static MonoMethodSignature *csig = NULL;
1615 MonoMethodBuilder *mb;
1616 MonoMethod *res;
1617 GHashTable *cache;
1618 int params_var;
1619 char *name;
1621 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1622 !strcmp (method->name, "BeginInvoke"));
1624 sig = method->signature;
1626 cache = method->klass->image->delegate_begin_invoke_cache;
1627 if ((res = mono_marshal_find_in_cache (cache, sig)))
1628 return res;
1630 g_assert (sig->hasthis);
1632 if (!csig) {
1633 csig = mono_metadata_signature_alloc (method->klass->image, 2);
1635 /* MonoAsyncResult * begin_invoke (MonoDelegate *delegate, gpointer params[]) */
1636 csig->ret = &mono_defaults.object_class->byval_arg;
1637 csig->params [0] = &mono_defaults.object_class->byval_arg;
1638 csig->params [1] = &mono_defaults.int_class->byval_arg;
1641 name = mono_signature_to_name (sig, "begin_invoke");
1642 mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
1643 g_free (name);
1645 mb->method->save_lmf = 1;
1647 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
1649 mono_mb_emit_ldarg (mb, 0);
1650 mono_mb_emit_ldloc (mb, params_var);
1651 mono_mb_emit_native_call (mb, csig, mono_delegate_begin_invoke);
1652 emit_thread_interrupt_checkpoint (mb);
1653 mono_mb_emit_byte (mb, CEE_RET);
1655 res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
1656 mono_mb_free (mb);
1657 return res;
1660 static MonoObject *
1661 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
1663 MonoDomain *domain = mono_domain_get ();
1664 MonoAsyncResult *ares;
1665 MonoMethod *method = NULL;
1666 MonoMethodSignature *sig;
1667 MonoMethodMessage *msg;
1668 MonoObject *res, *exc;
1669 MonoArray *out_args;
1670 MonoClass *klass;
1671 int i;
1673 g_assert (delegate);
1675 if (!delegate->method_info || !delegate->method_info->method)
1676 g_assert_not_reached ();
1678 klass = delegate->object.vtable->klass;
1680 for (i = 0; i < klass->method.count; ++i) {
1681 if (klass->methods [i]->name[0] == 'E' &&
1682 !strcmp ("EndInvoke", klass->methods [i]->name)) {
1683 method = klass->methods [i];
1684 break;
1688 g_assert (method != NULL);
1690 sig = method->signature;
1692 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
1694 ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
1695 g_assert (ares);
1697 if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
1698 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
1699 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
1700 mono_message_init (domain, msg, delegate->method_info, NULL);
1701 msg->call_type = CallType_EndInvoke;
1702 msg->async_result = ares;
1703 res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
1705 else
1706 res = mono_thread_pool_finish (ares, &out_args, &exc);
1708 if (exc) {
1709 if (((MonoException*)exc)->stack_trace) {
1710 char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
1711 char *tmp;
1712 tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
1713 g_free (strace);
1714 ((MonoException*)exc)->stack_trace = mono_string_new (domain, tmp);
1715 g_free (tmp);
1717 mono_raise_exception ((MonoException*)exc);
1720 mono_method_return_message_restore (method, params, out_args);
1721 return res;
1724 static void
1725 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
1727 if (return_type->byref)
1728 return_type = &mono_defaults.int_class->byval_arg;
1729 else if (return_type->type == MONO_TYPE_VALUETYPE && return_type->data.klass->enumtype)
1730 return_type = return_type->data.klass->enum_basetype;
1732 switch (return_type->type) {
1733 case MONO_TYPE_VOID:
1734 g_assert_not_reached ();
1735 break;
1736 case MONO_TYPE_PTR:
1737 case MONO_TYPE_STRING:
1738 case MONO_TYPE_CLASS:
1739 case MONO_TYPE_OBJECT:
1740 case MONO_TYPE_ARRAY:
1741 case MONO_TYPE_SZARRAY:
1742 /* nothing to do */
1743 break;
1744 case MONO_TYPE_U1:
1745 case MONO_TYPE_BOOLEAN:
1746 mono_mb_emit_byte (mb, CEE_UNBOX);
1747 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1748 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1749 break;
1750 case MONO_TYPE_I1:
1751 mono_mb_emit_byte (mb, CEE_UNBOX);
1752 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1753 mono_mb_emit_byte (mb, CEE_LDIND_I1);
1754 break;
1755 case MONO_TYPE_U2:
1756 case MONO_TYPE_CHAR:
1757 mono_mb_emit_byte (mb, CEE_UNBOX);
1758 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1759 mono_mb_emit_byte (mb, CEE_LDIND_U2);
1760 break;
1761 case MONO_TYPE_I2:
1762 mono_mb_emit_byte (mb, CEE_UNBOX);
1763 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1764 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1765 break;
1766 case MONO_TYPE_I:
1767 case MONO_TYPE_U:
1768 mono_mb_emit_byte (mb, CEE_UNBOX);
1769 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1770 mono_mb_emit_byte (mb, CEE_LDIND_I);
1771 break;
1772 case MONO_TYPE_I4:
1773 mono_mb_emit_byte (mb, CEE_UNBOX);
1774 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1775 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1776 break;
1777 case MONO_TYPE_U4:
1778 mono_mb_emit_byte (mb, CEE_UNBOX);
1779 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1780 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1781 break;
1782 case MONO_TYPE_U8:
1783 case MONO_TYPE_I8:
1784 mono_mb_emit_byte (mb, CEE_UNBOX);
1785 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1786 mono_mb_emit_byte (mb, CEE_LDIND_I8);
1787 break;
1788 case MONO_TYPE_R4:
1789 mono_mb_emit_byte (mb, CEE_UNBOX);
1790 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1791 mono_mb_emit_byte (mb, CEE_LDIND_R4);
1792 break;
1793 case MONO_TYPE_R8:
1794 mono_mb_emit_byte (mb, CEE_UNBOX);
1795 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1796 mono_mb_emit_byte (mb, CEE_LDIND_R8);
1797 break;
1798 case MONO_TYPE_VALUETYPE: {
1799 int class;
1800 mono_mb_emit_byte (mb, CEE_UNBOX);
1801 class = mono_mb_add_data (mb, mono_class_from_mono_type (return_type));
1802 mono_mb_emit_i4 (mb, class);
1803 mono_mb_emit_byte (mb, CEE_LDOBJ);
1804 mono_mb_emit_i4 (mb, class);
1805 break;
1807 default:
1808 g_warning ("type 0x%x not handled", return_type->type);
1809 g_assert_not_reached ();
1812 mono_mb_emit_byte (mb, CEE_RET);
1815 MonoMethod *
1816 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
1818 MonoMethodSignature *sig;
1819 static MonoMethodSignature *csig = NULL;
1820 MonoMethodBuilder *mb;
1821 MonoMethod *res;
1822 GHashTable *cache;
1823 int params_var;
1824 char *name;
1826 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1827 !strcmp (method->name, "EndInvoke"));
1829 sig = method->signature;
1831 cache = method->klass->image->delegate_end_invoke_cache;
1832 if ((res = mono_marshal_find_in_cache (cache, sig)))
1833 return res;
1835 g_assert (sig->hasthis);
1837 if (!csig) {
1838 csig = mono_metadata_signature_alloc (method->klass->image, 2);
1840 /* MonoObject *end_invoke (MonoDelegate *delegate, gpointer params[]) */
1841 csig->ret = &mono_defaults.object_class->byval_arg;
1842 csig->params [0] = &mono_defaults.object_class->byval_arg;
1843 csig->params [1] = &mono_defaults.int_class->byval_arg;
1846 name = mono_signature_to_name (sig, "end_invoke");
1847 mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
1848 g_free (name);
1850 mb->method->save_lmf = 1;
1852 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
1854 mono_mb_emit_ldarg (mb, 0);
1855 mono_mb_emit_ldloc (mb, params_var);
1856 mono_mb_emit_native_call (mb, csig, mono_delegate_end_invoke);
1857 emit_thread_interrupt_checkpoint (mb);
1859 if (sig->ret->type == MONO_TYPE_VOID) {
1860 mono_mb_emit_byte (mb, CEE_POP);
1861 mono_mb_emit_byte (mb, CEE_RET);
1862 } else
1863 mono_mb_emit_restore_result (mb, sig->ret);
1865 res = mono_mb_create_and_cache (cache, sig,
1866 mb, sig, sig->param_count + 16);
1867 mono_mb_free (mb);
1869 return res;
1872 static MonoObject *
1873 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
1875 MonoMethodMessage *msg;
1876 MonoTransparentProxy *this;
1877 MonoObject *res, *exc;
1878 MonoArray *out_args;
1880 this = *((MonoTransparentProxy **)params [0]);
1882 g_assert (this);
1883 g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
1885 /* skip the this pointer */
1886 params++;
1888 if (this->remote_class->proxy_class->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
1890 int i;
1891 MonoMethodSignature *sig = method->signature;
1892 int count = sig->param_count;
1893 gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
1895 for (i=0; i<count; i++) {
1896 MonoClass *class = mono_class_from_mono_type (sig->params [i]);
1897 if (class->valuetype) {
1898 if (sig->params [i]->byref)
1899 mparams[i] = *((gpointer *)params [i]);
1900 else
1901 mparams[i] = params [i];
1902 } else {
1903 mparams[i] = *((gpointer**)params [i]);
1907 return mono_runtime_invoke (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this): this, mparams, NULL);
1910 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
1912 res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
1914 if (exc)
1915 mono_raise_exception ((MonoException *)exc);
1917 mono_method_return_message_restore (method, params, out_args);
1919 return res;
1922 MonoMethod *
1923 mono_marshal_get_remoting_invoke (MonoMethod *method)
1925 MonoMethodSignature *sig;
1926 static MonoMethodSignature *csig = NULL;
1927 MonoMethodBuilder *mb;
1928 MonoMethod *res;
1929 GHashTable *cache;
1930 int params_var;
1932 g_assert (method);
1934 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
1935 return method;
1937 sig = method->signature;
1939 /* we cant remote methods without this pointer */
1940 if (!sig->hasthis)
1941 return method;
1943 cache = method->klass->image->remoting_invoke_cache;
1944 if ((res = mono_marshal_find_in_cache (cache, method)))
1945 return res;
1947 if (!csig) {
1948 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
1949 csig->params [0] = &mono_defaults.int_class->byval_arg;
1950 csig->params [1] = &mono_defaults.int_class->byval_arg;
1951 csig->ret = &mono_defaults.object_class->byval_arg;
1952 csig->pinvoke = 1;
1955 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
1956 mb->method->save_lmf = 1;
1958 params_var = mono_mb_emit_save_args (mb, sig, TRUE);
1960 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1961 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1962 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
1963 mono_mb_emit_ldloc (mb, params_var);
1964 mono_mb_emit_native_call (mb, csig, mono_remoting_wrapper);
1965 emit_thread_interrupt_checkpoint (mb);
1967 if (sig->ret->type == MONO_TYPE_VOID) {
1968 mono_mb_emit_byte (mb, CEE_POP);
1969 mono_mb_emit_byte (mb, CEE_RET);
1970 } else {
1971 mono_mb_emit_restore_result (mb, sig->ret);
1974 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1975 mono_mb_free (mb);
1977 return res;
1980 MonoMethod *
1981 mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
1983 MonoMethodSignature *sig;
1984 MonoMethodBuilder *mb;
1985 MonoMethod *res, *native;
1986 GHashTable *cache;
1987 int i, pos;
1989 g_assert (method);
1991 if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
1992 return method;
1994 sig = method->signature;
1996 /* we cant remote methods without this pointer */
1997 g_assert (sig->hasthis);
1999 cache = method->klass->image->remoting_invoke_cache;
2000 if ((res = mono_marshal_find_in_cache (cache, (char *)method + 1)))
2001 return res;
2003 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
2005 mono_mb_emit_ldarg (mb, 0);
2006 pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
2008 native = mono_marshal_get_remoting_invoke (method);
2010 for (i = 0; i <= sig->param_count; i++)
2011 mono_mb_emit_ldarg (mb, i);
2013 mono_mb_emit_managed_call (mb, native, native->signature);
2014 mono_mb_emit_byte (mb, CEE_RET);
2016 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2018 for (i = 0; i <= sig->param_count; i++)
2019 mono_mb_emit_ldarg (mb, i);
2021 mono_mb_emit_managed_call (mb, method, method->signature);
2022 mono_mb_emit_byte (mb, CEE_RET);
2024 res = mono_mb_create_and_cache (cache, (char*)method + 1,
2025 mb, sig, sig->param_count + 16);
2026 mono_mb_free (mb);
2028 return res;
2032 * the returned method invokes all methods in a multicast delegate
2034 MonoMethod *
2035 mono_marshal_get_delegate_invoke (MonoMethod *method)
2037 MonoMethodSignature *sig, *static_sig;
2038 int i;
2039 MonoMethodBuilder *mb;
2040 MonoMethod *res;
2041 GHashTable *cache;
2042 int pos0, pos1;
2043 char *name;
2045 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
2046 !strcmp (method->name, "Invoke"));
2048 sig = method->signature;
2050 cache = method->klass->image->delegate_invoke_cache;
2051 if ((res = mono_marshal_find_in_cache (cache, sig)))
2052 return res;
2054 static_sig = mono_metadata_signature_dup (sig);
2055 static_sig->hasthis = 0;
2057 name = mono_signature_to_name (sig, "invoke");
2058 mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_INVOKE);
2059 g_free (name);
2061 /* allocate local 0 (object) */
2062 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2064 g_assert (sig->hasthis);
2067 * if (prev != null)
2068 * prev.Invoke( args .. );
2069 * return this.<target>( args .. );
2072 /* this wrapper can be used in unmanaged-managed transitions */
2073 emit_thread_interrupt_checkpoint (mb);
2075 /* get this->prev */
2076 mono_mb_emit_ldarg (mb, 0);
2077 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
2078 mono_mb_emit_byte (mb, CEE_LDIND_I );
2079 mono_mb_emit_stloc (mb, 0);
2081 /* if prev != null */
2082 mono_mb_emit_ldloc (mb, 0);
2083 mono_mb_emit_byte (mb, CEE_BRFALSE);
2085 pos0 = mb->pos;
2086 mono_mb_emit_i4 (mb, 0);
2088 /* then recurse */
2089 mono_mb_emit_ldloc (mb, 0);
2090 for (i = 0; i < sig->param_count; i++)
2091 mono_mb_emit_ldarg (mb, i + 1);
2092 mono_mb_emit_managed_call (mb, method, method->signature);
2093 if (sig->ret->type != MONO_TYPE_VOID)
2094 mono_mb_emit_byte (mb, CEE_POP);
2096 /* continued or prev == null */
2097 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
2099 /* get this->target */
2100 mono_mb_emit_ldarg (mb, 0);
2101 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, target));
2102 mono_mb_emit_byte (mb, CEE_LDIND_I );
2103 mono_mb_emit_stloc (mb, 0);
2105 /* if target != null */
2106 mono_mb_emit_ldloc (mb, 0);
2107 mono_mb_emit_byte (mb, CEE_BRFALSE);
2108 pos0 = mb->pos;
2109 mono_mb_emit_i4 (mb, 0);
2111 /* then call this->method_ptr nonstatic */
2112 mono_mb_emit_ldloc (mb, 0);
2113 for (i = 0; i < sig->param_count; ++i)
2114 mono_mb_emit_ldarg (mb, i + 1);
2115 mono_mb_emit_ldarg (mb, 0);
2116 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
2117 mono_mb_emit_byte (mb, CEE_LDIND_I );
2118 mono_mb_emit_byte (mb, CEE_CALLI);
2119 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
2121 mono_mb_emit_byte (mb, CEE_BR);
2122 pos1 = mb->pos;
2123 mono_mb_emit_i4 (mb, 0);
2125 /* else [target == null] call this->method_ptr static */
2126 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
2128 for (i = 0; i < sig->param_count; ++i)
2129 mono_mb_emit_ldarg (mb, i + 1);
2130 mono_mb_emit_ldarg (mb, 0);
2131 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
2132 mono_mb_emit_byte (mb, CEE_LDIND_I );
2133 mono_mb_emit_byte (mb, CEE_CALLI);
2134 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
2136 /* return */
2137 mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
2138 mono_mb_emit_byte (mb, CEE_RET);
2140 res = mono_mb_create_and_cache (cache, sig,
2141 mb, sig, sig->param_count + 16);
2142 mono_mb_free (mb);
2144 return res;
2148 * signature_dup_add_this:
2150 * Make a copy of @sig, adding an explicit this argument.
2152 static MonoMethodSignature*
2153 signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass)
2155 MonoMethodSignature *res;
2156 int i;
2158 res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1);
2159 memcpy (res, sig, sizeof (MonoMethodSignature));
2160 res->param_count = sig->param_count + 1;
2161 res->hasthis = FALSE;
2162 for (i = sig->param_count - 1; i >= 0; i --)
2163 res->params [i + 1] = sig->params [i];
2164 res->params [0] = &mono_ptr_class_get (&klass->byval_arg)->byval_arg;
2166 return res;
2169 typedef struct {
2170 MonoMethod *ctor;
2171 MonoMethodSignature *sig;
2172 } CtorSigPair;
2177 * generates IL code for the runtime invoke function
2178 * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
2180 * we also catch exceptions if exc != null
2182 MonoMethod *
2183 mono_marshal_get_runtime_invoke (MonoMethod *method)
2185 MonoMethodSignature *sig, *csig, *callsig;
2186 MonoExceptionClause *clause;
2187 MonoMethodHeader *header;
2188 MonoMethodBuilder *mb;
2189 GHashTable *cache = NULL;
2190 MonoClass *target_klass;
2191 MonoMethod *res = NULL;
2192 GSList *item;
2193 static MonoString *string_dummy = NULL;
2194 static MonoMethodSignature *dealy_abort_sig = NULL;
2195 int i, pos, posna;
2196 char *name;
2198 g_assert (method);
2200 target_klass = method->klass;
2202 EnterCriticalSection (&marshal_mutex);
2204 if (method->string_ctor) {
2205 static GSList *strsig_list = NULL;
2206 CtorSigPair *cs;
2208 callsig = NULL;
2209 for (item = strsig_list; item; item = item->next) {
2210 cs = item->data;
2211 if (mono_metadata_signature_equal (method->signature, cs->ctor->signature)) {
2212 callsig = cs->sig;
2213 break;
2216 if (!callsig) {
2217 callsig = mono_metadata_signature_dup (method->signature);
2218 callsig->ret = &mono_defaults.string_class->byval_arg;
2219 cs = g_new (CtorSigPair, 1);
2220 cs->sig = callsig;
2221 cs->ctor = method;
2222 strsig_list = g_slist_prepend (strsig_list, cs);
2224 } else {
2225 if (method->klass->valuetype && method->signature->hasthis) {
2227 * Valuetype methods receive a managed pointer as the this argument.
2228 * Create a new signature to reflect this.
2230 callsig = signature_dup_add_this (method->signature, method->klass);
2232 else
2233 callsig = method->signature;
2236 cache = method->klass->image->runtime_invoke_cache;
2238 /* from mono_marshal_find_in_cache */
2239 res = g_hash_table_lookup (cache, callsig);
2240 LeaveCriticalSection (&marshal_mutex);
2242 if (res) {
2243 return res;
2246 if (!dealy_abort_sig) {
2247 dealy_abort_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
2248 dealy_abort_sig->ret = &mono_defaults.void_class->byval_arg;
2249 dealy_abort_sig->pinvoke = 0;
2252 target_klass = mono_defaults.object_class;
2254 /* to make it work with our special string constructors */
2255 if (!string_dummy) {
2256 MONO_GC_REGISTER_ROOT (string_dummy);
2257 string_dummy = mono_string_new_wrapper ("dummy");
2260 sig = method->signature;
2262 csig = mono_metadata_signature_alloc (method->klass->image, 4);
2264 csig->ret = &mono_defaults.object_class->byval_arg;
2265 if (method->klass->valuetype && method->signature->hasthis)
2266 csig->params [0] = callsig->params [0];
2267 else
2268 csig->params [0] = &mono_defaults.object_class->byval_arg;
2269 csig->params [1] = &mono_defaults.int_class->byval_arg;
2270 csig->params [2] = &mono_defaults.int_class->byval_arg;
2271 csig->params [3] = &mono_defaults.int_class->byval_arg;
2273 name = mono_signature_to_name (callsig, "runtime_invoke");
2274 mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE);
2275 g_free (name);
2277 /* allocate local 0 (object) tmp */
2278 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2279 /* allocate local 1 (object) exc */
2280 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2282 /* cond set *exc to null */
2283 mono_mb_emit_byte (mb, CEE_LDARG_2);
2284 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
2285 mono_mb_emit_byte (mb, 3);
2286 mono_mb_emit_byte (mb, CEE_LDARG_2);
2287 mono_mb_emit_byte (mb, CEE_LDNULL);
2288 mono_mb_emit_byte (mb, CEE_STIND_I);
2290 if (sig->hasthis) {
2291 if (method->string_ctor) {
2292 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2293 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
2294 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
2295 } else {
2296 mono_mb_emit_ldarg (mb, 0);
2300 for (i = 0; i < sig->param_count; i++) {
2301 MonoType *t = sig->params [i];
2302 int type;
2304 mono_mb_emit_ldarg (mb, 1);
2305 if (i) {
2306 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
2307 mono_mb_emit_byte (mb, CEE_ADD);
2309 mono_mb_emit_byte (mb, CEE_LDIND_I);
2311 if (t->byref)
2312 continue;
2314 type = sig->params [i]->type;
2315 handle_enum:
2316 switch (type) {
2317 case MONO_TYPE_I1:
2318 mono_mb_emit_byte (mb, CEE_LDIND_I1);
2319 break;
2320 case MONO_TYPE_BOOLEAN:
2321 case MONO_TYPE_U1:
2322 mono_mb_emit_byte (mb, CEE_LDIND_U1);
2323 break;
2324 case MONO_TYPE_I2:
2325 mono_mb_emit_byte (mb, CEE_LDIND_I2);
2326 break;
2327 case MONO_TYPE_U2:
2328 case MONO_TYPE_CHAR:
2329 mono_mb_emit_byte (mb, CEE_LDIND_U2);
2330 break;
2331 case MONO_TYPE_I:
2332 case MONO_TYPE_U:
2333 mono_mb_emit_byte (mb, CEE_LDIND_I);
2334 break;
2335 case MONO_TYPE_I4:
2336 mono_mb_emit_byte (mb, CEE_LDIND_I4);
2337 break;
2338 case MONO_TYPE_U4:
2339 mono_mb_emit_byte (mb, CEE_LDIND_U4);
2340 break;
2341 case MONO_TYPE_R4:
2342 mono_mb_emit_byte (mb, CEE_LDIND_R4);
2343 break;
2344 case MONO_TYPE_R8:
2345 mono_mb_emit_byte (mb, CEE_LDIND_R8);
2346 break;
2347 case MONO_TYPE_I8:
2348 case MONO_TYPE_U8:
2349 mono_mb_emit_byte (mb, CEE_LDIND_I8);
2350 break;
2351 case MONO_TYPE_STRING:
2352 case MONO_TYPE_CLASS:
2353 case MONO_TYPE_ARRAY:
2354 case MONO_TYPE_PTR:
2355 case MONO_TYPE_SZARRAY:
2356 case MONO_TYPE_OBJECT:
2357 /* do nothing */
2358 break;
2359 case MONO_TYPE_VALUETYPE:
2360 if (t->data.klass->enumtype) {
2361 type = t->data.klass->enum_basetype->type;
2362 goto handle_enum;
2364 mono_mb_emit_byte (mb, CEE_LDOBJ);
2365 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
2366 break;
2367 default:
2368 g_assert_not_reached ();
2372 mono_mb_emit_ldarg (mb, 3);
2373 emit_thread_force_interrupt_checkpoint (mb);
2374 mono_mb_emit_calli (mb, callsig);
2376 if (sig->ret->byref) {
2377 /* fixme: */
2378 g_assert_not_reached ();
2382 switch (sig->ret->type) {
2383 case MONO_TYPE_VOID:
2384 if (!method->string_ctor)
2385 mono_mb_emit_byte (mb, CEE_LDNULL);
2386 break;
2387 case MONO_TYPE_BOOLEAN:
2388 case MONO_TYPE_CHAR:
2389 case MONO_TYPE_I1:
2390 case MONO_TYPE_U1:
2391 case MONO_TYPE_I2:
2392 case MONO_TYPE_U2:
2393 case MONO_TYPE_I4:
2394 case MONO_TYPE_U4:
2395 case MONO_TYPE_I:
2396 case MONO_TYPE_U:
2397 case MONO_TYPE_R4:
2398 case MONO_TYPE_R8:
2399 case MONO_TYPE_I8:
2400 case MONO_TYPE_U8:
2401 case MONO_TYPE_VALUETYPE:
2402 /* box value types */
2403 mono_mb_emit_byte (mb, CEE_BOX);
2404 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret)));
2405 break;
2406 case MONO_TYPE_STRING:
2407 case MONO_TYPE_CLASS:
2408 case MONO_TYPE_ARRAY:
2409 case MONO_TYPE_SZARRAY:
2410 case MONO_TYPE_OBJECT:
2411 /* nothing to do */
2412 break;
2413 case MONO_TYPE_PTR:
2414 default:
2415 g_assert_not_reached ();
2418 mono_mb_emit_stloc (mb, 0);
2420 mono_mb_emit_byte (mb, CEE_LEAVE);
2421 pos = mb->pos;
2422 mono_mb_emit_i4 (mb, 0);
2424 clause = g_new0 (MonoExceptionClause, 1);
2425 clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
2426 clause->try_len = mb->pos;
2428 /* filter code */
2429 clause->token_or_filter = mb->pos;
2431 mono_mb_emit_byte (mb, CEE_POP);
2432 mono_mb_emit_byte (mb, CEE_LDARG_2);
2433 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2434 mono_mb_emit_byte (mb, CEE_PREFIX1);
2435 mono_mb_emit_byte (mb, CEE_CGT_UN);
2436 mono_mb_emit_byte (mb, CEE_PREFIX1);
2437 mono_mb_emit_byte (mb, CEE_ENDFILTER);
2439 clause->handler_offset = mb->pos;
2441 /* handler code */
2442 /* store exception */
2443 mono_mb_emit_stloc (mb, 1);
2445 mono_mb_emit_byte (mb, CEE_LDARG_2);
2446 mono_mb_emit_ldloc (mb, 1);
2447 mono_mb_emit_byte (mb, CEE_STIND_I);
2449 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2450 mono_mb_emit_stloc (mb, 0);
2452 /* Check for the abort exception */
2453 mono_mb_emit_ldloc (mb, 1);
2454 mono_mb_emit_byte (mb, CEE_ISINST);
2455 mono_mb_emit_i4 (mb, mono_defaults.threadabortexception_class->type_token);
2456 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
2457 posna = mb->pos;
2458 mono_mb_emit_byte (mb, 0);
2460 /* Delay the abort exception */
2461 mono_mb_emit_native_call (mb, dealy_abort_sig, ves_icall_System_Threading_Thread_ResetAbort);
2463 mono_mb_patch_addr_s (mb, posna, mb->pos - posna - 1);
2464 mono_mb_emit_byte (mb, CEE_LEAVE);
2465 mono_mb_emit_i4 (mb, 0);
2467 clause->handler_len = mb->pos - clause->handler_offset;
2469 /* return result */
2470 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2471 mono_mb_emit_ldloc (mb, 0);
2472 mono_mb_emit_byte (mb, CEE_RET);
2474 /* taken from mono_mb_create_and_cache */
2475 EnterCriticalSection (&marshal_mutex);
2477 res = g_hash_table_lookup (cache, callsig);
2478 /* Somebody may have created it before us */
2479 if (!res) {
2480 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
2481 g_hash_table_insert (cache, callsig, res);
2482 mono_g_hash_table_insert (wrapper_hash, res, callsig);
2485 LeaveCriticalSection (&marshal_mutex);
2486 /* end mono_mb_create_and_cache */
2488 mono_mb_free (mb);
2490 header = ((MonoMethodNormal *)res)->header;
2491 header->num_clauses = 1;
2492 header->clauses = clause;
2494 return res;
2497 static void
2498 raise_auto_layout_exception (MonoClass *klass)
2500 char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
2501 klass->name_space, klass->name);
2503 MonoException *e = mono_exception_from_name_msg (
2504 mono_get_corlib (), "System.Runtime.InteropServices",
2505 "MarshalDirectiveException", msg);
2506 g_free (msg);
2507 mono_raise_exception (e);
2511 * generates IL code to call managed methods from unmanaged code
2513 MonoMethod *
2514 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMarshalSpec **mspecs)
2516 MonoMethodSignature *sig, *csig;
2517 MonoMethodBuilder *mb;
2518 MonoClass *klass = NULL;
2519 MonoMethod *res;
2520 GHashTable *cache;
2521 int i, pos = 0, *tmp_locals;
2522 static MonoMethodSignature *alloc_sig = NULL;
2523 int retobj_var = 0;
2525 g_assert (method != NULL);
2526 g_assert (!method->signature->pinvoke);
2528 cache = method->klass->image->managed_wrapper_cache;
2529 if (!this && (res = mono_marshal_find_in_cache (cache, method)))
2530 return res;
2532 /* Under MS, the allocation should be done using CoTaskMemAlloc */
2533 if (!alloc_sig) {
2534 alloc_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
2535 alloc_sig->params [0] = &mono_defaults.int_class->byval_arg;
2536 alloc_sig->ret = &mono_defaults.int_class->byval_arg;
2537 alloc_sig->pinvoke = 1;
2540 sig = method->signature;
2542 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2544 /* allocate local 0 (pointer) src_ptr */
2545 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2546 /* allocate local 1 (pointer) dst_ptr */
2547 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2548 /* allocate local 2 (boolean) delete_old */
2549 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
2551 if (!MONO_TYPE_IS_VOID(sig->ret)) {
2552 /* allocate local 3 to store the return value */
2553 mono_mb_add_local (mb, sig->ret);
2556 mono_mb_emit_icon (mb, 0);
2557 mono_mb_emit_byte (mb, CEE_STLOC_2);
2559 /* we copy the signature, so that we can modify it */
2560 csig = mono_metadata_signature_dup (sig);
2561 csig->hasthis = 0;
2562 csig->pinvoke = 1;
2564 #ifdef PLATFORM_WIN32
2566 * Under windows, delegates passed to native code must use the STDCALL
2567 * calling convention.
2569 csig->call_convention = MONO_CALL_STDCALL;
2570 #endif
2572 /* fixme: howto handle this ? */
2573 if (sig->hasthis) {
2575 if (this) {
2576 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2577 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
2578 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, this));
2581 } else {
2582 /* fixme: */
2583 g_assert_not_reached ();
2588 /* we first do all conversions */
2589 tmp_locals = alloca (sizeof (int) * sig->param_count);
2590 for (i = 0; i < sig->param_count; i ++) {
2591 MonoType *t = sig->params [i];
2592 MonoMarshalSpec *spec = mspecs [i + 1];
2594 tmp_locals [i] = 0;
2596 /* Ensure that we have marshalling info for this param */
2597 mono_marshal_load_type_info (mono_class_from_mono_type (t));
2599 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
2600 MonoType *mtype;
2601 MonoClass *mklass;
2602 MonoMethod *marshal_native_to_managed;
2603 MonoMethod *get_instance;
2605 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
2606 g_assert (mtype != NULL);
2607 mklass = mono_class_from_mono_type (mtype);
2608 g_assert (mklass != NULL);
2610 marshal_native_to_managed = mono_find_method_by_name (mklass, "MarshalNativeToManaged", 1);
2611 g_assert (marshal_native_to_managed);
2612 get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
2613 g_assert (get_instance);
2615 switch (t->type) {
2616 case MONO_TYPE_CLASS:
2617 case MONO_TYPE_OBJECT:
2618 case MONO_TYPE_STRING:
2619 case MONO_TYPE_ARRAY:
2620 case MONO_TYPE_SZARRAY:
2621 if (t->byref)
2622 break;
2624 tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2626 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
2628 mono_mb_emit_byte (mb, CEE_CALL);
2629 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
2631 mono_mb_emit_ldarg (mb, i);
2633 mono_mb_emit_byte (mb, CEE_CALLVIRT);
2634 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
2636 mono_mb_emit_stloc (mb, tmp_locals [i]);
2637 break;
2638 default:
2639 g_warning ("custom marshalling of type %x is currently not supported", t->type);
2640 g_assert_not_reached ();
2641 break;
2643 continue;
2646 switch (t->type) {
2647 case MONO_TYPE_CLASS: {
2648 klass = t->data.klass;
2650 tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2652 if (klass->delegate) {
2653 g_assert (!t->byref);
2654 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2655 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
2656 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
2657 mono_mb_emit_ldarg (mb, i);
2658 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
2659 mono_mb_emit_stloc (mb, tmp_locals [i]);
2660 break;
2663 /* The class can not have an automatic layout */
2664 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
2665 raise_auto_layout_exception (klass);
2667 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2668 mono_mb_emit_byte (mb, CEE_LDNULL);
2669 mono_mb_emit_stloc (mb, tmp_locals [i]);
2670 break;
2673 /* Set src */
2674 mono_mb_emit_ldarg (mb, i);
2675 if (t->byref) {
2676 int pos2;
2678 /* Check for NULL and raise an exception */
2679 mono_mb_emit_byte (mb, CEE_BRTRUE);
2680 pos2 = mb->pos;
2681 mono_mb_emit_i4 (mb, 0);
2683 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
2685 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
2686 mono_mb_emit_ldarg (mb, i);
2687 mono_mb_emit_byte (mb, CEE_LDIND_I);
2690 mono_mb_emit_byte (mb, CEE_STLOC_0);
2692 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2693 mono_mb_emit_stloc (mb, tmp_locals [i]);
2695 mono_mb_emit_byte (mb, CEE_LDLOC_0);
2696 mono_mb_emit_byte (mb, CEE_BRFALSE);
2697 pos = mb->pos;
2698 mono_mb_emit_i4 (mb, 0);
2700 /* Create and set dst */
2701 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2702 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
2703 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
2704 mono_mb_emit_stloc (mb, tmp_locals [i]);
2705 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2706 mono_mb_emit_icon (mb, sizeof (MonoObject));
2707 mono_mb_emit_byte (mb, CEE_ADD);
2708 mono_mb_emit_byte (mb, CEE_STLOC_1);
2710 /* emit valuetype conversion code */
2711 emit_struct_conv (mb, klass, TRUE);
2713 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2714 break;
2716 case MONO_TYPE_VALUETYPE:
2718 klass = sig->params [i]->data.klass;
2719 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2720 klass->blittable || klass->enumtype)
2721 break;
2723 tmp_locals [i] = mono_mb_add_local (mb, &klass->byval_arg);
2725 if (t->attrs & PARAM_ATTRIBUTE_OUT)
2726 break;
2728 if (t->byref)
2729 mono_mb_emit_ldarg (mb, i);
2730 else
2731 mono_mb_emit_ldarg_addr (mb, i);
2732 mono_mb_emit_byte (mb, CEE_STLOC_0);
2734 if (t->byref) {
2735 mono_mb_emit_byte (mb, CEE_LDLOC_0);
2736 mono_mb_emit_byte (mb, CEE_BRFALSE);
2737 pos = mb->pos;
2738 mono_mb_emit_i4 (mb, 0);
2741 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2742 mono_mb_emit_byte (mb, CEE_STLOC_1);
2744 /* emit valuetype conversion code */
2745 emit_struct_conv (mb, klass, TRUE);
2747 if (t->byref)
2748 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2749 break;
2750 case MONO_TYPE_STRING: {
2751 MonoMarshalNative encoding = mono_marshal_get_string_encoding (NULL, spec);
2753 if (t->byref)
2754 continue;
2756 tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2757 csig->params [i] = &mono_defaults.int_class->byval_arg;
2759 mono_mb_emit_ldarg (mb, i);
2761 switch (encoding) {
2762 case MONO_NATIVE_LPWSTR:
2763 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPWSTR_STR));
2764 break;
2765 case MONO_NATIVE_LPSTR:
2766 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
2767 break;
2768 default: {
2769 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
2770 MonoException *exc = mono_get_exception_not_implemented (msg);
2771 g_warning (msg);
2772 g_free (msg);
2773 mono_raise_exception (exc);
2777 mono_mb_emit_stloc (mb, tmp_locals [i]);
2778 break;
2780 case MONO_TYPE_ARRAY:
2781 case MONO_TYPE_SZARRAY:
2782 if (t->byref)
2783 continue;
2785 klass = mono_class_from_mono_type (t);
2787 tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2788 csig->params [i] = &mono_defaults.int_class->byval_arg;
2790 g_warning ("array marshaling not implemented");
2791 g_assert_not_reached ();
2792 break;
2796 for (i = 0; i < sig->param_count; i++) {
2797 MonoType *t = sig->params [i];
2799 switch (t->type) {
2800 case MONO_TYPE_BOOLEAN:
2801 case MONO_TYPE_I1:
2802 case MONO_TYPE_U1:
2803 case MONO_TYPE_I2:
2804 case MONO_TYPE_U2:
2805 case MONO_TYPE_I4:
2806 case MONO_TYPE_U4:
2807 case MONO_TYPE_I:
2808 case MONO_TYPE_U:
2809 case MONO_TYPE_PTR:
2810 case MONO_TYPE_R4:
2811 case MONO_TYPE_R8:
2812 case MONO_TYPE_I8:
2813 case MONO_TYPE_U8:
2814 mono_mb_emit_ldarg (mb, i);
2815 break;
2816 case MONO_TYPE_STRING:
2817 if (t->byref) {
2818 mono_mb_emit_ldarg (mb, i);
2819 } else {
2820 g_assert (tmp_locals [i]);
2821 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2823 break;
2824 case MONO_TYPE_CLASS:
2825 if (t->byref)
2826 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2827 else
2828 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2829 break;
2830 case MONO_TYPE_ARRAY:
2831 case MONO_TYPE_SZARRAY:
2832 case MONO_TYPE_OBJECT:
2833 if (tmp_locals [i])
2834 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2835 else
2836 mono_mb_emit_ldarg (mb, i);
2837 break;
2838 case MONO_TYPE_VALUETYPE:
2839 klass = sig->params [i]->data.klass;
2840 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2841 klass->blittable || klass->enumtype) {
2842 mono_mb_emit_ldarg (mb, i);
2843 break;
2846 g_assert (tmp_locals [i]);
2847 if (t->byref)
2848 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2849 else
2850 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2851 break;
2852 default:
2853 g_warning ("type 0x%02x unknown", t->type);
2854 g_assert_not_reached ();
2858 emit_thread_interrupt_checkpoint (mb);
2859 mono_mb_emit_managed_call (mb, method, NULL);
2861 /* Ensure that we have marshalling info for the return */
2862 mono_marshal_load_type_info (mono_class_from_mono_type (sig->ret));
2864 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
2865 MonoMarshalSpec *spec = mspecs [0];
2866 MonoType *mtype;
2867 MonoClass *mklass;
2868 guint32 loc1;
2870 g_assert (!sig->ret->byref);
2872 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
2873 g_assert (mtype);
2874 mklass = mono_class_from_mono_type (mtype);
2875 g_assert (mklass);
2877 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2879 switch (sig->ret->type) {
2880 case MONO_TYPE_CLASS:
2881 case MONO_TYPE_OBJECT:
2882 case MONO_TYPE_STRING:
2883 case MONO_TYPE_ARRAY:
2884 case MONO_TYPE_SZARRAY:
2885 mono_mb_emit_byte (mb, CEE_STLOC_3);
2887 mono_mb_emit_byte (mb, CEE_LDLOC_3);
2888 mono_mb_emit_stloc (mb, loc1);
2890 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
2891 mono_mb_emit_byte (mb, CEE_CALL);
2892 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_find_method_by_name (mklass, "GetInstance", 1)));
2893 mono_mb_emit_byte (mb, CEE_DUP);
2895 mono_mb_emit_byte (mb, CEE_LDLOC_3);
2896 mono_mb_emit_byte (mb, CEE_CALLVIRT);
2897 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_find_method_by_name (mklass, "MarshalManagedToNative", 1)));
2898 mono_mb_emit_byte (mb, CEE_STLOC_3);
2900 mono_mb_emit_ldloc (mb, loc1);
2901 mono_mb_emit_byte (mb, CEE_CALLVIRT);
2902 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_find_method_by_name (mklass, "CleanUpManagedData", 1)));
2904 break;
2905 default:
2906 g_warning ("custom marshalling of type %x is currently not supported", sig->ret->type);
2907 g_assert_not_reached ();
2908 break;
2911 else
2912 if (!sig->ret->byref) {
2913 switch (sig->ret->type) {
2914 case MONO_TYPE_VOID:
2915 break;
2916 case MONO_TYPE_BOOLEAN:
2917 case MONO_TYPE_I1:
2918 case MONO_TYPE_U1:
2919 case MONO_TYPE_I2:
2920 case MONO_TYPE_U2:
2921 case MONO_TYPE_I4:
2922 case MONO_TYPE_U4:
2923 case MONO_TYPE_I:
2924 case MONO_TYPE_U:
2925 case MONO_TYPE_PTR:
2926 case MONO_TYPE_R4:
2927 case MONO_TYPE_R8:
2928 case MONO_TYPE_I8:
2929 case MONO_TYPE_U8:
2930 case MONO_TYPE_OBJECT:
2931 mono_mb_emit_byte (mb, CEE_STLOC_3);
2932 break;
2933 case MONO_TYPE_STRING:
2934 csig->ret = &mono_defaults.int_class->byval_arg;
2936 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPSTR));
2937 mono_mb_emit_byte (mb, CEE_STLOC_3);
2938 break;
2939 case MONO_TYPE_VALUETYPE:
2940 klass = sig->ret->data.klass;
2941 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2942 klass->blittable || klass->enumtype)
2943 break;
2945 /* load pointer to returned value type */
2946 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2947 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
2949 /* store the address of the source into local variable 0 */
2950 mono_mb_emit_byte (mb, CEE_STLOC_0);
2951 /* allocate space for the native struct and
2952 * store the address into dst_ptr */
2953 retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2954 g_assert (retobj_var);
2955 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
2956 mono_mb_emit_byte (mb, CEE_CONV_I);
2957 mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
2958 emit_thread_interrupt_checkpoint (mb);
2959 mono_mb_emit_byte (mb, CEE_STLOC_1);
2960 mono_mb_emit_byte (mb, CEE_LDLOC_1);
2961 mono_mb_emit_stloc (mb, retobj_var);
2963 /* emit valuetype conversion code */
2964 emit_struct_conv (mb, klass, FALSE);
2965 break;
2966 case MONO_TYPE_CLASS: {
2967 int pos2;
2969 klass = sig->ret->data.klass;
2971 if (klass->delegate) {
2972 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
2973 mono_mb_emit_byte (mb, CEE_STLOC_3);
2974 break;
2977 /* The class can not have an automatic layout */
2978 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
2979 raise_auto_layout_exception (klass);
2981 mono_mb_emit_byte (mb, CEE_STLOC_0);
2982 /* Check for null */
2983 mono_mb_emit_byte (mb, CEE_LDLOC_0);
2984 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
2985 mono_mb_emit_byte (mb, CEE_LDNULL);
2986 mono_mb_emit_byte (mb, CEE_STLOC_3);
2987 pos2 = mono_mb_emit_branch (mb, CEE_BR);
2989 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2991 /* Set src */
2992 mono_mb_emit_byte (mb, CEE_LDLOC_0);
2993 mono_mb_emit_icon (mb, sizeof (MonoObject));
2994 mono_mb_emit_byte (mb, CEE_ADD);
2995 mono_mb_emit_byte (mb, CEE_STLOC_0);
2997 /* Allocate and set dest */
2998 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
2999 mono_mb_emit_byte (mb, CEE_CONV_I);
3000 mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
3001 emit_thread_interrupt_checkpoint (mb);
3002 mono_mb_emit_byte (mb, CEE_DUP);
3003 mono_mb_emit_byte (mb, CEE_STLOC_1);
3004 mono_mb_emit_byte (mb, CEE_STLOC_3);
3006 emit_struct_conv (mb, klass, FALSE);
3008 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
3009 break;
3011 default:
3012 g_warning ("return type 0x%02x unknown", sig->ret->type);
3013 g_assert_not_reached ();
3015 } else {
3016 mono_mb_emit_byte (mb, CEE_STLOC_3);
3019 /* Convert byref arguments back */
3020 for (i = 0; i < sig->param_count; i ++) {
3021 MonoType *t = sig->params [i];
3022 MonoMarshalSpec *spec = mspecs [i + 1];
3024 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
3025 MonoType *mtype;
3026 MonoClass *mklass;
3027 MonoMethod *cleanup_managed;
3028 MonoMethod *get_instance;
3030 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
3031 g_assert (mtype != NULL);
3032 mklass = mono_class_from_mono_type (mtype);
3033 g_assert (mklass != NULL);
3035 get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
3036 g_assert (get_instance);
3037 cleanup_managed = mono_find_method_by_name (mklass, "CleanUpManagedData", 1);
3038 g_assert (cleanup_managed);
3040 switch (t->type) {
3041 case MONO_TYPE_CLASS:
3042 case MONO_TYPE_OBJECT:
3043 case MONO_TYPE_STRING:
3044 case MONO_TYPE_ARRAY:
3045 case MONO_TYPE_SZARRAY:
3046 if (t->byref)
3047 g_assert_not_reached ();
3049 /* Call CleanUpManagedData */
3051 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
3053 mono_mb_emit_byte (mb, CEE_CALL);
3054 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3056 mono_mb_emit_ldloc (mb, tmp_locals [i]);
3057 mono_mb_emit_byte (mb, CEE_CALLVIRT);
3058 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_managed));
3060 break;
3061 default:
3062 g_warning ("custom marshalling of type %x is currently not supported", t->type);
3063 g_assert_not_reached ();
3064 break;
3066 continue;
3069 if (!t->byref)
3070 continue;
3072 switch (t->type) {
3073 case MONO_TYPE_CLASS: {
3074 int pos2;
3076 klass = t->data.klass;
3078 /* Check for null */
3079 mono_mb_emit_ldloc (mb, tmp_locals [i]);
3080 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
3081 mono_mb_emit_ldarg (mb, i);
3082 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3083 mono_mb_emit_byte (mb, CEE_STIND_I);
3084 pos2 = mono_mb_emit_branch (mb, CEE_BR);
3086 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3088 /* Set src */
3089 mono_mb_emit_ldloc (mb, tmp_locals [i]);
3090 mono_mb_emit_icon (mb, sizeof (MonoObject));
3091 mono_mb_emit_byte (mb, CEE_ADD);
3092 mono_mb_emit_byte (mb, CEE_STLOC_0);
3094 /* Allocate and set dest */
3095 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
3096 mono_mb_emit_byte (mb, CEE_CONV_I);
3097 mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
3098 emit_thread_interrupt_checkpoint (mb);
3099 mono_mb_emit_byte (mb, CEE_STLOC_1);
3101 /* Update argument pointer */
3102 mono_mb_emit_ldarg (mb, i);
3103 mono_mb_emit_byte (mb, CEE_LDLOC_1);
3104 mono_mb_emit_byte (mb, CEE_STIND_I);
3106 /* emit valuetype conversion code */
3107 emit_struct_conv (mb, klass, FALSE);
3109 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
3110 break;
3112 case MONO_TYPE_VALUETYPE: {
3113 int pos2;
3115 klass = t->data.klass;
3117 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3118 klass->blittable || klass->enumtype) {
3119 break;
3122 /* Check for null */
3123 mono_mb_emit_ldarg (mb, i);
3124 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3126 /* Set src */
3127 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
3128 mono_mb_emit_byte (mb, CEE_STLOC_0);
3130 /* Set dest */
3131 mono_mb_emit_ldarg (mb, i);
3132 mono_mb_emit_byte (mb, CEE_STLOC_1);
3134 /* emit valuetype conversion code */
3135 emit_struct_conv (mb, klass, FALSE);
3137 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
3138 break;
3143 if (retobj_var) {
3144 mono_mb_emit_ldloc (mb, retobj_var);
3145 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3146 mono_mb_emit_byte (mb, CEE_MONO_RETOBJ);
3147 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3149 else {
3150 if (!MONO_TYPE_IS_VOID(sig->ret))
3151 mono_mb_emit_byte (mb, CEE_LDLOC_3);
3152 mono_mb_emit_byte (mb, CEE_RET);
3155 if (!this)
3156 res = mono_mb_create_and_cache (cache, method,
3157 mb, csig, sig->param_count + 16);
3158 else {
3159 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
3160 res->dynamic = 1;
3162 mono_mb_free (mb);
3164 /* 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)); */
3166 return res;
3170 * mono_marshal_get_ldfld_wrapper:
3171 * @type: the type of the field
3173 * This method generates a function which can be use to load a field with type
3174 * @type from an object. The generated function has the following signature:
3175 * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
3177 MonoMethod *
3178 mono_marshal_get_ldfld_wrapper (MonoType *type)
3180 MonoMethodSignature *sig, *csig;
3181 MonoMethodBuilder *mb;
3182 MonoMethod *res;
3183 MonoClass *klass;
3184 static GHashTable *ldfld_hash = NULL;
3185 char *name;
3186 int t, pos0, pos1 = 0;
3188 t = type->type;
3190 if (!type->byref) {
3191 if (type->type == MONO_TYPE_SZARRAY) {
3192 klass = mono_defaults.array_class;
3193 } else if (type->type == MONO_TYPE_VALUETYPE) {
3194 klass = type->data.klass;
3195 if (klass->enumtype) {
3196 t = klass->enum_basetype->type;
3197 klass = mono_class_from_mono_type (klass->enum_basetype);
3199 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
3200 t == MONO_TYPE_CLASS) {
3201 klass = mono_defaults.object_class;
3202 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
3203 klass = mono_defaults.int_class;
3204 } else {
3205 klass = mono_class_from_mono_type (type);
3207 } else {
3208 klass = mono_defaults.int_class;
3211 EnterCriticalSection (&marshal_mutex);
3212 if (!ldfld_hash)
3213 ldfld_hash = g_hash_table_new (NULL, NULL);
3214 res = g_hash_table_lookup (ldfld_hash, klass);
3215 LeaveCriticalSection (&marshal_mutex);
3216 if (res)
3217 return res;
3219 name = g_strdup_printf ("__ldfld_wrapper_%s.%s", klass->name_space, klass->name);
3220 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
3221 g_free (name);
3223 mb->method->save_lmf = 1;
3225 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
3226 sig->params [0] = &mono_defaults.object_class->byval_arg;
3227 sig->params [1] = &mono_defaults.int_class->byval_arg;
3228 sig->params [2] = &mono_defaults.int_class->byval_arg;
3229 sig->params [3] = &mono_defaults.int_class->byval_arg;
3230 sig->ret = &klass->byval_arg;
3232 mono_mb_emit_ldarg (mb, 0);
3233 pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3235 mono_mb_emit_ldarg (mb, 0);
3236 mono_mb_emit_ldarg (mb, 1);
3237 mono_mb_emit_ldarg (mb, 2);
3239 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
3240 csig->params [0] = &mono_defaults.object_class->byval_arg;
3241 csig->params [1] = &mono_defaults.int_class->byval_arg;
3242 csig->params [2] = &mono_defaults.int_class->byval_arg;
3243 csig->ret = &klass->this_arg;
3244 csig->pinvoke = 1;
3246 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
3247 emit_thread_interrupt_checkpoint (mb);
3249 if (klass->valuetype) {
3250 mono_mb_emit_byte (mb, CEE_UNBOX);
3251 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3252 mono_mb_emit_byte (mb, CEE_BR);
3253 pos1 = mb->pos;
3254 mono_mb_emit_i4 (mb, 0);
3255 } else {
3256 mono_mb_emit_byte (mb, CEE_RET);
3260 mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
3262 mono_mb_emit_ldarg (mb, 0);
3263 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3264 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3265 mono_mb_emit_ldarg (mb, 3);
3266 mono_mb_emit_byte (mb, CEE_ADD);
3268 if (klass->valuetype)
3269 mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
3271 switch (t) {
3272 case MONO_TYPE_I1:
3273 case MONO_TYPE_U1:
3274 case MONO_TYPE_BOOLEAN:
3275 mono_mb_emit_byte (mb, CEE_LDIND_I1);
3276 break;
3277 case MONO_TYPE_CHAR:
3278 case MONO_TYPE_I2:
3279 case MONO_TYPE_U2:
3280 mono_mb_emit_byte (mb, CEE_LDIND_I2);
3281 break;
3282 case MONO_TYPE_I4:
3283 case MONO_TYPE_U4:
3284 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3285 break;
3286 case MONO_TYPE_I8:
3287 case MONO_TYPE_U8:
3288 mono_mb_emit_byte (mb, CEE_LDIND_I8);
3289 break;
3290 case MONO_TYPE_R4:
3291 mono_mb_emit_byte (mb, CEE_LDIND_R4);
3292 break;
3293 case MONO_TYPE_R8:
3294 mono_mb_emit_byte (mb, CEE_LDIND_R8);
3295 break;
3296 case MONO_TYPE_ARRAY:
3297 case MONO_TYPE_PTR:
3298 case MONO_TYPE_FNPTR:
3299 case MONO_TYPE_SZARRAY:
3300 case MONO_TYPE_OBJECT:
3301 case MONO_TYPE_CLASS:
3302 case MONO_TYPE_STRING:
3303 case MONO_TYPE_I:
3304 case MONO_TYPE_U:
3305 mono_mb_emit_byte (mb, CEE_LDIND_I);
3306 break;
3307 case MONO_TYPE_VALUETYPE:
3308 g_assert (!klass->enumtype);
3309 mono_mb_emit_byte (mb, CEE_LDOBJ);
3310 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3311 break;
3312 default:
3313 g_warning ("type %x not implemented", type->type);
3314 g_assert_not_reached ();
3317 mono_mb_emit_byte (mb, CEE_RET);
3319 res = mono_mb_create_and_cache (ldfld_hash, klass,
3320 mb, sig, sig->param_count + 16);
3321 mono_mb_free (mb);
3323 return res;
3327 * mono_marshal_get_stfld_wrapper:
3328 * @type: the type of the field
3330 * This method generates a function which can be use to store a field with type
3331 * @type. The generated function has the following signature:
3332 * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
3334 MonoMethod *
3335 mono_marshal_get_stfld_wrapper (MonoType *type)
3337 MonoMethodSignature *sig, *csig;
3338 MonoMethodBuilder *mb;
3339 MonoMethod *res;
3340 MonoClass *klass;
3341 static GHashTable *stfld_hash = NULL;
3342 char *name;
3343 int t, pos;
3345 t = type->type;
3347 if (!type->byref) {
3348 if (type->type == MONO_TYPE_SZARRAY) {
3349 klass = mono_defaults.array_class;
3350 } else if (type->type == MONO_TYPE_VALUETYPE) {
3351 klass = type->data.klass;
3352 if (klass->enumtype) {
3353 t = klass->enum_basetype->type;
3354 klass = mono_class_from_mono_type (klass->enum_basetype);
3356 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
3357 t == MONO_TYPE_CLASS) {
3358 klass = mono_defaults.object_class;
3359 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
3360 klass = mono_defaults.int_class;
3361 } else {
3362 klass = mono_class_from_mono_type (type);
3364 } else {
3365 klass = mono_defaults.int_class;
3368 EnterCriticalSection (&marshal_mutex);
3369 if (!stfld_hash)
3370 stfld_hash = g_hash_table_new (NULL, NULL);
3371 res = g_hash_table_lookup (stfld_hash, klass);
3372 LeaveCriticalSection (&marshal_mutex);
3373 if (res)
3374 return res;
3376 name = g_strdup_printf ("__stfld_wrapper_%s.%s", klass->name_space, klass->name);
3377 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
3378 g_free (name);
3380 mb->method->save_lmf = 1;
3382 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
3383 sig->params [0] = &mono_defaults.object_class->byval_arg;
3384 sig->params [1] = &mono_defaults.int_class->byval_arg;
3385 sig->params [2] = &mono_defaults.int_class->byval_arg;
3386 sig->params [3] = &mono_defaults.int_class->byval_arg;
3387 sig->params [4] = &klass->byval_arg;
3388 sig->ret = &mono_defaults.void_class->byval_arg;
3390 mono_mb_emit_ldarg (mb, 0);
3391 pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3393 mono_mb_emit_ldarg (mb, 0);
3394 mono_mb_emit_ldarg (mb, 1);
3395 mono_mb_emit_ldarg (mb, 2);
3396 mono_mb_emit_ldarg (mb, 4);
3398 if (klass->valuetype) {
3399 mono_mb_emit_byte (mb, CEE_BOX);
3400 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3403 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
3404 csig->params [0] = &mono_defaults.object_class->byval_arg;
3405 csig->params [1] = &mono_defaults.int_class->byval_arg;
3406 csig->params [2] = &mono_defaults.int_class->byval_arg;
3407 csig->params [3] = &klass->this_arg;
3408 csig->ret = &mono_defaults.void_class->byval_arg;
3409 csig->pinvoke = 1;
3411 mono_mb_emit_native_call (mb, csig, mono_store_remote_field_new);
3412 emit_thread_interrupt_checkpoint (mb);
3414 mono_mb_emit_byte (mb, CEE_RET);
3416 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3418 mono_mb_emit_ldarg (mb, 0);
3419 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3420 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3421 mono_mb_emit_ldarg (mb, 3);
3422 mono_mb_emit_byte (mb, CEE_ADD);
3423 mono_mb_emit_ldarg (mb, 4);
3425 switch (t) {
3426 case MONO_TYPE_I1:
3427 case MONO_TYPE_U1:
3428 case MONO_TYPE_BOOLEAN:
3429 mono_mb_emit_byte (mb, CEE_STIND_I1);
3430 break;
3431 case MONO_TYPE_CHAR:
3432 case MONO_TYPE_I2:
3433 case MONO_TYPE_U2:
3434 mono_mb_emit_byte (mb, CEE_STIND_I2);
3435 break;
3436 case MONO_TYPE_I4:
3437 case MONO_TYPE_U4:
3438 mono_mb_emit_byte (mb, CEE_STIND_I4);
3439 break;
3440 case MONO_TYPE_I8:
3441 case MONO_TYPE_U8:
3442 mono_mb_emit_byte (mb, CEE_STIND_I8);
3443 break;
3444 case MONO_TYPE_R4:
3445 mono_mb_emit_byte (mb, CEE_STIND_R4);
3446 break;
3447 case MONO_TYPE_R8:
3448 mono_mb_emit_byte (mb, CEE_STIND_R8);
3449 break;
3450 case MONO_TYPE_ARRAY:
3451 case MONO_TYPE_PTR:
3452 case MONO_TYPE_FNPTR:
3453 case MONO_TYPE_SZARRAY:
3454 case MONO_TYPE_OBJECT:
3455 case MONO_TYPE_CLASS:
3456 case MONO_TYPE_STRING:
3457 case MONO_TYPE_I:
3458 case MONO_TYPE_U:
3459 mono_mb_emit_byte (mb, CEE_STIND_I);
3460 break;
3461 case MONO_TYPE_VALUETYPE:
3462 g_assert (!klass->enumtype);
3463 mono_mb_emit_byte (mb, CEE_STOBJ);
3464 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3465 break;
3466 default:
3467 g_warning ("type %x not implemented", type->type);
3468 g_assert_not_reached ();
3471 mono_mb_emit_byte (mb, CEE_RET);
3473 res = mono_mb_create_and_cache (stfld_hash, klass,
3474 mb, sig, sig->param_count + 16);
3475 mono_mb_free (mb);
3477 return res;
3481 * generates IL code for the icall wrapper (the generated method
3482 * calls the unmanaged code in func)
3484 MonoMethod *
3485 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func)
3487 MonoMethodSignature *csig;
3488 MonoMethodBuilder *mb;
3489 MonoMethod *res;
3490 int i;
3492 g_assert (sig->pinvoke);
3494 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
3496 mb->method->save_lmf = 1;
3498 /* we copy the signature, so that we can modify it */
3500 if (sig->hasthis)
3501 mono_mb_emit_byte (mb, CEE_LDARG_0);
3503 for (i = 0; i < sig->param_count; i++)
3504 mono_mb_emit_ldarg (mb, i + sig->hasthis);
3506 mono_mb_emit_native_call (mb, sig, (gpointer) func);
3507 emit_thread_interrupt_checkpoint (mb);
3508 mono_mb_emit_byte (mb, CEE_RET);
3510 csig = mono_metadata_signature_dup (sig);
3511 csig->pinvoke = 0;
3512 if (csig->call_convention == MONO_CALL_VARARG)
3513 csig->call_convention = 0;
3515 res = mono_mb_create_method (mb, csig, csig->param_count + 16);
3516 mono_mb_free (mb);
3518 return res;
3521 typedef struct {
3522 MonoMethodBuilder *mb;
3523 MonoMethodPInvoke *piinfo;
3524 int *orig_conv_args; /* Locals containing the original values of byref args */
3525 } EmitMarshalContext;
3527 typedef enum {
3528 MARSHAL_ACTION_CONV_IN,
3529 MARSHAL_ACTION_PUSH,
3530 MARSHAL_ACTION_CONV_OUT,
3531 MARSHAL_ACTION_CONV_RESULT
3532 } MarshalAction;
3534 static int
3535 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
3536 MonoMarshalSpec *spec,
3537 int conv_arg, MonoType **conv_arg_type,
3538 MarshalAction action)
3540 MonoType *mtype;
3541 MonoClass *mklass;
3542 MonoMethod *get_instance, *cleanup_native;
3543 MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
3544 MonoMethodBuilder *mb = m->mb;
3545 guint32 loc1;
3547 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, mb->method->klass->image);
3548 g_assert (mtype != NULL);
3549 mklass = mono_class_from_mono_type (mtype);
3550 g_assert (mklass != NULL);
3552 get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
3553 g_assert (get_instance);
3554 cleanup_native = mono_find_method_by_name (mklass, "CleanUpNativeData", 1);
3555 g_assert (cleanup_native);
3556 marshal_managed_to_native = mono_find_method_by_name (mklass, "MarshalManagedToNative", 1);
3557 g_assert (marshal_managed_to_native);
3558 marshal_native_to_managed = mono_find_method_by_name (mklass, "MarshalNativeToManaged", 1);
3559 g_assert (marshal_native_to_managed);
3561 switch (action) {
3562 case MARSHAL_ACTION_CONV_IN:
3563 switch (t->type) {
3564 case MONO_TYPE_CLASS:
3565 case MONO_TYPE_OBJECT:
3566 case MONO_TYPE_STRING:
3567 case MONO_TYPE_ARRAY:
3568 case MONO_TYPE_SZARRAY:
3569 case MONO_TYPE_VALUETYPE:
3570 if (t->byref)
3571 break;
3573 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3575 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
3577 mono_mb_emit_byte (mb, CEE_CALL);
3578 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3580 mono_mb_emit_ldarg (mb, argnum);
3582 if (t->type == MONO_TYPE_VALUETYPE) {
3584 * Since we can't determine the type of the argument, we
3585 * will assume the unmanaged function takes a pointer.
3587 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3589 mono_mb_emit_byte (mb, CEE_BOX);
3590 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (t)));
3593 mono_mb_emit_byte (mb, CEE_CALLVIRT);
3594 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native));
3595 mono_mb_emit_stloc (mb, conv_arg);
3596 break;
3598 default:
3599 g_warning ("custom marshalling of type %x is currently not supported", t->type);
3600 g_assert_not_reached ();
3601 break;
3604 break;
3606 case MARSHAL_ACTION_CONV_OUT:
3607 switch (t->type) {
3608 case MONO_TYPE_CLASS:
3609 case MONO_TYPE_OBJECT:
3610 case MONO_TYPE_STRING:
3611 case MONO_TYPE_ARRAY:
3612 case MONO_TYPE_SZARRAY:
3613 case MONO_TYPE_VALUETYPE:
3614 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
3616 mono_mb_emit_byte (mb, CEE_CALL);
3617 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3619 mono_mb_emit_ldloc (mb, conv_arg);
3621 mono_mb_emit_byte (mb, CEE_CALLVIRT);
3622 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native));
3624 break;
3626 default:
3627 g_warning ("custom marshalling of type %x is currently not supported", t->type);
3628 g_assert_not_reached ();
3629 break;
3631 break;
3633 case MARSHAL_ACTION_PUSH:
3634 mono_mb_emit_ldloc (mb, conv_arg);
3635 break;
3637 case MARSHAL_ACTION_CONV_RESULT:
3638 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3640 switch (t->type) {
3641 case MONO_TYPE_CLASS:
3642 case MONO_TYPE_OBJECT:
3643 case MONO_TYPE_STRING:
3644 case MONO_TYPE_ARRAY:
3645 case MONO_TYPE_SZARRAY:
3646 mono_mb_emit_byte (mb, CEE_STLOC_3);
3648 mono_mb_emit_byte (mb, CEE_LDLOC_3);
3649 mono_mb_emit_stloc (mb, loc1);
3651 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
3653 mono_mb_emit_byte (mb, CEE_CALL);
3654 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3655 mono_mb_emit_byte (mb, CEE_DUP);
3657 mono_mb_emit_byte (mb, CEE_LDLOC_3);
3658 mono_mb_emit_byte (mb, CEE_CALLVIRT);
3659 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
3660 mono_mb_emit_byte (mb, CEE_STLOC_3);
3662 mono_mb_emit_ldloc (mb, loc1);
3663 mono_mb_emit_byte (mb, CEE_CALLVIRT);
3664 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native));
3666 break;
3667 default:
3668 g_assert_not_reached ();
3669 break;
3671 break;
3673 default:
3674 g_assert_not_reached ();
3677 return conv_arg;
3680 static int
3681 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
3682 MonoMarshalSpec *spec,
3683 int conv_arg, MonoType **conv_arg_type,
3684 MarshalAction action)
3686 MonoMethodBuilder *mb = m->mb;
3688 switch (action) {
3689 case MARSHAL_ACTION_CONV_IN: {
3690 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
3692 g_assert (t->type == MONO_TYPE_OBJECT);
3693 g_assert (!t->byref);
3695 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3696 mono_mb_emit_ldarg (mb, argnum);
3697 mono_mb_emit_icon (mb, encoding);
3698 mono_mb_emit_icall (mb, mono_marshal_asany);
3699 mono_mb_emit_stloc (mb, conv_arg);
3700 break;
3703 case MARSHAL_ACTION_PUSH:
3704 mono_mb_emit_ldloc (mb, conv_arg);
3705 break;
3707 case MARSHAL_ACTION_CONV_OUT: {
3708 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
3710 mono_mb_emit_ldarg (mb, argnum);
3711 mono_mb_emit_ldloc (mb, conv_arg);
3712 mono_mb_emit_icon (mb, encoding);
3713 mono_mb_emit_icall (mb, mono_marshal_free_asany);
3714 break;
3717 default:
3718 g_assert_not_reached ();
3721 return conv_arg;
3724 static int
3725 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
3726 MonoMarshalSpec *spec,
3727 int conv_arg, MonoType **conv_arg_type,
3728 MarshalAction action)
3730 MonoMethodBuilder *mb = m->mb;
3731 MonoClass *klass;
3732 int pos = 0;
3734 klass = t->data.klass;
3736 switch (action) {
3737 case MARSHAL_ACTION_CONV_IN:
3738 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3739 klass->blittable || klass->enumtype)
3740 break;
3742 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3744 /* store the address of the source into local variable 0 */
3745 if (t->byref)
3746 mono_mb_emit_ldarg (mb, argnum);
3747 else
3748 mono_mb_emit_ldarg_addr (mb, argnum);
3750 mono_mb_emit_byte (mb, CEE_STLOC_0);
3752 /* allocate space for the native struct and
3753 * store the address into local variable 1 (dest) */
3754 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
3755 mono_mb_emit_byte (mb, CEE_PREFIX1);
3756 mono_mb_emit_byte (mb, CEE_LOCALLOC);
3757 mono_mb_emit_stloc (mb, conv_arg);
3759 if (t->byref) {
3760 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3761 mono_mb_emit_byte (mb, CEE_BRFALSE);
3762 pos = mb->pos;
3763 mono_mb_emit_i4 (mb, 0);
3766 /* set dst_ptr */
3767 mono_mb_emit_ldloc (mb, conv_arg);
3768 mono_mb_emit_byte (mb, CEE_STLOC_1);
3770 /* emit valuetype conversion code */
3771 emit_struct_conv (mb, klass, FALSE);
3773 if (t->byref)
3774 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3775 break;
3777 case MARSHAL_ACTION_PUSH:
3778 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3779 klass->blittable || klass->enumtype) {
3780 mono_mb_emit_ldarg (mb, argnum);
3781 break;
3783 mono_mb_emit_ldloc (mb, conv_arg);
3784 if (!t->byref) {
3785 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3786 mono_mb_emit_byte (mb, CEE_MONO_LDNATIVEOBJ);
3787 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3789 break;
3791 case MARSHAL_ACTION_CONV_OUT:
3792 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3793 klass->blittable || klass->enumtype)
3794 break;
3796 if (t->byref) {
3797 /* dst = argument */
3798 mono_mb_emit_ldarg (mb, argnum);
3799 mono_mb_emit_byte (mb, CEE_STLOC_1);
3801 mono_mb_emit_byte (mb, CEE_LDLOC_1);
3802 mono_mb_emit_byte (mb, CEE_BRFALSE);
3803 pos = mb->pos;
3804 mono_mb_emit_i4 (mb, 0);
3806 /* src = tmp_locals [i] */
3807 mono_mb_emit_ldloc (mb, conv_arg);
3808 mono_mb_emit_byte (mb, CEE_STLOC_0);
3810 /* emit valuetype conversion code */
3811 emit_struct_conv (mb, klass, TRUE);
3814 emit_struct_free (mb, klass, conv_arg);
3816 if (t->byref)
3817 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3818 break;
3820 case MARSHAL_ACTION_CONV_RESULT:
3821 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3822 klass->blittable) {
3823 mono_mb_emit_byte (mb, CEE_STLOC_3);
3824 break;
3826 /* load pointer to returned value type */
3827 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3828 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
3829 /* store the address of the source into local variable 0 */
3830 mono_mb_emit_byte (mb, CEE_STLOC_0);
3831 /* set dst_ptr */
3832 mono_mb_emit_ldloc_addr (mb, 3);
3833 mono_mb_emit_byte (mb, CEE_STLOC_1);
3835 /* emit valuetype conversion code */
3836 emit_struct_conv (mb, klass, TRUE);
3837 break;
3839 default:
3840 g_assert_not_reached ();
3843 return conv_arg;
3846 static int
3847 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
3848 MonoMarshalSpec *spec,
3849 int conv_arg, MonoType **conv_arg_type,
3850 MarshalAction action)
3852 MonoMethodBuilder *mb = m->mb;
3853 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
3854 MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
3856 switch (action) {
3857 case MARSHAL_ACTION_CONV_IN:
3858 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3859 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3861 if (t->byref) {
3862 if (t->attrs & PARAM_ATTRIBUTE_OUT)
3863 break;
3865 mono_mb_emit_ldarg (mb, argnum);
3866 mono_mb_emit_byte (mb, CEE_LDIND_I);
3867 } else {
3868 mono_mb_emit_ldarg (mb, argnum);
3871 if (conv == -1) {
3872 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
3873 MonoException *exc = mono_get_exception_not_implemented (msg);
3874 g_warning (msg);
3875 g_free (msg);
3876 mono_raise_exception (exc);
3878 else
3879 mono_mb_emit_icall (mb, conv_to_icall (conv));
3881 mono_mb_emit_stloc (mb, conv_arg);
3882 break;
3884 case MARSHAL_ACTION_CONV_OUT:
3885 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
3886 mono_mb_emit_ldarg (mb, argnum);
3887 mono_mb_emit_ldloc (mb, conv_arg);
3888 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
3889 mono_mb_emit_byte (mb, CEE_STIND_I);
3890 } else {
3891 if (mono_marshal_need_free (t, m->piinfo, spec)) {
3892 mono_mb_emit_ldloc (mb, conv_arg);
3893 mono_mb_emit_icall (mb, mono_marshal_free);
3896 break;
3898 case MARSHAL_ACTION_CONV_RESULT:
3899 mono_mb_emit_byte (mb, CEE_STLOC_0);
3900 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3902 if (spec) {
3903 switch (spec->native) {
3904 case MONO_NATIVE_LPWSTR:
3905 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPWSTR_STR));
3906 break;
3907 default:
3908 g_warning ("marshalling conversion not implemented");
3909 g_assert_not_reached ();
3911 } else {
3912 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
3914 mono_mb_emit_byte (mb, CEE_STLOC_3);
3916 /* free the string */
3917 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3918 mono_mb_emit_icall (mb, g_free);
3919 break;
3921 default:
3922 g_assert_not_reached ();
3925 return conv_arg;
3928 static int
3929 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
3930 MonoMarshalSpec *spec,
3931 int conv_arg, MonoType **conv_arg_type,
3932 MarshalAction action)
3934 MonoMethodBuilder *mb = m->mb;
3935 MonoClass *klass = t->data.klass;
3936 int pos, pos2, loc;
3938 switch (action) {
3939 case MARSHAL_ACTION_CONV_IN:
3940 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3941 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3943 m->orig_conv_args [argnum] = 0;
3945 if (klass->delegate) {
3946 g_assert (!t->byref);
3947 mono_mb_emit_ldarg (mb, argnum);
3948 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
3949 mono_mb_emit_stloc (mb, conv_arg);
3950 } else if (klass == mono_defaults.stringbuilder_class) {
3951 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
3952 MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
3954 g_assert (!t->byref);
3955 mono_mb_emit_ldarg (mb, argnum);
3957 if (conv != -1)
3958 mono_mb_emit_icall (mb, conv_to_icall (conv));
3959 else {
3960 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
3961 MonoException *exc = mono_get_exception_not_implemented (msg);
3962 g_warning (msg);
3963 g_free (msg);
3964 mono_raise_exception (exc);
3967 mono_mb_emit_stloc (mb, conv_arg);
3968 } else if (klass->blittable) {
3969 mono_mb_emit_ldarg (mb, argnum);
3970 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3971 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3972 mono_mb_emit_icon (mb, sizeof (MonoObject));
3973 mono_mb_emit_byte (mb, CEE_ADD);
3974 mono_mb_emit_stloc (mb, conv_arg);
3975 break;
3976 } else {
3977 mono_mb_emit_byte (mb, CEE_LDNULL);
3978 mono_mb_emit_stloc (mb, conv_arg);
3980 if (t->byref) {
3981 /* we dont need any conversions for out parameters */
3982 if (t->attrs & PARAM_ATTRIBUTE_OUT)
3983 break;
3985 mono_mb_emit_ldarg (mb, argnum);
3986 mono_mb_emit_byte (mb, CEE_LDIND_I);
3988 } else {
3989 mono_mb_emit_ldarg (mb, argnum);
3990 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3991 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3994 /* store the address of the source into local variable 0 */
3995 mono_mb_emit_byte (mb, CEE_STLOC_0);
3996 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3997 mono_mb_emit_byte (mb, CEE_BRFALSE);
3998 pos = mb->pos;
3999 mono_mb_emit_i4 (mb, 0);
4001 /* allocate space for the native struct and store the address */
4002 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
4003 mono_mb_emit_byte (mb, CEE_PREFIX1);
4004 mono_mb_emit_byte (mb, CEE_LOCALLOC);
4005 mono_mb_emit_stloc (mb, conv_arg);
4007 if (t->byref) {
4008 /* Need to store the original buffer so we can free it later */
4009 m->orig_conv_args [argnum] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4010 mono_mb_emit_ldloc (mb, conv_arg);
4011 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
4014 /* set the src_ptr */
4015 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4016 mono_mb_emit_icon (mb, sizeof (MonoObject));
4017 mono_mb_emit_byte (mb, CEE_ADD);
4018 mono_mb_emit_byte (mb, CEE_STLOC_0);
4020 /* set dst_ptr */
4021 mono_mb_emit_ldloc (mb, conv_arg);
4022 mono_mb_emit_byte (mb, CEE_STLOC_1);
4024 /* emit valuetype conversion code */
4025 emit_struct_conv (mb, klass, FALSE);
4027 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4029 break;
4031 case MARSHAL_ACTION_CONV_OUT:
4032 if (klass == mono_defaults.stringbuilder_class) {
4033 gboolean need_free;
4034 MonoMarshalNative encoding;
4035 MonoMarshalConv conv;
4037 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
4038 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
4040 g_assert (!t->byref);
4041 g_assert (encoding != -1);
4043 mono_mb_emit_ldarg (mb, argnum);
4044 mono_mb_emit_ldloc (mb, conv_arg);
4046 mono_mb_emit_icall (mb, conv_to_icall (conv));
4048 if (need_free) {
4049 mono_mb_emit_ldloc (mb, conv_arg);
4050 mono_mb_emit_icall (mb, mono_marshal_free);
4052 break;
4055 if (klass->delegate)
4056 break;
4058 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4059 /* allocate a new object */
4060 mono_mb_emit_ldarg (mb, argnum);
4061 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4062 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
4063 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
4064 mono_mb_emit_byte (mb, CEE_STIND_I);
4067 /* dst = *argument */
4068 mono_mb_emit_ldarg (mb, argnum);
4070 if (t->byref)
4071 mono_mb_emit_byte (mb, CEE_LDIND_I);
4073 mono_mb_emit_byte (mb, CEE_STLOC_1);
4075 mono_mb_emit_byte (mb, CEE_LDLOC_1);
4076 mono_mb_emit_byte (mb, CEE_BRFALSE);
4077 pos = mb->pos;
4078 mono_mb_emit_i4 (mb, 0);
4080 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4081 mono_mb_emit_byte (mb, CEE_LDLOC_1);
4082 mono_mb_emit_icon (mb, sizeof (MonoObject));
4083 mono_mb_emit_byte (mb, CEE_ADD);
4084 mono_mb_emit_byte (mb, CEE_STLOC_1);
4086 /* src = tmp_locals [i] */
4087 mono_mb_emit_ldloc (mb, conv_arg);
4088 mono_mb_emit_byte (mb, CEE_STLOC_0);
4090 /* emit valuetype conversion code */
4091 emit_struct_conv (mb, t->data.klass, TRUE);
4093 /* Free the structure returned by the native code */
4094 emit_struct_free (mb, klass, conv_arg);
4096 if (m->orig_conv_args [argnum]) {
4098 * If the native function changed the pointer, then free
4099 * the original structure plus the new pointer.
4101 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
4102 mono_mb_emit_ldloc (mb, conv_arg);
4103 mono_mb_emit_byte (mb, CEE_BEQ);
4104 pos2 = mb->pos;
4105 mono_mb_emit_i4 (mb, 0);
4107 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
4108 g_assert (m->orig_conv_args [argnum]);
4110 emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
4113 mono_mb_emit_ldloc (mb, conv_arg);
4114 mono_mb_emit_icall (mb, g_free);
4116 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
4119 else
4120 /* Free the original structure passed to native code */
4121 emit_struct_free (mb, klass, conv_arg);
4123 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4124 break;
4126 case MARSHAL_ACTION_CONV_RESULT:
4127 if (klass->delegate) {
4128 g_assert (!t->byref);
4129 mono_mb_emit_byte (mb, CEE_STLOC_0);
4130 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4131 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
4132 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4133 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4134 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
4135 mono_mb_emit_byte (mb, CEE_STLOC_3);
4136 } else {
4137 /* set src */
4138 mono_mb_emit_byte (mb, CEE_STLOC_0);
4140 /* Make a copy since emit_conv modifies local 0 */
4141 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4142 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4143 mono_mb_emit_stloc (mb, loc);
4145 mono_mb_emit_byte (mb, CEE_LDNULL);
4146 mono_mb_emit_byte (mb, CEE_STLOC_3);
4148 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4149 mono_mb_emit_byte (mb, CEE_BRFALSE);
4150 pos = mb->pos;
4151 mono_mb_emit_i4 (mb, 0);
4153 /* allocate result object */
4155 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4156 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);
4157 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4158 mono_mb_emit_byte (mb, CEE_STLOC_3);
4160 /* set dst */
4162 mono_mb_emit_byte (mb, CEE_LDLOC_3);
4163 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4164 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4165 mono_mb_emit_icon (mb, sizeof (MonoObject));
4166 mono_mb_emit_byte (mb, CEE_ADD);
4167 mono_mb_emit_byte (mb, CEE_STLOC_1);
4169 /* emit conversion code */
4170 emit_struct_conv (mb, klass, TRUE);
4172 emit_struct_free (mb, klass, loc);
4174 /* Free the pointer allocated by unmanaged code */
4175 mono_mb_emit_ldloc (mb, loc);
4176 mono_mb_emit_icall (mb, g_free);
4177 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4179 break;
4181 default:
4182 g_assert_not_reached ();
4185 return conv_arg;
4188 static int
4189 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
4190 MonoMarshalSpec *spec,
4191 int conv_arg, MonoType **conv_arg_type,
4192 MarshalAction action)
4194 MonoMethodBuilder *mb = m->mb;
4195 MonoClass *klass = mono_class_from_mono_type (t);
4196 gboolean need_convert, need_free;
4198 switch (action) {
4199 case MARSHAL_ACTION_CONV_IN:
4200 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4201 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4203 if (klass->element_class->blittable) {
4204 mono_mb_emit_ldarg (mb, argnum);
4205 if (t->byref)
4206 mono_mb_emit_byte (mb, CEE_LDIND_I);
4207 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
4208 mono_mb_emit_stloc (mb, conv_arg);
4210 else {
4211 MonoClass *eklass;
4212 guint32 label1, label2, label3;
4213 int index_var, src_var, dest_ptr, esize;
4214 MonoMarshalNative encoding;
4215 MonoMarshalConv conv;
4216 gboolean is_string = FALSE;
4218 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4220 eklass = klass->element_class;
4222 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
4223 if (eklass == mono_defaults.string_class) {
4224 is_string = TRUE;
4225 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
4227 else if (eklass == mono_defaults.stringbuilder_class) {
4228 is_string = TRUE;
4229 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
4231 else
4232 conv = -1;
4234 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4235 mono_mb_emit_ldarg (mb, argnum);
4236 if (t->byref)
4237 mono_mb_emit_byte (mb, CEE_LDIND_I);
4238 mono_mb_emit_stloc (mb, src_var);
4240 /* Check null */
4241 mono_mb_emit_ldloc (mb, src_var);
4242 mono_mb_emit_stloc (mb, conv_arg);
4243 mono_mb_emit_ldloc (mb, src_var);
4244 mono_mb_emit_byte (mb, CEE_BRFALSE);
4245 label1 = mb->pos;
4246 mono_mb_emit_i4 (mb, 0);
4248 if (is_string) {
4249 if (conv == -1) {
4250 char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
4251 MonoException *exc = mono_get_exception_not_implemented (msg);
4252 g_warning (msg);
4253 g_free (msg);
4254 mono_raise_exception (exc);
4258 if (is_string)
4259 esize = sizeof (gpointer);
4260 else
4261 esize = mono_class_native_size (eklass, NULL);
4263 /* allocate space for the native struct and store the address */
4264 mono_mb_emit_icon (mb, esize);
4265 mono_mb_emit_ldloc (mb, src_var);
4266 mono_mb_emit_byte (mb, CEE_LDLEN);
4268 if (eklass == mono_defaults.string_class) {
4269 /* Make the array bigger for the terminating null */
4270 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
4271 mono_mb_emit_byte (mb, CEE_ADD);
4273 mono_mb_emit_byte (mb, CEE_MUL);
4274 mono_mb_emit_byte (mb, CEE_PREFIX1);
4275 mono_mb_emit_byte (mb, CEE_LOCALLOC);
4276 mono_mb_emit_stloc (mb, conv_arg);
4278 mono_mb_emit_ldloc (mb, conv_arg);
4279 mono_mb_emit_stloc (mb, dest_ptr);
4281 /* Emit marshalling loop */
4282 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4283 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4284 mono_mb_emit_stloc (mb, index_var);
4285 label2 = mb->pos;
4286 mono_mb_emit_ldloc (mb, index_var);
4287 mono_mb_emit_ldloc (mb, src_var);
4288 mono_mb_emit_byte (mb, CEE_LDLEN);
4289 mono_mb_emit_byte (mb, CEE_BGE);
4290 label3 = mb->pos;
4291 mono_mb_emit_i4 (mb, 0);
4293 /* Emit marshalling code */
4295 if (is_string) {
4296 mono_mb_emit_ldloc (mb, dest_ptr);
4297 mono_mb_emit_ldloc (mb, src_var);
4298 mono_mb_emit_ldloc (mb, index_var);
4299 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4300 mono_mb_emit_icall (mb, conv_to_icall (conv));
4301 mono_mb_emit_byte (mb, CEE_STIND_I);
4303 else {
4304 /* set the src_ptr */
4305 mono_mb_emit_ldloc (mb, src_var);
4306 mono_mb_emit_ldloc (mb, index_var);
4307 mono_mb_emit_byte (mb, CEE_LDELEMA);
4308 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
4309 mono_mb_emit_byte (mb, CEE_STLOC_0);
4311 /* set dst_ptr */
4312 mono_mb_emit_ldloc (mb, dest_ptr);
4313 mono_mb_emit_byte (mb, CEE_STLOC_1);
4315 /* emit valuetype conversion code */
4316 emit_struct_conv (mb, eklass, FALSE);
4319 mono_mb_emit_add_to_local (mb, index_var, 1);
4320 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
4322 mono_mb_emit_byte (mb, CEE_BR);
4323 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
4325 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
4327 if (eklass == mono_defaults.string_class) {
4328 /* Null terminate */
4329 mono_mb_emit_ldloc (mb, dest_ptr);
4330 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4331 mono_mb_emit_byte (mb, CEE_STIND_REF);
4334 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
4337 break;
4339 case MARSHAL_ACTION_CONV_OUT:
4340 /* Character arrays are implicitly marshalled as [Out] */
4341 need_convert = (klass->element_class == mono_defaults.char_class) || (klass->element_class == mono_defaults.stringbuilder_class) || (t->attrs & PARAM_ATTRIBUTE_OUT);
4342 need_free = mono_marshal_need_free (&klass->element_class->byval_arg,
4343 m->piinfo, spec);
4345 if (need_convert || need_free) {
4346 /* FIXME: Optimize blittable case */
4347 MonoClass *eklass;
4348 guint32 label1, label2, label3;
4349 int index_var, src_ptr, loc, esize;
4351 eklass = klass->element_class;
4352 if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
4353 esize = sizeof (gpointer);
4354 else
4355 esize = mono_class_native_size (eklass, NULL);
4356 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4357 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4359 /* Check null */
4360 mono_mb_emit_ldarg (mb, argnum);
4361 if (t->byref)
4362 mono_mb_emit_byte (mb, CEE_LDIND_I);
4363 mono_mb_emit_byte (mb, CEE_BRFALSE);
4364 label1 = mb->pos;
4365 mono_mb_emit_i4 (mb, 0);
4367 mono_mb_emit_ldloc (mb, conv_arg);
4368 mono_mb_emit_stloc (mb, src_ptr);
4370 /* Emit marshalling loop */
4371 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4372 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4373 mono_mb_emit_stloc (mb, index_var);
4374 label2 = mb->pos;
4375 mono_mb_emit_ldloc (mb, index_var);
4376 mono_mb_emit_ldarg (mb, argnum);
4377 if (t->byref)
4378 mono_mb_emit_byte (mb, CEE_LDIND_I);
4379 mono_mb_emit_byte (mb, CEE_LDLEN);
4380 mono_mb_emit_byte (mb, CEE_BGE);
4381 label3 = mb->pos;
4382 mono_mb_emit_i4 (mb, 0);
4384 /* Emit marshalling code */
4386 if (eklass == mono_defaults.stringbuilder_class) {
4387 gboolean need_free2;
4388 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
4390 g_assert (conv != -1);
4392 /* dest */
4393 mono_mb_emit_ldarg (mb, argnum);
4394 if (t->byref)
4395 mono_mb_emit_byte (mb, CEE_LDIND_I);
4396 mono_mb_emit_ldloc (mb, index_var);
4397 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4399 /* src */
4400 mono_mb_emit_ldloc (mb, src_ptr);
4401 mono_mb_emit_byte (mb, CEE_LDIND_I);
4403 mono_mb_emit_icall (mb, conv_to_icall (conv));
4405 if (need_free) {
4406 /* src */
4407 mono_mb_emit_ldloc (mb, src_ptr);
4408 mono_mb_emit_byte (mb, CEE_LDIND_I);
4410 mono_mb_emit_icall (mb, mono_marshal_free);
4413 else if (eklass == mono_defaults.string_class) {
4414 if (need_free) {
4415 /* src */
4416 mono_mb_emit_ldloc (mb, src_ptr);
4417 mono_mb_emit_byte (mb, CEE_LDIND_I);
4419 mono_mb_emit_icall (mb, mono_marshal_free);
4422 else {
4423 if (need_convert) {
4424 /* set the src_ptr */
4425 mono_mb_emit_ldloc (mb, src_ptr);
4426 mono_mb_emit_byte (mb, CEE_STLOC_0);
4428 /* set dst_ptr */
4429 mono_mb_emit_ldarg (mb, argnum);
4430 if (t->byref)
4431 mono_mb_emit_byte (mb, CEE_LDIND_I);
4432 mono_mb_emit_ldloc (mb, index_var);
4433 mono_mb_emit_byte (mb, CEE_LDELEMA);
4434 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
4435 mono_mb_emit_byte (mb, CEE_STLOC_1);
4437 /* emit valuetype conversion code */
4438 emit_struct_conv (mb, eklass, TRUE);
4441 if (need_free) {
4442 mono_mb_emit_ldloc (mb, src_ptr);
4443 mono_mb_emit_stloc (mb, loc);
4444 mono_mb_emit_ldloc (mb, loc);
4446 emit_struct_free (mb, eklass, loc);
4450 mono_mb_emit_add_to_local (mb, index_var, 1);
4451 mono_mb_emit_add_to_local (mb, src_ptr, esize);
4453 mono_mb_emit_byte (mb, CEE_BR);
4454 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
4456 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
4457 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
4459 break;
4461 case MARSHAL_ACTION_CONV_RESULT:
4462 /* fixme: we need conversions here */
4463 mono_mb_emit_byte (mb, CEE_STLOC_3);
4465 default:
4466 g_assert_not_reached ();
4469 return conv_arg;
4472 static int
4473 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
4474 MonoMarshalSpec *spec,
4475 int conv_arg, MonoType **conv_arg_type,
4476 MarshalAction action)
4478 MonoMethodBuilder *mb = m->mb;
4480 switch (action) {
4481 case MARSHAL_ACTION_CONV_IN: {
4482 MonoType *local_type;
4483 int variant_bool = 0;
4484 if (!t->byref)
4485 break;
4486 if (spec == NULL) {
4487 local_type = &mono_defaults.int32_class->byval_arg;
4488 } else {
4489 switch (spec->native) {
4490 case MONO_NATIVE_I1:
4491 local_type = &mono_defaults.byte_class->byval_arg;
4492 break;
4493 case MONO_NATIVE_VARIANTBOOL:
4494 local_type = &mono_defaults.int16_class->byval_arg;
4495 variant_bool = 1;
4496 break;
4497 default:
4498 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
4499 local_type = &mono_defaults.int32_class->byval_arg;
4500 break;
4503 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4504 conv_arg = mono_mb_add_local (mb, local_type);
4505 mono_mb_emit_ldarg (mb, argnum);
4506 mono_mb_emit_byte (mb, CEE_LDIND_I1);
4507 if (variant_bool)
4508 mono_mb_emit_byte (mb, CEE_NEG);
4509 mono_mb_emit_stloc (mb, conv_arg);
4510 break;
4513 case MARSHAL_ACTION_CONV_RESULT:
4514 /* maybe we need to make sure that it fits within 8 bits */
4515 mono_mb_emit_byte (mb, CEE_STLOC_3);
4516 break;
4518 default:
4519 g_assert_not_reached ();
4522 return conv_arg;
4525 static int
4526 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
4527 MonoMarshalSpec *spec, int conv_arg,
4528 MonoType **conv_arg_type, MarshalAction action)
4530 /* Ensure that we have marshalling info for this param */
4531 mono_marshal_load_type_info (mono_class_from_mono_type (t));
4533 if (spec && spec->native == MONO_NATIVE_CUSTOM)
4534 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4536 if (spec && spec->native == MONO_NATIVE_ASANY)
4537 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4539 switch (t->type) {
4540 case MONO_TYPE_VALUETYPE:
4541 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4542 case MONO_TYPE_STRING:
4543 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4544 case MONO_TYPE_CLASS:
4545 case MONO_TYPE_OBJECT:
4546 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4547 case MONO_TYPE_ARRAY:
4548 case MONO_TYPE_SZARRAY:
4549 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4550 case MONO_TYPE_BOOLEAN:
4551 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4554 return conv_arg;
4558 * mono_marshal_get_native_wrapper:
4559 * @method: The MonoMethod to wrap.
4561 * generates IL code for the pinvoke wrapper (the generated method
4562 * calls the unmanaged code in method->addr)
4564 MonoMethod *
4565 mono_marshal_get_native_wrapper (MonoMethod *method)
4567 EmitMarshalContext m;
4568 MonoMethodSignature *sig, *csig;
4569 MonoMethodPInvoke *piinfo;
4570 MonoMethodBuilder *mb;
4571 MonoMarshalSpec **mspecs;
4572 MonoMethod *res;
4573 GHashTable *cache;
4574 MonoClass *klass;
4575 gboolean pinvoke = FALSE;
4576 int i, argnum, *tmp_locals;
4577 int type;
4578 const char *exc_class = "MissingMethodException";
4579 const char *exc_arg = NULL;
4581 g_assert (method != NULL);
4582 g_assert (method->signature->pinvoke);
4584 cache = method->klass->image->native_wrapper_cache;
4585 if ((res = mono_marshal_find_in_cache (cache, method)))
4586 return res;
4588 sig = method->signature;
4590 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
4591 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
4592 pinvoke = TRUE;
4594 if (!method->addr) {
4595 if (pinvoke)
4596 mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
4597 else
4598 method->addr = mono_lookup_internal_call (method);
4601 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
4603 mb->method->save_lmf = 1;
4605 piinfo = (MonoMethodPInvoke *)method;
4607 if (!method->addr) {
4608 mono_mb_emit_exception (mb, exc_class, exc_arg);
4609 csig = mono_metadata_signature_dup (sig);
4610 csig->pinvoke = 0;
4611 res = mono_mb_create_and_cache (cache, method,
4612 mb, csig, csig->param_count + 16);
4613 mono_mb_free (mb);
4614 return res;
4617 m.mb = mb;
4618 m.piinfo = piinfo;
4620 /* internal calls: we simply push all arguments and call the method (no conversions) */
4621 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
4623 /* hack - string constructors returns a value */
4624 if (method->string_ctor) {
4625 csig = mono_metadata_signature_dup (sig);
4626 csig->ret = &mono_defaults.string_class->byval_arg;
4627 } else
4628 csig = sig;
4630 if (sig->hasthis)
4631 mono_mb_emit_byte (mb, CEE_LDARG_0);
4633 for (i = 0; i < sig->param_count; i++)
4634 mono_mb_emit_ldarg (mb, i + sig->hasthis);
4636 g_assert (method->addr);
4637 mono_mb_emit_native_call (mb, csig, method->addr);
4638 emit_thread_interrupt_checkpoint (mb);
4639 mono_mb_emit_byte (mb, CEE_RET);
4641 csig = mono_metadata_signature_dup (csig);
4642 csig->pinvoke = 0;
4643 res = mono_mb_create_and_cache (cache, method,
4644 mb, csig, csig->param_count + 16);
4645 mono_mb_free (mb);
4646 return res;
4649 g_assert (pinvoke);
4651 mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
4652 mono_method_get_marshal_info (method, mspecs);
4654 /* pinvoke: we need to convert the arguments if necessary */
4656 /* we copy the signature, so that we can set pinvoke to 0 */
4657 csig = mono_metadata_signature_dup (sig);
4658 csig->pinvoke = 1;
4660 /* we allocate local for use with emit_struct_conv() */
4661 /* allocate local 0 (pointer) src_ptr */
4662 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4663 /* allocate local 1 (pointer) dst_ptr */
4664 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4665 /* allocate local 2 (boolean) delete_old */
4666 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
4668 /* delete_old = FALSE */
4669 mono_mb_emit_icon (mb, 0);
4670 mono_mb_emit_byte (mb, CEE_STLOC_2);
4672 if (!MONO_TYPE_IS_VOID(sig->ret)) {
4673 /* allocate local 3 to store the return value */
4674 mono_mb_add_local (mb, sig->ret);
4677 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
4678 /* Return type custom marshaling */
4680 * Since we can't determine the return type of the unmanaged function,
4681 * we assume it returns a pointer, and pass that pointer to
4682 * MarshalNativeToManaged.
4684 csig->ret = &mono_defaults.int_class->byval_arg;
4687 /* we first do all conversions */
4688 tmp_locals = alloca (sizeof (int) * sig->param_count);
4689 m.orig_conv_args = alloca (sizeof (int) * (sig->param_count + 1));
4691 for (i = 0; i < sig->param_count; i ++) {
4692 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
4695 /* push all arguments */
4697 if (sig->hasthis)
4698 mono_mb_emit_byte (mb, CEE_LDARG_0);
4700 for (i = 0; i < sig->param_count; i++) {
4701 MonoType *t = sig->params [i];
4702 MonoMarshalSpec *spec = mspecs [i + 1];
4704 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY)))
4705 emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
4706 else {
4707 argnum = i + sig->hasthis;
4709 switch (t->type) {
4710 case MONO_TYPE_BOOLEAN:
4711 if (t->byref) {
4712 g_assert (tmp_locals [i]);
4713 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
4714 } else
4715 mono_mb_emit_ldarg (mb, argnum);
4716 break;
4717 case MONO_TYPE_I1:
4718 case MONO_TYPE_U1:
4719 case MONO_TYPE_I2:
4720 case MONO_TYPE_U2:
4721 case MONO_TYPE_I4:
4722 case MONO_TYPE_U4:
4723 case MONO_TYPE_I:
4724 case MONO_TYPE_U:
4725 case MONO_TYPE_PTR:
4726 case MONO_TYPE_R4:
4727 case MONO_TYPE_R8:
4728 case MONO_TYPE_I8:
4729 case MONO_TYPE_U8:
4730 mono_mb_emit_ldarg (mb, argnum);
4731 break;
4732 case MONO_TYPE_VALUETYPE:
4733 emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
4734 break;
4735 case MONO_TYPE_STRING:
4736 case MONO_TYPE_CLASS:
4737 case MONO_TYPE_OBJECT:
4738 case MONO_TYPE_ARRAY:
4739 case MONO_TYPE_SZARRAY:
4740 g_assert (tmp_locals [i]);
4741 if (t->byref)
4742 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
4743 else
4744 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4745 break;
4746 case MONO_TYPE_CHAR:
4747 /* fixme: dont know how to marshal that. We cant simply
4748 * convert it to a one byte UTF8 character, because an
4749 * unicode character may need more that one byte in UTF8 */
4750 mono_mb_emit_ldarg (mb, argnum);
4751 break;
4752 case MONO_TYPE_TYPEDBYREF:
4753 case MONO_TYPE_FNPTR:
4754 default:
4755 g_warning ("type 0x%02x unknown", t->type);
4756 g_assert_not_reached ();
4761 /* call the native method */
4762 mono_mb_emit_native_call (mb, csig, method->addr);
4764 /* Set LastError if needed */
4765 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
4766 MonoMethodSignature *lasterr_sig;
4768 lasterr_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4769 lasterr_sig->ret = &mono_defaults.void_class->byval_arg;
4770 lasterr_sig->pinvoke = 1;
4772 mono_mb_emit_native_call (mb, lasterr_sig, mono_marshal_set_last_error);
4775 /* convert the result */
4776 if (!sig->ret->byref) {
4777 MonoMarshalSpec *spec = mspecs [0];
4778 type = sig->ret->type;
4780 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
4781 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4782 } else {
4784 handle_enum:
4785 switch (type) {
4786 case MONO_TYPE_VOID:
4787 break;
4788 case MONO_TYPE_I1:
4789 case MONO_TYPE_U1:
4790 case MONO_TYPE_I2:
4791 case MONO_TYPE_U2:
4792 case MONO_TYPE_I4:
4793 case MONO_TYPE_U4:
4794 case MONO_TYPE_I:
4795 case MONO_TYPE_U:
4796 case MONO_TYPE_PTR:
4797 case MONO_TYPE_R4:
4798 case MONO_TYPE_R8:
4799 case MONO_TYPE_I8:
4800 case MONO_TYPE_U8:
4801 /* no conversions necessary */
4802 mono_mb_emit_byte (mb, CEE_STLOC_3);
4803 break;
4804 case MONO_TYPE_VALUETYPE:
4805 klass = sig->ret->data.klass;
4806 if (klass->enumtype) {
4807 type = sig->ret->data.klass->enum_basetype->type;
4808 goto handle_enum;
4810 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4811 break;
4812 case MONO_TYPE_STRING:
4813 case MONO_TYPE_CLASS:
4814 case MONO_TYPE_OBJECT:
4815 case MONO_TYPE_BOOLEAN:
4816 case MONO_TYPE_ARRAY:
4817 case MONO_TYPE_SZARRAY:
4818 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4819 break;
4820 case MONO_TYPE_CHAR:
4821 /* fixme: we need conversions here */
4822 mono_mb_emit_byte (mb, CEE_STLOC_3);
4823 break;
4824 case MONO_TYPE_TYPEDBYREF:
4825 case MONO_TYPE_FNPTR:
4826 default:
4827 g_warning ("return type 0x%02x unknown", sig->ret->type);
4828 g_assert_not_reached ();
4831 } else {
4832 mono_mb_emit_byte (mb, CEE_STLOC_3);
4836 * Need to call this after converting the result since MONO_VTADDR needs
4837 * to be adjacent to the call instruction.
4839 emit_thread_interrupt_checkpoint (mb);
4841 /* we need to convert byref arguments back and free string arrays */
4842 for (i = 0; i < sig->param_count; i++) {
4843 MonoType *t = sig->params [i];
4844 MonoMarshalSpec *spec = mspecs [i + 1];
4846 argnum = i + sig->hasthis;
4848 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
4849 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
4850 continue;
4853 switch (t->type) {
4854 case MONO_TYPE_STRING:
4855 case MONO_TYPE_VALUETYPE:
4856 case MONO_TYPE_CLASS:
4857 case MONO_TYPE_OBJECT:
4858 case MONO_TYPE_SZARRAY:
4859 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
4860 break;
4861 case MONO_TYPE_BOOLEAN:
4862 if (!t->byref)
4863 continue;
4864 mono_mb_emit_ldarg (mb, argnum);
4865 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4866 if (mspecs [i + 1] != NULL && mspecs [i + 1]->native == MONO_NATIVE_VARIANTBOOL)
4867 mono_mb_emit_byte (mb, CEE_NEG);
4868 mono_mb_emit_byte (mb, CEE_STIND_I1);
4872 if (!MONO_TYPE_IS_VOID(sig->ret))
4873 mono_mb_emit_byte (mb, CEE_LDLOC_3);
4875 mono_mb_emit_byte (mb, CEE_RET);
4877 csig = mono_metadata_signature_dup (sig);
4878 csig->pinvoke = 0;
4879 res = mono_mb_create_and_cache (cache, method,
4880 mb, csig, csig->param_count + 16);
4881 mono_mb_free (mb);
4883 for (i = sig->param_count; i >= 0; i--)
4884 g_free (mspecs [i]);
4885 g_free (mspecs);
4887 /* 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)); */
4889 return res;
4892 void
4893 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
4895 static MonoReflectionType *
4896 type_from_handle (MonoType *handle)
4898 MonoDomain *domain = mono_domain_get ();
4899 MonoClass *klass = mono_class_from_mono_type (handle);
4901 MONO_ARCH_SAVE_REGS;
4903 mono_class_init (klass);
4904 return mono_type_get_object (domain, handle);
4908 * mono_marshal_get_isinst:
4909 * @klass: the type of the field
4911 * This method generates a function which can be used to check if an object is
4912 * an instance of the given type, icluding the case where the object is a proxy.
4913 * The generated function has the following signature:
4914 * MonoObject* __isinst_wrapper_ (MonoObject *obj)
4916 MonoMethod *
4917 mono_marshal_get_isinst (MonoClass *klass)
4919 static MonoMethodSignature *isint_sig = NULL;
4920 static GHashTable *isinst_hash = NULL;
4921 MonoMethod *res;
4922 int pos_was_ok, pos_failed, pos_end, pos_end2;
4923 char *name;
4924 MonoMethodBuilder *mb;
4926 EnterCriticalSection (&marshal_mutex);
4927 if (!isinst_hash)
4928 isinst_hash = g_hash_table_new (NULL, NULL);
4930 res = g_hash_table_lookup (isinst_hash, klass);
4931 LeaveCriticalSection (&marshal_mutex);
4932 if (res)
4933 return res;
4935 if (!isint_sig) {
4936 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4937 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
4938 isint_sig->ret = &mono_defaults.object_class->byval_arg;
4939 isint_sig->pinvoke = 0;
4942 name = g_strdup_printf ("__isinst_wrapper_%s", klass->name);
4943 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
4944 g_free (name);
4946 mb->method->save_lmf = 1;
4948 /* check if the object is a proxy that needs special cast */
4949 mono_mb_emit_ldarg (mb, 0);
4950 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4951 mono_mb_emit_byte (mb, CEE_MONO_CISINST);
4952 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4954 /* The result of MONO_ISINST can be:
4955 0) the type check succeeded
4956 1) the type check did not succeed
4957 2) a CanCastTo call is needed */
4959 mono_mb_emit_byte (mb, CEE_DUP);
4960 pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
4962 mono_mb_emit_byte (mb, CEE_LDC_I4_2);
4963 pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
4965 /* get the real proxy from the transparent proxy*/
4967 mono_mb_emit_ldarg (mb, 0);
4968 mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
4969 pos_end = mono_mb_emit_branch (mb, CEE_BR);
4971 /* fail */
4973 mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
4974 mono_mb_emit_byte (mb, CEE_LDNULL);
4975 pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
4977 /* success */
4979 mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
4980 mono_mb_emit_byte (mb, CEE_POP);
4981 mono_mb_emit_ldarg (mb, 0);
4983 /* the end */
4985 mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
4986 mono_mb_patch_addr (mb, pos_end2, mb->pos - (pos_end2 + 4));
4987 mono_mb_emit_byte (mb, CEE_RET);
4989 res = mono_mb_create_and_cache (isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
4990 mono_mb_free (mb);
4992 return res;
4996 * mono_marshal_get_castclass:
4997 * @klass: the type of the field
4999 * This method generates a function which can be used to cast an object to
5000 * an instance of the given type, icluding the case where the object is a proxy.
5001 * The generated function has the following signature:
5002 * MonoObject* __castclass_wrapper_ (MonoObject *obj)
5004 MonoMethod *
5005 mono_marshal_get_castclass (MonoClass *klass)
5007 static MonoMethodSignature *castclass_sig = NULL;
5008 static GHashTable *castclass_hash = NULL;
5009 MonoMethod *res;
5010 int pos_was_ok, pos_was_ok2;
5011 char *name;
5012 MonoMethodBuilder *mb;
5014 EnterCriticalSection (&marshal_mutex);
5015 if (!castclass_hash)
5016 castclass_hash = g_hash_table_new (NULL, NULL);
5018 res = g_hash_table_lookup (castclass_hash, klass);
5019 LeaveCriticalSection (&marshal_mutex);
5020 if (res)
5021 return res;
5023 if (!castclass_sig) {
5024 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5025 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
5026 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
5027 castclass_sig->pinvoke = 0;
5030 name = g_strdup_printf ("__castclass_wrapper_%s", klass->name);
5031 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
5032 g_free (name);
5034 mb->method->save_lmf = 1;
5036 /* check if the object is a proxy that needs special cast */
5037 mono_mb_emit_ldarg (mb, 0);
5038 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5039 mono_mb_emit_byte (mb, CEE_MONO_CCASTCLASS);
5040 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
5042 /* The result of MONO_ISINST can be:
5043 0) the cast is valid
5044 1) cast of unknown proxy type
5045 or an exception if the cast is is invalid
5048 pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
5050 /* get the real proxy from the transparent proxy*/
5052 mono_mb_emit_ldarg (mb, 0);
5053 mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
5054 pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
5056 /* fail */
5057 mono_mb_emit_exception (mb, "InvalidCastException", NULL);
5059 /* success */
5060 mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
5061 mono_mb_patch_addr (mb, pos_was_ok2, mb->pos - (pos_was_ok2 + 4));
5062 mono_mb_emit_ldarg (mb, 0);
5064 /* the end */
5065 mono_mb_emit_byte (mb, CEE_RET);
5067 res = mono_mb_create_and_cache (castclass_hash, klass, mb, castclass_sig, castclass_sig->param_count + 16);
5068 mono_mb_free (mb);
5070 return res;
5073 MonoMethod *
5074 mono_marshal_get_proxy_cancast (MonoClass *klass)
5076 static MonoMethodSignature *from_handle_sig = NULL;
5077 static MonoMethodSignature *upgrade_proxy_sig = NULL;
5078 static MonoMethodSignature *isint_sig = NULL;
5079 static GHashTable *proxy_isinst_hash = NULL;
5080 MonoMethod *res;
5081 int pos_failed, pos_end;
5082 char *name;
5083 MonoMethod *can_cast_to;
5084 MonoMethodDesc *desc;
5085 MonoMethodBuilder *mb;
5087 EnterCriticalSection (&marshal_mutex);
5088 if (!proxy_isinst_hash)
5089 proxy_isinst_hash = g_hash_table_new (NULL, NULL);
5091 res = g_hash_table_lookup (proxy_isinst_hash, klass);
5092 LeaveCriticalSection (&marshal_mutex);
5093 if (res)
5094 return res;
5096 if (!isint_sig) {
5097 upgrade_proxy_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
5098 upgrade_proxy_sig->params [0] = &mono_defaults.object_class->byval_arg;
5099 upgrade_proxy_sig->params [1] = &mono_defaults.object_class->byval_arg;
5100 upgrade_proxy_sig->ret = &mono_defaults.void_class->byval_arg;
5101 upgrade_proxy_sig->pinvoke = 1;
5103 from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5104 from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
5105 from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
5107 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5108 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
5109 isint_sig->ret = &mono_defaults.object_class->byval_arg;
5110 isint_sig->pinvoke = 0;
5113 name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name);
5114 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
5115 g_free (name);
5117 mb->method->save_lmf = 1;
5119 /* get the real proxy from the transparent proxy*/
5120 mono_mb_emit_ldarg (mb, 0);
5121 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
5122 mono_mb_emit_byte (mb, CEE_LDIND_I);
5124 /* get the refletion type from the type handle */
5125 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5126 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
5127 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &klass->byval_arg));
5128 mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
5130 mono_mb_emit_ldarg (mb, 0);
5132 /* make the call to CanCastTo (type, ob) */
5133 desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
5134 can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
5135 g_assert (can_cast_to);
5136 mono_method_desc_free (desc);
5137 mono_mb_emit_byte (mb, CEE_CALLVIRT);
5138 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, can_cast_to));
5141 pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
5143 /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
5144 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5145 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
5146 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &klass->byval_arg));
5147 mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
5148 mono_mb_emit_ldarg (mb, 0);
5150 mono_mb_emit_native_call (mb, upgrade_proxy_sig, mono_upgrade_remote_class_wrapper);
5151 emit_thread_interrupt_checkpoint (mb);
5153 mono_mb_emit_ldarg (mb, 0);
5154 pos_end = mono_mb_emit_branch (mb, CEE_BR);
5156 /* fail */
5158 mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
5159 mono_mb_emit_byte (mb, CEE_LDNULL);
5161 /* the end */
5163 mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
5164 mono_mb_emit_byte (mb, CEE_RET);
5166 res = mono_mb_create_and_cache (proxy_isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
5167 mono_mb_free (mb);
5169 return res;
5172 void
5173 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
5175 MonoClass *klass;
5176 klass = mono_class_from_mono_type (rtype->type);
5177 mono_upgrade_remote_class (((MonoObject*)tproxy)->vtable->domain, tproxy->remote_class, klass);
5178 ((MonoObject*)tproxy)->vtable = tproxy->remote_class->vtable;
5182 * mono_marshal_get_struct_to_ptr:
5183 * @klass:
5185 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
5187 MonoMethod *
5188 mono_marshal_get_struct_to_ptr (MonoClass *klass)
5190 MonoMethodBuilder *mb;
5191 static MonoMethod *stoptr = NULL;
5192 MonoMethod *res;
5194 g_assert (klass != NULL);
5196 if (klass->str_to_ptr)
5197 return klass->str_to_ptr;
5199 if (!stoptr)
5200 stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
5201 g_assert (stoptr);
5203 mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
5205 if (klass->blittable) {
5206 mono_mb_emit_byte (mb, CEE_LDARG_1);
5207 mono_mb_emit_byte (mb, CEE_LDARG_0);
5208 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5209 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
5210 mono_mb_emit_byte (mb, CEE_PREFIX1);
5211 mono_mb_emit_byte (mb, CEE_CPBLK);
5212 } else {
5214 /* allocate local 0 (pointer) src_ptr */
5215 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5216 /* allocate local 1 (pointer) dst_ptr */
5217 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5218 /* allocate local 2 (boolean) delete_old */
5219 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
5220 mono_mb_emit_byte (mb, CEE_LDARG_2);
5221 mono_mb_emit_byte (mb, CEE_STLOC_2);
5223 /* initialize src_ptr to point to the start of object data */
5224 mono_mb_emit_byte (mb, CEE_LDARG_0);
5225 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5226 mono_mb_emit_byte (mb, CEE_STLOC_0);
5228 /* initialize dst_ptr */
5229 mono_mb_emit_byte (mb, CEE_LDARG_1);
5230 mono_mb_emit_byte (mb, CEE_STLOC_1);
5232 emit_struct_conv (mb, klass, FALSE);
5235 mono_mb_emit_byte (mb, CEE_RET);
5237 res = mono_mb_create_method (mb, stoptr->signature, 0);
5238 mono_mb_free (mb);
5240 klass->str_to_ptr = res;
5241 return res;
5245 * mono_marshal_get_ptr_to_struct:
5246 * @klass:
5248 * generates IL code for PtrToStructure (IntPtr src, object structure)
5250 MonoMethod *
5251 mono_marshal_get_ptr_to_struct (MonoClass *klass)
5253 MonoMethodBuilder *mb;
5254 static MonoMethod *ptostr = NULL;
5255 MonoMethod *res;
5257 g_assert (klass != NULL);
5259 if (klass->ptr_to_str)
5260 return klass->ptr_to_str;
5262 if (!ptostr)
5263 ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
5264 g_assert (ptostr);
5266 mb = mono_mb_new (klass, ptostr->name, MONO_WRAPPER_UNKNOWN);
5268 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
5269 mono_mb_emit_byte (mb, CEE_LDARG_1);
5270 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5271 mono_mb_emit_byte (mb, CEE_LDARG_0);
5272 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
5273 mono_mb_emit_byte (mb, CEE_PREFIX1);
5274 mono_mb_emit_byte (mb, CEE_CPBLK);
5275 } else {
5277 /* allocate local 0 (pointer) src_ptr */
5278 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5279 /* allocate local 1 (pointer) dst_ptr */
5280 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5282 /* initialize src_ptr to point to the start of object data */
5283 mono_mb_emit_byte (mb, CEE_LDARG_0);
5284 mono_mb_emit_byte (mb, CEE_STLOC_0);
5286 /* initialize dst_ptr */
5287 mono_mb_emit_byte (mb, CEE_LDARG_1);
5288 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5289 mono_mb_emit_byte (mb, CEE_STLOC_1);
5291 emit_struct_conv (mb, klass, TRUE);
5294 mono_mb_emit_byte (mb, CEE_RET);
5296 res = mono_mb_create_method (mb, ptostr->signature, 0);
5297 mono_mb_free (mb);
5299 klass->ptr_to_str = res;
5300 return res;
5304 * generates IL code for the synchronized wrapper: the generated method
5305 * calls METHOD while locking 'this' or the parent type.
5307 MonoMethod *
5308 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
5310 static MonoMethodSignature *from_handle_sig = NULL;
5311 static MonoMethod *enter_method, *exit_method;
5312 MonoMethodSignature *sig;
5313 MonoExceptionClause *clause;
5314 MonoMethodHeader *header;
5315 MonoMethodBuilder *mb;
5316 MonoMethod *res;
5317 GHashTable *cache;
5318 int i, pos, this_local, ret_local = 0;
5320 g_assert (method);
5322 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
5323 return method;
5325 cache = method->klass->image->synchronized_cache;
5326 if ((res = mono_marshal_find_in_cache (cache, method)))
5327 return res;
5329 sig = method->signature;
5331 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
5333 /* result */
5334 if (!MONO_TYPE_IS_VOID (sig->ret))
5335 ret_local = mono_mb_add_local (mb, sig->ret);
5337 /* this */
5338 this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5340 clause = g_new0 (MonoExceptionClause, 1);
5341 clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
5343 if (!enter_method) {
5344 MonoMethodDesc *desc;
5346 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
5347 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
5348 g_assert (enter_method);
5349 mono_method_desc_free (desc);
5350 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
5351 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
5352 g_assert (exit_method);
5353 mono_method_desc_free (desc);
5356 * GetTypeFromHandle isn't called as a managed method because it has
5357 * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
5358 * transformed into something else by the JIT.
5360 from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5361 from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
5362 from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
5365 /* Push this or the type object */
5366 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
5367 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5368 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
5369 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &method->klass->byval_arg));
5370 mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
5372 else
5373 mono_mb_emit_ldarg (mb, 0);
5374 mono_mb_emit_stloc (mb, this_local);
5376 /* Call Monitor::Enter() */
5377 mono_mb_emit_ldloc (mb, this_local);
5378 mono_mb_emit_managed_call (mb, enter_method, NULL);
5380 clause->try_offset = mb->pos;
5382 /* Call the method */
5383 if (sig->hasthis)
5384 mono_mb_emit_ldarg (mb, 0);
5385 for (i = 0; i < sig->param_count; i++)
5386 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
5387 mono_mb_emit_managed_call (mb, method, method->signature);
5388 if (!MONO_TYPE_IS_VOID (sig->ret))
5389 mono_mb_emit_stloc (mb, ret_local);
5391 mono_mb_emit_byte (mb, CEE_LEAVE);
5392 pos = mb->pos;
5393 mono_mb_emit_i4 (mb, 0);
5395 clause->try_len = mb->pos - clause->try_offset;
5396 clause->handler_offset = mb->pos;
5398 /* Call Monitor::Exit() */
5399 mono_mb_emit_ldloc (mb, this_local);
5400 /* mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */
5401 mono_mb_emit_managed_call (mb, exit_method, NULL);
5402 mono_mb_emit_byte (mb, CEE_ENDFINALLY);
5404 clause->handler_len = mb->pos - clause->handler_offset;
5406 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5407 if (!MONO_TYPE_IS_VOID (sig->ret))
5408 mono_mb_emit_ldloc (mb, ret_local);
5409 mono_mb_emit_byte (mb, CEE_RET);
5411 res = mono_mb_create_and_cache (cache, method,
5412 mb, sig, sig->param_count + 16);
5413 mono_mb_free (mb);
5415 header = ((MonoMethodNormal *)res)->header;
5416 header->num_clauses = 1;
5417 header->clauses = clause;
5419 return res;
5422 MonoMethod*
5423 mono_marshal_get_stelemref ()
5425 static MonoMethod* ret = NULL;
5426 MonoMethodSignature *sig;
5427 MonoMethodBuilder *mb;
5429 guint32 b1, b2, b3, b4;
5430 guint32 copy_pos;
5431 int aklass, vklass;
5433 if (ret)
5434 return ret;
5436 mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
5439 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5441 /* void stelemref (void* array, int idx, void* value) */
5442 sig->ret = &mono_defaults.void_class->byval_arg;
5443 sig->params [0] = &mono_defaults.int_class->byval_arg;
5444 sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
5445 sig->params [2] = &mono_defaults.int_class->byval_arg;
5447 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5448 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5451 the method:
5452 <check ABC>
5453 if (!value)
5454 goto store;
5456 aklass = array->vtable->klass->element_class;
5457 vklass = value->vtable->klass;
5459 if (vklass->idepth < aklass->idepth)
5460 goto long;
5462 if (vklass->supertypes [aklass->idepth - 1] != aklass)
5463 goto long;
5465 store:
5466 array [idx] = value;
5467 return;
5469 long:
5470 if (mono_object_isinst (value, aklass))
5471 goto store;
5473 throw new ArrayTypeMismatchException ();
5476 /* ABC */
5477 mono_mb_emit_ldarg (mb, 0);
5478 mono_mb_emit_ldarg (mb, 1);
5479 mono_mb_emit_byte (mb, CEE_LDELEMA);
5480 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.int_class));
5481 mono_mb_emit_byte (mb, CEE_POP);
5483 /* if (!value) goto do_store */
5484 mono_mb_emit_ldarg (mb, 2);
5485 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5487 /* aklass = array->vtable->klass->element_class */
5488 mono_mb_emit_ldarg (mb, 0);
5489 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
5490 mono_mb_emit_byte (mb, CEE_LDIND_I);
5491 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
5492 mono_mb_emit_byte (mb, CEE_LDIND_I);
5493 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
5494 mono_mb_emit_byte (mb, CEE_LDIND_I);
5495 mono_mb_emit_stloc (mb, aklass);
5497 /* vklass = value->vtable->klass */
5498 mono_mb_emit_ldarg (mb, 2);
5499 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
5500 mono_mb_emit_byte (mb, CEE_LDIND_I);
5501 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
5502 mono_mb_emit_byte (mb, CEE_LDIND_I);
5503 mono_mb_emit_stloc (mb, vklass);
5505 /* if (vklass->idepth < aklass->idepth) goto failue */
5506 mono_mb_emit_ldloc (mb, vklass);
5507 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5508 mono_mb_emit_byte (mb, CEE_LDIND_I4);
5510 mono_mb_emit_ldloc (mb, aklass);
5511 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5512 mono_mb_emit_byte (mb, CEE_LDIND_I4);
5514 b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
5516 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
5517 mono_mb_emit_ldloc (mb, vklass);
5518 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
5519 mono_mb_emit_byte (mb, CEE_LDIND_I);
5521 mono_mb_emit_ldloc (mb, aklass);
5522 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5523 mono_mb_emit_byte (mb, CEE_LDIND_I4);
5524 mono_mb_emit_icon (mb, 1);
5525 mono_mb_emit_byte (mb, CEE_SUB);
5526 mono_mb_emit_icon (mb, sizeof (void*));
5527 mono_mb_emit_byte (mb, CEE_MUL);
5528 mono_mb_emit_byte (mb, CEE_ADD);
5529 mono_mb_emit_byte (mb, CEE_LDIND_I);
5531 mono_mb_emit_ldloc (mb, aklass);
5533 b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
5535 copy_pos = mb->pos;
5536 /* do_store */
5537 mono_mb_patch_addr (mb, b1, mb->pos - (b1 + 4));
5538 mono_mb_emit_ldarg (mb, 0);
5539 mono_mb_emit_ldarg (mb, 1);
5540 mono_mb_emit_ldarg (mb, 2);
5541 mono_mb_emit_byte (mb, CEE_STELEM_I);
5543 mono_mb_emit_byte (mb, CEE_RET);
5545 /* the hard way */
5546 mono_mb_patch_addr (mb, b2, mb->pos - (b2 + 4));
5547 mono_mb_patch_addr (mb, b3, mb->pos - (b3 + 4));
5549 mono_mb_emit_ldarg (mb, 2);
5550 mono_mb_emit_ldloc (mb, aklass);
5551 mono_mb_emit_icall (mb, mono_object_isinst);
5553 b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
5554 mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
5555 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
5557 mono_mb_emit_byte (mb, CEE_RET);
5558 ret = mono_mb_create_method (mb, sig, 4);
5559 mono_mb_free (mb);
5560 return ret;
5563 void*
5564 mono_marshal_alloc (gulong size)
5566 gpointer res;
5568 #ifdef PLATFORM_WIN32
5569 res = CoTaskMemAlloc (size);
5570 #else
5571 res = g_try_malloc ((gulong)size);
5572 if (!res)
5573 mono_gc_out_of_memory ((gulong)size);
5574 #endif
5575 return res;
5578 void
5579 mono_marshal_free (gpointer ptr)
5581 #ifdef PLATFORM_WIN32
5582 CoTaskMemFree (ptr);
5583 #else
5584 g_free (ptr);
5585 #endif
5588 void
5589 mono_marshal_free_array (gpointer *ptr, int size)
5591 int i;
5593 if (!ptr)
5594 return;
5596 for (i = 0; i < size; i++)
5597 if (ptr [i])
5598 g_free (ptr [i]);
5601 void *
5602 mono_marshal_realloc (gpointer ptr, gpointer size)
5604 MONO_ARCH_SAVE_REGS;
5606 return g_try_realloc (ptr, (gulong)size);
5609 void *
5610 mono_marshal_string_to_utf16 (MonoString *s)
5612 return s ? mono_string_chars (s) : NULL;
5616 * mono_marshal_set_last_error:
5618 * This function is invoked to set the last error value from a P/Invoke call
5619 * which has SetLastError set.
5621 void
5622 mono_marshal_set_last_error (void)
5624 #ifdef WIN32
5625 TlsSetValue (last_error_tls_id, (gpointer)GetLastError ());
5626 #else
5627 TlsSetValue (last_error_tls_id, (gpointer)errno);
5628 #endif
5631 void
5632 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
5633 gpointer dest, gint32 length)
5635 int element_size;
5636 void *source_addr;
5638 MONO_ARCH_SAVE_REGS;
5640 MONO_CHECK_ARG_NULL (src);
5641 MONO_CHECK_ARG_NULL (dest);
5643 g_assert (src->obj.vtable->klass->rank == 1);
5644 g_assert (start_index >= 0);
5645 g_assert (length >= 0);
5646 g_assert (start_index + length <= mono_array_length (src));
5648 element_size = mono_array_element_size (src->obj.vtable->klass);
5650 source_addr = mono_array_addr_with_size (src, element_size, start_index);
5652 memcpy (dest, source_addr, length * element_size);
5655 void
5656 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
5657 MonoArray *dest, gint32 length)
5659 int element_size;
5660 void *dest_addr;
5662 MONO_ARCH_SAVE_REGS;
5664 MONO_CHECK_ARG_NULL (src);
5665 MONO_CHECK_ARG_NULL (dest);
5667 g_assert (dest->obj.vtable->klass->rank == 1);
5668 g_assert (start_index >= 0);
5669 g_assert (length >= 0);
5670 g_assert (start_index + length <= mono_array_length (dest));
5672 element_size = mono_array_element_size (dest->obj.vtable->klass);
5674 dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
5676 memcpy (dest_addr, src, length * element_size);
5679 #if NO_UNALIGNED_ACCESS
5680 #define RETURN_UNALIGNED(type, addr) \
5682 type val; \
5683 memcpy(&val, p + offset, sizeof(val)); \
5684 return val; \
5686 #define WRITE_UNALIGNED(type, addr, val) \
5687 memcpy(addr, &val, sizeof(type))
5688 #else
5689 #define RETURN_UNALIGNED(type, addr) \
5690 return *(type*)(p + offset);
5691 #define WRITE_UNALIGNED(type, addr, val) \
5692 (*(type *)(addr) = (val))
5693 #endif
5695 gpointer
5696 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
5698 char *p = ptr;
5700 MONO_ARCH_SAVE_REGS;
5702 RETURN_UNALIGNED(gpointer, p + offset);
5705 unsigned char
5706 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
5708 char *p = ptr;
5710 MONO_ARCH_SAVE_REGS;
5712 return *(unsigned char*)(p + offset);
5715 gint16
5716 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
5718 char *p = ptr;
5720 MONO_ARCH_SAVE_REGS;
5722 RETURN_UNALIGNED(gint16, p + offset);
5725 gint32
5726 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
5728 char *p = ptr;
5730 MONO_ARCH_SAVE_REGS;
5732 RETURN_UNALIGNED(gint32, p + offset);
5735 gint64
5736 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
5738 char *p = ptr;
5740 MONO_ARCH_SAVE_REGS;
5742 RETURN_UNALIGNED(gint64, p + offset);
5745 void
5746 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
5748 char *p = ptr;
5750 MONO_ARCH_SAVE_REGS;
5752 *(unsigned char*)(p + offset) = val;
5755 void
5756 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
5758 char *p = ptr;
5760 MONO_ARCH_SAVE_REGS;
5762 WRITE_UNALIGNED(gpointer, p + offset, val);
5765 void
5766 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
5768 char *p = ptr;
5770 MONO_ARCH_SAVE_REGS;
5772 WRITE_UNALIGNED(gint16, p + offset, val);
5775 void
5776 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
5778 char *p = ptr;
5780 MONO_ARCH_SAVE_REGS;
5782 WRITE_UNALIGNED(gint32, p + offset, val);
5785 void
5786 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
5788 char *p = ptr;
5790 MONO_ARCH_SAVE_REGS;
5792 WRITE_UNALIGNED(gint64, p + offset, val);
5795 MonoString *
5796 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
5798 MONO_ARCH_SAVE_REGS;
5800 if (ptr == NULL)
5801 return mono_string_new (mono_domain_get (), "");
5802 else
5803 return mono_string_new (mono_domain_get (), ptr);
5806 MonoString *
5807 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
5809 MONO_ARCH_SAVE_REGS;
5811 if (ptr == NULL)
5812 return mono_string_new (mono_domain_get (), "");
5813 else
5814 return mono_string_new_len (mono_domain_get (), ptr, len);
5817 MonoString *
5818 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
5820 MonoDomain *domain = mono_domain_get ();
5821 int len = 0;
5822 guint16 *t = ptr;
5824 MONO_ARCH_SAVE_REGS;
5826 if (ptr == NULL)
5827 return mono_string_new (mono_domain_get (), "");
5829 while (*t++)
5830 len++;
5832 return mono_string_new_utf16 (domain, ptr, len);
5835 MonoString *
5836 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
5838 MonoDomain *domain = mono_domain_get ();
5840 MONO_ARCH_SAVE_REGS;
5842 if (ptr == NULL)
5843 return mono_string_new (mono_domain_get (), "");
5844 else
5845 return mono_string_new_utf16 (domain, ptr, len);
5848 MonoString *
5849 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
5851 MONO_ARCH_SAVE_REGS;
5853 g_warning ("PtrToStringBSTR not implemented");
5854 g_assert_not_reached ();
5856 return NULL;
5859 guint32
5860 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5862 MONO_ARCH_SAVE_REGS;
5864 return ((guint32)TlsGetValue (last_error_tls_id));
5867 guint32
5868 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
5870 MonoClass *klass;
5871 MonoType *type;
5872 guint32 layout;
5874 MONO_ARCH_SAVE_REGS;
5876 MONO_CHECK_ARG_NULL (rtype);
5878 type = rtype->type;
5879 klass = mono_class_from_mono_type (type);
5880 layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
5882 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5883 gchar *msg;
5884 MonoException *exc;
5886 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
5887 exc = mono_get_exception_argument ("t", msg);
5888 g_free (msg);
5889 mono_raise_exception (exc);
5893 return mono_class_native_size (klass, NULL);
5896 void
5897 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
5899 MonoMethod *method;
5900 gpointer pa [3];
5902 MONO_ARCH_SAVE_REGS;
5904 MONO_CHECK_ARG_NULL (obj);
5905 MONO_CHECK_ARG_NULL (dst);
5907 method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
5909 pa [0] = obj;
5910 pa [1] = &dst;
5911 pa [2] = &delete_old;
5913 mono_runtime_invoke (method, NULL, pa, NULL);
5916 void
5917 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
5919 MonoMethod *method;
5920 gpointer pa [2];
5922 MONO_ARCH_SAVE_REGS;
5924 MONO_CHECK_ARG_NULL (src);
5925 MONO_CHECK_ARG_NULL (dst);
5927 method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
5929 pa [0] = &src;
5930 pa [1] = dst;
5932 mono_runtime_invoke (method, NULL, pa, NULL);
5935 MonoObject *
5936 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
5938 MonoDomain *domain = mono_domain_get ();
5939 MonoObject *res;
5941 MONO_ARCH_SAVE_REGS;
5943 MONO_CHECK_ARG_NULL (src);
5944 MONO_CHECK_ARG_NULL (type);
5946 res = mono_object_new (domain, mono_class_from_mono_type (type->type));
5948 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res);
5950 return res;
5954 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
5956 MonoMarshalType *info;
5957 MonoClass *klass;
5958 char *fname;
5959 int i, match_index = -1;
5961 MONO_ARCH_SAVE_REGS;
5963 MONO_CHECK_ARG_NULL (type);
5964 MONO_CHECK_ARG_NULL (field_name);
5966 fname = mono_string_to_utf8 (field_name);
5967 klass = mono_class_from_mono_type (type->type);
5969 while (klass && match_index == -1) {
5970 for (i = 0; i < klass->field.count; ++i) {
5971 if (*fname == *klass->fields [i].name && strcmp (fname, klass->fields [i].name) == 0) {
5972 match_index = i;
5973 break;
5977 if (match_index == -1)
5978 klass = klass->parent;
5981 g_free (fname);
5983 if(match_index == -1) {
5984 MonoException* exc;
5985 gchar *tmp;
5987 /* Get back original class instance */
5988 klass = mono_class_from_mono_type (type->type);
5990 tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
5991 exc = mono_get_exception_argument ("fieldName", tmp);
5992 g_free (tmp);
5994 mono_raise_exception ((MonoException*)exc);
5997 info = mono_marshal_load_type_info (klass);
5998 return info->fields [match_index].offset;
6001 gpointer
6002 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
6004 MONO_ARCH_SAVE_REGS;
6006 return mono_string_to_utf8 (string);
6009 gpointer
6010 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
6012 MONO_ARCH_SAVE_REGS;
6014 if (string == NULL)
6015 return NULL;
6016 else
6017 return g_memdup (mono_string_chars (string), mono_string_length (string)*2);
6020 static void
6021 mono_struct_delete_old (MonoClass *klass, char *ptr)
6023 MonoMarshalType *info;
6024 int i;
6026 info = mono_marshal_load_type_info (klass);
6028 for (i = 0; i < info->num_fields; i++) {
6029 MonoMarshalNative ntype;
6030 MonoMarshalConv conv;
6031 MonoType *ftype = info->fields [i].field->type;
6032 char *cpos;
6034 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
6035 continue;
6037 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE,
6038 klass->unicode, &conv);
6040 cpos = ptr + info->fields [i].offset;
6042 switch (conv) {
6043 case MONO_MARSHAL_CONV_NONE:
6044 if (MONO_TYPE_ISSTRUCT (ftype)) {
6045 mono_struct_delete_old (ftype->data.klass, cpos);
6046 continue;
6048 break;
6049 case MONO_MARSHAL_CONV_STR_LPWSTR:
6050 case MONO_MARSHAL_CONV_STR_LPSTR:
6051 case MONO_MARSHAL_CONV_STR_LPTSTR:
6052 case MONO_MARSHAL_CONV_STR_BSTR:
6053 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
6054 case MONO_MARSHAL_CONV_STR_TBSTR:
6055 mono_marshal_free (*(gpointer *)cpos);
6056 break;
6057 default:
6058 continue;
6063 void
6064 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
6066 MonoClass *klass;
6068 MONO_ARCH_SAVE_REGS;
6070 MONO_CHECK_ARG_NULL (src);
6071 MONO_CHECK_ARG_NULL (type);
6073 klass = mono_class_from_mono_type (type->type);
6075 mono_struct_delete_old (klass, (char *)src);
6079 /* FIXME: on win32 we should probably use GlobalAlloc(). */
6080 void*
6081 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
6083 gpointer res;
6085 MONO_ARCH_SAVE_REGS;
6087 if ((gulong)size == 0)
6088 /* This returns a valid pointer for size 0 on MS.NET */
6089 size = 4;
6091 res = g_try_malloc ((gulong)size);
6092 if (!res)
6093 mono_gc_out_of_memory ((gulong)size);
6095 return res;
6098 void
6099 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
6101 MONO_ARCH_SAVE_REGS;
6103 g_free (ptr);
6106 void*
6107 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
6109 MONO_ARCH_SAVE_REGS;
6111 #ifdef PLATFORM_WIN32
6112 return CoTaskMemAlloc (size);
6113 #else
6114 return g_try_malloc ((gulong)size);
6115 #endif
6118 void
6119 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
6121 MONO_ARCH_SAVE_REGS;
6123 #ifdef PLATFORM_WIN32
6124 CoTaskMemFree (ptr);
6125 #else
6126 g_free (ptr);
6127 #endif
6130 void*
6131 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
6133 return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
6136 MonoDelegate*
6137 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type)
6139 return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn);
6142 MonoMarshalType *
6143 mono_marshal_load_type_info (MonoClass* klass)
6145 int i, j, count = 0, native_size = 0, min_align = 1;
6146 MonoMarshalType *info;
6147 guint32 layout;
6149 g_assert (klass != NULL);
6151 if (klass->marshal_info)
6152 return klass->marshal_info;
6154 if (!klass->inited)
6155 mono_class_init (klass);
6157 for (i = 0; i < klass->field.count; ++i) {
6158 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
6159 continue;
6160 if (mono_field_is_deleted (&klass->fields [i]))
6161 continue;
6162 count++;
6165 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
6167 klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
6168 info->num_fields = count;
6170 /* Try to find a size for this type in metadata */
6171 mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
6173 if (klass->parent) {
6174 int parent_size = mono_class_native_size (klass->parent, NULL);
6176 /* Add parent size to real size */
6177 native_size += parent_size;
6178 info->native_size = parent_size;
6181 for (j = i = 0; i < klass->field.count; ++i) {
6182 int size, align;
6184 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
6185 continue;
6187 if (mono_field_is_deleted (&klass->fields [i]))
6188 continue;
6189 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
6190 mono_metadata_field_info (klass->image, klass->field.first + i,
6191 NULL, NULL, &info->fields [j].mspec);
6193 info->fields [j].field = &klass->fields [i];
6195 if ((klass->field.count == 1) && (klass->instance_size == sizeof (MonoObject)) &&
6196 (strcmp (klass->fields [i].name, "$PRIVATE$") == 0)) {
6197 /* This field is a hack inserted by MCS to empty structures */
6198 continue;
6201 switch (layout) {
6202 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
6203 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
6204 size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec,
6205 &align, TRUE, klass->unicode);
6206 align = klass->packing_size ? MIN (klass->packing_size, align): align;
6207 min_align = MAX (align, min_align);
6208 info->fields [j].offset = info->native_size;
6209 info->fields [j].offset += align - 1;
6210 info->fields [j].offset &= ~(align - 1);
6211 info->native_size = info->fields [j].offset + size;
6212 break;
6213 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
6214 size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec,
6215 &align, TRUE, klass->unicode);
6216 align = klass->packing_size ? MIN (klass->packing_size, align): align;
6217 min_align = MAX (align, min_align);
6218 info->fields [j].offset = klass->fields [i].offset - sizeof (MonoObject);
6219 info->native_size = MAX (info->native_size, info->fields [j].offset + size);
6220 break;
6222 j++;
6225 if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
6226 info->native_size = MAX (native_size, info->native_size);
6229 if (info->native_size & (min_align - 1)) {
6230 info->native_size += min_align - 1;
6231 info->native_size &= ~(min_align - 1);
6234 /* Update the class's blittable info, if the layouts don't match */
6235 if (info->native_size != mono_class_value_size (klass, NULL))
6236 klass->blittable = FALSE;
6238 /* If this is an array type, ensure that we have element info */
6239 if (klass->element_class) {
6240 mono_marshal_load_type_info (klass->element_class);
6243 return klass->marshal_info;
6247 * mono_class_native_size:
6248 * @klass: a class
6250 * Returns: the native size of an object instance (when marshaled
6251 * to unmanaged code)
6253 gint32
6254 mono_class_native_size (MonoClass *klass, guint32 *align)
6257 if (!klass->marshal_info)
6258 mono_marshal_load_type_info (klass);
6260 if (align)
6261 *align = klass->min_align;
6263 return klass->marshal_info->native_size;
6267 * mono_type_native_stack_size:
6268 * @t: the type to return the size it uses on the stack
6270 * Returns: the number of bytes required to hold an instance of this
6271 * type on the native stack
6274 mono_type_native_stack_size (MonoType *t, gint *align)
6276 int tmp;
6278 g_assert (t != NULL);
6280 if (!align)
6281 align = &tmp;
6283 if (t->byref) {
6284 *align = 4;
6285 return 4;
6288 switch (t->type){
6289 case MONO_TYPE_BOOLEAN:
6290 case MONO_TYPE_CHAR:
6291 case MONO_TYPE_I1:
6292 case MONO_TYPE_U1:
6293 case MONO_TYPE_I2:
6294 case MONO_TYPE_U2:
6295 case MONO_TYPE_I4:
6296 case MONO_TYPE_U4:
6297 case MONO_TYPE_I:
6298 case MONO_TYPE_U:
6299 case MONO_TYPE_STRING:
6300 case MONO_TYPE_OBJECT:
6301 case MONO_TYPE_CLASS:
6302 case MONO_TYPE_SZARRAY:
6303 case MONO_TYPE_PTR:
6304 case MONO_TYPE_FNPTR:
6305 case MONO_TYPE_ARRAY:
6306 case MONO_TYPE_TYPEDBYREF:
6307 *align = 4;
6308 return 4;
6309 case MONO_TYPE_R4:
6310 *align = 4;
6311 return 4;
6312 case MONO_TYPE_I8:
6313 case MONO_TYPE_U8:
6314 case MONO_TYPE_R8:
6315 *align = 4;
6316 return 8;
6317 case MONO_TYPE_VALUETYPE: {
6318 guint32 size;
6320 if (t->data.klass->enumtype)
6321 return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
6322 else {
6323 size = mono_class_native_size (t->data.klass, align);
6324 *align = *align + 3;
6325 *align &= ~3;
6327 size += 3;
6328 size &= ~3;
6330 return size;
6333 default:
6334 g_error ("type 0x%02x unknown", t->type);
6336 return 0;
6339 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
6340 the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
6341 but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
6342 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
6344 gint32
6345 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align,
6346 gboolean as_field, gboolean unicode)
6348 MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
6349 MonoClass *klass;
6351 switch (native_type) {
6352 case MONO_NATIVE_BOOLEAN:
6353 *align = 4;
6354 return 4;
6355 case MONO_NATIVE_I1:
6356 case MONO_NATIVE_U1:
6357 *align = 1;
6358 return 1;
6359 case MONO_NATIVE_I2:
6360 case MONO_NATIVE_U2:
6361 case MONO_NATIVE_VARIANTBOOL:
6362 *align = 2;
6363 return 2;
6364 case MONO_NATIVE_I4:
6365 case MONO_NATIVE_U4:
6366 case MONO_NATIVE_ERROR:
6367 *align = 4;
6368 return 4;
6369 case MONO_NATIVE_I8:
6370 case MONO_NATIVE_U8:
6371 *align = ALIGNMENT(guint64);
6372 return 8;
6373 case MONO_NATIVE_R4:
6374 *align = 4;
6375 return 4;
6376 case MONO_NATIVE_R8:
6377 *align = ALIGNMENT(double);
6378 return 8;
6379 case MONO_NATIVE_INT:
6380 case MONO_NATIVE_UINT:
6381 case MONO_NATIVE_LPSTR:
6382 case MONO_NATIVE_LPWSTR:
6383 case MONO_NATIVE_LPTSTR:
6384 case MONO_NATIVE_BSTR:
6385 case MONO_NATIVE_ANSIBSTR:
6386 case MONO_NATIVE_TBSTR:
6387 case MONO_NATIVE_LPARRAY:
6388 case MONO_NATIVE_SAFEARRAY:
6389 case MONO_NATIVE_IUNKNOWN:
6390 case MONO_NATIVE_IDISPATCH:
6391 case MONO_NATIVE_INTERFACE:
6392 case MONO_NATIVE_ASANY:
6393 case MONO_NATIVE_FUNC:
6394 case MONO_NATIVE_LPSTRUCT:
6395 *align = ALIGNMENT(gpointer);
6396 return sizeof (gpointer);
6397 case MONO_NATIVE_STRUCT:
6398 klass = mono_class_from_mono_type (type);
6399 return mono_class_native_size (klass, align);
6400 case MONO_NATIVE_BYVALTSTR: {
6401 int esize = unicode ? 2: 1;
6402 g_assert (mspec);
6403 *align = esize;
6404 return mspec->data.array_data.num_elem * esize;
6406 case MONO_NATIVE_BYVALARRAY: {
6407 int esize;
6408 klass = mono_class_from_mono_type (type);
6409 esize = mono_class_native_size (klass->element_class, align);
6410 g_assert (mspec);
6411 return mspec->data.array_data.num_elem * esize;
6413 case MONO_NATIVE_CUSTOM:
6414 g_assert_not_reached ();
6415 break;
6416 case MONO_NATIVE_CURRENCY:
6417 case MONO_NATIVE_VBBYREFSTR:
6418 default:
6419 g_error ("native type %02x not implemented", native_type);
6420 break;
6422 g_assert_not_reached ();
6423 return 0;
6426 gpointer
6427 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding)
6429 MonoType *t;
6430 MonoClass *klass;
6432 if (o == NULL)
6433 return NULL;
6435 t = &o->vtable->klass->byval_arg;
6436 switch (t->type) {
6437 case MONO_TYPE_I4:
6438 case MONO_TYPE_U4:
6439 case MONO_TYPE_PTR:
6440 case MONO_TYPE_I1:
6441 case MONO_TYPE_U1:
6442 case MONO_TYPE_BOOLEAN:
6443 case MONO_TYPE_I2:
6444 case MONO_TYPE_U2:
6445 case MONO_TYPE_CHAR:
6446 case MONO_TYPE_I8:
6447 case MONO_TYPE_U8:
6448 case MONO_TYPE_R4:
6449 case MONO_TYPE_R8:
6450 return mono_object_unbox (o);
6451 break;
6452 case MONO_TYPE_STRING:
6453 switch (string_encoding) {
6454 case MONO_NATIVE_LPWSTR:
6455 return mono_string_to_utf16 ((MonoString*)o);
6456 break;
6457 case MONO_NATIVE_LPSTR:
6458 return mono_string_to_lpstr ((MonoString*)o);
6459 break;
6460 default:
6461 g_warning ("marshaling conversion %d not implemented", string_encoding);
6462 g_assert_not_reached ();
6464 break;
6465 case MONO_TYPE_CLASS:
6466 case MONO_TYPE_VALUETYPE: {
6467 MonoMethod *method;
6468 gpointer pa [3];
6469 gpointer res;
6470 MonoBoolean delete_old = FALSE;
6472 klass = t->data.klass;
6474 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
6475 break;
6477 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6478 klass->blittable || klass->enumtype)
6479 return mono_object_unbox (o);
6481 res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
6483 method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
6485 pa [0] = o;
6486 pa [1] = &res;
6487 pa [2] = &delete_old;
6489 mono_runtime_invoke (method, NULL, pa, NULL);
6491 return res;
6495 mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
6497 return NULL;
6500 void
6501 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding)
6503 MonoType *t;
6504 MonoClass *klass;
6506 if (o == NULL)
6507 return;
6509 t = &o->vtable->klass->byval_arg;
6510 switch (t->type) {
6511 case MONO_TYPE_STRING:
6512 switch (string_encoding) {
6513 case MONO_NATIVE_LPWSTR:
6514 case MONO_NATIVE_LPSTR:
6515 mono_marshal_free (ptr);
6516 break;
6517 default:
6518 g_warning ("marshaling conversion %d not implemented", string_encoding);
6519 g_assert_not_reached ();
6521 break;
6522 case MONO_TYPE_CLASS:
6523 case MONO_TYPE_VALUETYPE: {
6524 klass = t->data.klass;
6526 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6527 klass->blittable || klass->enumtype)
6528 break;
6530 mono_struct_delete_old (klass, ptr);
6532 mono_marshal_free (ptr);
6533 break;
6535 default:
6536 break;