2004-09-03 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / marshal.c
1 /*
2  * marshal.c: Routines for marshaling complex types in P/Invoke methods.
3  * 
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.  http://www.ximian.com
8  *
9  */
10
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/os/gc_wrapper.h>
26 #include <string.h>
27 #include <errno.h>
28
29 /* #define DEBUG_RUNTIME_CODE */
30
31 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
32         a = i,
33
34 enum {
35 #include "mono/cil/opcode.def"
36         LAST = 0xff
37 };
38 #undef OPDEF
39
40 struct _MonoMethodBuilder {
41         MonoMethod *method;
42         GList *locals_list;
43         int locals;
44         guint32 code_size, pos;
45         unsigned char *code;
46 };
47
48 static void
49 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
50
51 static MonoMethod *
52 mono_find_method_by_name (MonoClass *klass, const char *name, int param_count)
53 {
54         MonoMethod *res = NULL;
55         int i;
56
57         for (i = 0; i < klass->method.count; ++i) {
58                 if (klass->methods [i]->name[0] == name [0] && 
59                     !strcmp (name, klass->methods [i]->name) &&
60                     klass->methods [i]->signature->param_count == param_count) {
61                         res = klass->methods [i];
62                         break;
63                 }
64         }
65         return res;
66 }
67
68 #ifdef DEBUG_RUNTIME_CODE
69 static char*
70 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
71 {
72         return g_strdup (" ");
73 }
74
75 static MonoDisHelper marshal_dh = {
76         "\n",
77         "IL_%04x: ",
78         "IL_%04x",
79         indenter, 
80         NULL,
81         NULL
82 };
83 #endif 
84
85 /* This mutex protects the various marshalling related caches in MonoImage */
86 static CRITICAL_SECTION marshal_mutex;
87
88 /* Maps wrapper methods to the methods they wrap */
89 static MonoGHashTable *wrapper_hash;
90
91 static guint32 last_error_tls_id;
92
93 static void
94 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
95 {
96         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
97
98         mono_register_jit_icall (func, name, sig, save);
99 }
100
101 void
102 mono_marshal_init (void)
103 {
104         static gboolean module_initialized = FALSE;
105
106         if (!module_initialized) {
107                 module_initialized = TRUE;
108                 InitializeCriticalSection (&marshal_mutex);
109                 MONO_GC_REGISTER_ROOT (wrapper_hash);
110                 wrapper_hash = mono_g_hash_table_new (NULL, NULL);
111                 last_error_tls_id = TlsAlloc ();
112
113                 register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
114                 register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
115                 register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
116                 register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
117                 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
118                 register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
119                 register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
120                 register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
121                 register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
122                 register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
123                 register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
124                 register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
125                 register_icall (mono_marshal_string_array, "mono_marshal_string_array", "ptr object", FALSE);
126                 register_icall (mono_marshal_string_array_to_unicode, "mono_marshal_string_array_to_unicode", "ptr object", FALSE);
127                 register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32", FALSE);
128                 register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32", FALSE);
129                 register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
130                 register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
131                 register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
132                 register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
133                 register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
134                 register_icall (g_free, "g_free", "void ptr", FALSE);
135                 register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
136         }
137 }
138
139 gpointer
140 mono_delegate_to_ftnptr (MonoDelegate *delegate)
141 {
142         MonoMethod *method, *wrapper, *invoke;
143         MonoMarshalSpec **mspecs;
144         MonoClass *klass;
145         int i;
146
147         if (!delegate)
148                 return NULL;
149
150         if (delegate->delegate_trampoline)
151                 return delegate->delegate_trampoline;
152
153         klass = ((MonoObject *)delegate)->vtable->klass;
154         g_assert (klass->delegate);
155
156         method = delegate->method_info->method;
157         invoke = mono_find_method_by_name (klass, "Invoke", method->signature->param_count);
158
159         mspecs = g_new (MonoMarshalSpec*, invoke->signature->param_count + 1);
160         mono_method_get_marshal_info (invoke, mspecs);
161
162         wrapper = mono_marshal_get_managed_wrapper (method, delegate->target, mspecs);
163
164         for (i = invoke->signature->param_count; i >= 0; i--)
165                 if (mspecs [i])
166                         mono_metadata_free_marshal_spec (mspecs [i]);
167         g_free (mspecs);
168
169         delegate->delegate_trampoline =  mono_compile_method (wrapper);
170
171         return delegate->delegate_trampoline;
172 }
173
174 MonoDelegate*
175 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
176 {
177         MonoDelegate *d;
178         MonoJitInfo *ji;
179
180         d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
181
182         ji = mono_jit_info_table_find (mono_domain_get (), ftn);
183         if (ji == NULL)
184                 mono_raise_exception (mono_get_exception_argument ("", "Function pointer was not created by a Delegate."));
185
186         /* FIXME: discard the wrapper and call the original method */
187         mono_delegate_ctor ((MonoObject*)d, NULL, ftn);
188
189         return d;
190 }
191
192 void
193 mono_delegate_free_ftnptr (MonoDelegate *delegate)
194 {
195         MonoJitInfo *ji;
196         void *ptr, *ptr2;
197
198         ptr2 = delegate->delegate_trampoline;
199
200         ptr = InterlockedExchangePointer (&delegate->delegate_trampoline, NULL);
201         ji = mono_jit_info_table_find (mono_domain_get (), ptr);
202         g_assert (ji);
203
204         if (!delegate->target) {
205                 /* The wrapper method is shared between delegates -> no need to free it */
206                 return;
207         }
208
209         mono_runtime_free_method (ji->method);
210 }
211
212 gpointer
213 mono_array_to_savearray (MonoArray *array)
214 {
215         if (!array)
216                 return NULL;
217
218         g_assert_not_reached ();
219         return NULL;
220 }
221
222 gpointer
223 mono_array_to_lparray (MonoArray *array)
224 {
225         if (!array)
226                 return NULL;
227
228         /* fixme: maybe we need to make a copy */
229         return array->vector;
230 }
231
232 void
233 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
234 {
235         GError *error = NULL;
236         guint16 *ut;
237         glong items_written;
238         int l;
239
240         if (!sb || !text)
241                 return;
242
243         l = strlen (text);
244
245         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
246         
247         if (items_written > mono_stringbuilder_capacity (sb))
248                 items_written = mono_stringbuilder_capacity (sb);
249         
250         if (!error) {
251                 memcpy (mono_string_chars (sb->str), ut, items_written * 2);
252                 sb->length = items_written;
253         } else 
254                 g_error_free (error);
255
256         g_free (ut);
257 }
258
259 void
260 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
261 {
262         guint32 len;
263
264         if (!sb || !text)
265                 return;
266
267         g_assert (mono_string_chars (sb->str) == text);
268
269         for (len = 0; text [len] != 0; ++len)
270                 ;
271
272         sb->length = len;
273 }
274
275 gpointer
276 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
277 {
278         GError *error = NULL;
279         glong *res;
280         gchar *tmp;
281
282         if (!sb)
283                 return NULL;
284
285         res = g_malloc0 (mono_stringbuilder_capacity (sb) + 1);
286
287         tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error);
288         if (error) {
289                 g_error_free (error);
290                 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
291         }
292         else
293                 memcpy (res, tmp, sb->length + 1);
294
295         return res;
296 }
297
298 gpointer
299 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
300 {
301         if (!sb)
302                 return NULL;
303
304         return mono_string_chars (sb->str);
305 }
306
307 gpointer
308 mono_string_to_ansibstr (MonoString *string_obj)
309 {
310         g_error ("implement me");
311         return NULL;
312 }
313
314 gpointer
315 mono_string_to_bstr (MonoString *string_obj)
316 {
317         g_error ("implement me");
318         return NULL;
319 }
320
321 void
322 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
323 {
324         char *s;
325         int len;
326
327         g_assert (dst != NULL);
328         g_assert (size > 0);
329
330         memset (dst, 0, size);
331         
332         if (!src)
333                 return;
334
335         s = mono_string_to_utf8 (src);
336         len = MIN (size, strlen (s));
337         memcpy (dst, s, len);
338         g_free (s);
339
340         *((char *)dst + size - 1) = 0;
341 }
342
343 void
344 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
345 {
346         int len;
347
348         g_assert (dst != NULL);
349         g_assert (size > 1);
350
351         if (!src) {
352                 memset (dst, 0, size);
353                 return;
354         }
355
356         len = MIN (size, (mono_string_length (src) * 2));
357         memcpy (dst, mono_string_chars (src), len);
358
359         *((char *)dst + size - 1) = 0;
360         *((char *)dst + size - 2) = 0;
361 }
362
363 void
364 mono_mb_free (MonoMethodBuilder *mb)
365 {
366         g_list_free (mb->locals_list);
367         g_free (mb);
368 }
369
370 MonoMethodBuilder *
371 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
372 {
373         MonoMethodBuilder *mb;
374         MonoMethod *m;
375
376         g_assert (klass != NULL);
377         g_assert (name != NULL);
378
379         mb = g_new0 (MonoMethodBuilder, 1);
380
381         mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
382
383         m->klass = klass;
384         m->name = g_strdup (name);
385         m->inline_info = 1;
386         m->inline_count = -1;
387         m->wrapper_type = type;
388
389         mb->code_size = 256;
390         mb->code = g_malloc (mb->code_size);
391         
392         return mb;
393 }
394
395 int
396 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
397 {
398         int res = mb->locals;
399
400         g_assert (mb != NULL);
401         g_assert (type != NULL);
402
403         mb->locals_list = g_list_append (mb->locals_list, type);
404         mb->locals++;
405
406         return res;
407 }
408
409 MonoMethod *
410 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
411 {
412         MonoMethodHeader *header;
413         GList *l;
414         int i;
415
416         g_assert (mb != NULL);
417
418         ((MonoMethodNormal *)mb->method)->header = header = (MonoMethodHeader *) 
419                 g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
420
421         if (max_stack < 8)
422                 max_stack = 8;
423
424         header->max_stack = max_stack;
425
426         for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
427                 header->locals [i] = (MonoType *)l->data;
428         }
429
430         mb->method->signature = signature;
431         header->code = mb->code;
432         header->code_size = mb->pos;
433         header->num_locals = mb->locals;
434
435 #ifdef DEBUG_RUNTIME_CODE
436         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (mb->method, TRUE));
437         printf ("%s\n", mono_disasm_code (&marshal_dh, mb->method, mb->code, mb->code + mb->pos));
438 #endif
439
440         return mb->method;
441 }
442
443 guint32
444 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
445 {
446         MonoMethodWrapper *mw;
447
448         g_assert (mb != NULL);
449
450         mw = (MonoMethodWrapper *)mb->method;
451
452         mw->data = g_list_append (mw->data, data);
453
454         return g_list_length (mw->data);
455 }
456
457 void
458 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
459 {
460         mb->code [pos] = value & 0xff;
461         mb->code [pos + 1] = (value >> 8) & 0xff;
462         mb->code [pos + 2] = (value >> 16) & 0xff;
463         mb->code [pos + 3] = (value >> 24) & 0xff;
464 }
465
466 void
467 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
468 {
469         *((gint8 *)(&mb->code [pos])) = value;
470 }
471
472 void
473 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
474 {
475         if (mb->pos >= mb->code_size) {
476                 mb->code_size += 64;
477                 mb->code = g_realloc (mb->code, mb->code_size);
478         }
479
480         mb->code [mb->pos++] = op;
481 }
482
483 void
484 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
485 {
486         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
487         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
488
489         if (offset) {
490                 mono_mb_emit_icon (mb, offset);
491                 mono_mb_emit_byte (mb, CEE_ADD);
492         }
493 }
494
495 static int
496 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
497 {
498         int pos;
499         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
500         mono_mb_emit_byte (mb, CEE_LDIND_I);
501         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
502         mono_mb_emit_byte (mb, CEE_ADD);
503         mono_mb_emit_byte (mb, CEE_LDIND_I);
504         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
505         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
506         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
507         mono_mb_emit_byte (mb, branch_code);
508         pos = mb->pos;
509         mono_mb_emit_i4 (mb, 0);
510         return pos;
511 }
512
513 void
514 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
515 {
516         if ((mb->pos + 4) >= mb->code_size) {
517                 mb->code_size += 64;
518                 mb->code = g_realloc (mb->code, mb->code_size);
519         }
520
521         mono_mb_patch_addr (mb, mb->pos, data);
522         mb->pos += 4;
523 }
524
525 void
526 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
527 {
528         if ((mb->pos + 2) >= mb->code_size) {
529                 mb->code_size += 64;
530                 mb->code = g_realloc (mb->code, mb->code_size);
531         }
532
533         mb->code [mb->pos] = data & 0xff;
534         mb->code [mb->pos + 1] = (data >> 8) & 0xff;
535         mb->pos += 2;
536 }
537
538 void
539 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
540 {
541         mono_mb_emit_byte (mb, CEE_LDSTR);
542         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, str));
543 }
544
545
546 void
547 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
548 {
549         if (argnum < 4) {
550                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
551         } else if (argnum < 256) {
552                 mono_mb_emit_byte (mb, CEE_LDARG_S);
553                 mono_mb_emit_byte (mb, argnum);
554         } else {
555                 mono_mb_emit_byte (mb, CEE_PREFIX1);
556                 mono_mb_emit_byte (mb, CEE_LDARG);
557                 mono_mb_emit_i2 (mb, argnum);
558         }
559 }
560
561 void
562 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
563 {
564         if (argnum < 256) {
565                 mono_mb_emit_byte (mb, CEE_LDARGA_S);
566                 mono_mb_emit_byte (mb, argnum);
567         } else {
568                 mono_mb_emit_byte (mb, CEE_PREFIX1);
569                 mono_mb_emit_byte (mb, CEE_LDARGA);
570                 mono_mb_emit_i2 (mb, argnum);
571         }
572 }
573
574 void
575 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
576 {
577         if (locnum < 256) {
578                 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
579                 mono_mb_emit_byte (mb, locnum);
580         } else {
581                 mono_mb_emit_byte (mb, CEE_PREFIX1);
582                 mono_mb_emit_byte (mb, CEE_LDLOCA);
583                 mono_mb_emit_i2 (mb, locnum);
584         }
585 }
586
587 void
588 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
589 {
590         if (num < 4) {
591                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
592         } else if (num < 256) {
593                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
594                 mono_mb_emit_byte (mb, num);
595         } else {
596                 mono_mb_emit_byte (mb, CEE_PREFIX1);
597                 mono_mb_emit_byte (mb, CEE_LDLOC);
598                 mono_mb_emit_i2 (mb, num);
599         }
600 }
601
602 void
603 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
604 {
605         if (num < 4) {
606                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
607         } else if (num < 256) {
608                 mono_mb_emit_byte (mb, CEE_STLOC_S);
609                 mono_mb_emit_byte (mb, num);
610         } else {
611                 mono_mb_emit_byte (mb, CEE_PREFIX1);
612                 mono_mb_emit_byte (mb, CEE_STLOC);
613                 mono_mb_emit_i2 (mb, num);
614         }
615 }
616
617 void
618 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
619 {
620         if (value >= -1 && value < 8) {
621                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
622         } else if (value >= -128 && value <= 127) {
623                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
624                 mono_mb_emit_byte (mb, value);
625         } else {
626                 mono_mb_emit_byte (mb, CEE_LDC_I4);
627                 mono_mb_emit_i4 (mb, value);
628         }
629 }
630
631 guint32
632 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
633 {
634         guint32 res;
635         mono_mb_emit_byte (mb, op);
636         res = mb->pos;
637         mono_mb_emit_i4 (mb, 0);
638         return res;
639 }
640
641 static void
642 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
643 {
644         mono_mb_emit_byte (mb, CEE_CALLI);
645         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
646 }
647
648 void
649 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
650 {
651         mono_mb_emit_byte (mb, CEE_PREFIX1);
652         mono_mb_emit_byte (mb, CEE_LDFTN);
653         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
654         mono_mb_emit_calli (mb, opt_sig ? opt_sig : method->signature);
655 }
656
657 void
658 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
659 {
660         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
661         mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
662         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
663         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
664         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
665         mono_mb_emit_calli (mb, sig);
666         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
667         mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
668 }
669
670 static void
671 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
672 {
673         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
674         mono_mb_emit_byte (mb, CEE_MONO_ICALL);
675         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
676 }
677
678 void
679 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
680 {
681         /* fixme: we need a better way to throw exception,
682          * supporting several exception types and messages */
683         MonoMethod *ctor = NULL;
684
685         MonoClass *mme = mono_class_from_name (mono_defaults.corlib, "System", exc_name);
686         int i;
687         mono_class_init (mme);
688         for (i = 0; i < mme->method.count; ++i) {
689                 if (strcmp (mme->methods [i]->name, ".ctor") == 0 && mme->methods [i]->signature->param_count == 0) {
690                         ctor = mme->methods [i];
691                         break;
692                 }
693         }
694         g_assert (ctor);
695         mono_mb_emit_byte (mb, CEE_NEWOBJ);
696         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ctor));
697         if (msg != NULL) {
698                 mono_mb_emit_byte (mb, CEE_DUP);
699                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message));
700                 mono_mb_emit_ldstr (mb, (char*)msg);
701                 mono_mb_emit_byte (mb, CEE_STIND_I);
702         }
703         mono_mb_emit_byte (mb, CEE_THROW);
704 }
705
706 void
707 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
708 {
709         mono_mb_emit_ldloc (mb, local); 
710         mono_mb_emit_icon (mb, incr);
711         mono_mb_emit_byte (mb, CEE_ADD);
712         mono_mb_emit_stloc (mb, local); 
713 }
714
715 static void
716 emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, 
717                       int usize, int msize, MonoMarshalSpec *mspec)
718 {
719         switch (conv) {
720         case MONO_MARSHAL_CONV_BOOL_I4:
721                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
722                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
723                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
724                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
725                 mono_mb_emit_byte (mb, 3);
726                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
727                 mono_mb_emit_byte (mb, CEE_BR_S);
728                 mono_mb_emit_byte (mb, 1);
729                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
730                 mono_mb_emit_byte (mb, CEE_STIND_I1);
731                 break;
732         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
733                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
734                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
735                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
736                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
737                 mono_mb_emit_byte (mb, 3);
738                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
739                 mono_mb_emit_byte (mb, CEE_BR_S);
740                 mono_mb_emit_byte (mb, 1);
741                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
742                 mono_mb_emit_byte (mb, CEE_STIND_I1);
743                 break;
744         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
745                 MonoClass *eclass = NULL;
746                 int esize;
747
748                 if (type->type == MONO_TYPE_SZARRAY) {
749                         eclass = type->data.klass;
750                 } else {
751                         g_assert_not_reached ();
752                 }
753
754                 if (eclass->valuetype)
755                         esize = mono_class_instance_size (eclass) - sizeof (MonoObject);
756                 else
757                         esize = sizeof (gpointer);
758
759                 /* create a new array */
760                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
761                 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
762                 mono_mb_emit_byte (mb, CEE_NEWARR);     
763                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass));
764                 mono_mb_emit_byte (mb, CEE_STIND_I);
765
766                 /* copy the elements */
767                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
768                 mono_mb_emit_byte (mb, CEE_LDIND_I);
769                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
770                 mono_mb_emit_byte (mb, CEE_ADD);
771                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
772                 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
773                 mono_mb_emit_byte (mb, CEE_PREFIX1);
774                 mono_mb_emit_byte (mb, CEE_CPBLK);                      
775
776                 break;
777         }
778         case MONO_MARSHAL_CONV_STR_BYVALSTR: 
779                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
780                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
781                 mono_mb_emit_icall (mb, mono_string_new_wrapper);
782                 mono_mb_emit_byte (mb, CEE_STIND_I);            
783                 break;
784         case MONO_MARSHAL_CONV_STR_LPTSTR:
785         case MONO_MARSHAL_CONV_STR_LPSTR:
786                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
787                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
788                 mono_mb_emit_byte (mb, CEE_LDIND_I);
789                 mono_mb_emit_icall (mb, mono_string_new_wrapper);
790                 mono_mb_emit_byte (mb, CEE_STIND_I);            
791                 break;
792         case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
793                 MonoClass *klass = mono_class_from_mono_type (type);
794                 int src_var, dst_var;
795
796                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
797                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
798                 
799                 /* *dst = new object */
800                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
801                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
802                 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
803                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
804                 mono_mb_emit_byte (mb, CEE_STIND_I);
805         
806                 /* save the old src pointer */
807                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
808                 mono_mb_emit_stloc (mb, src_var);
809                 /* save the old dst pointer */
810                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
811                 mono_mb_emit_stloc (mb, dst_var);
812
813                 /* dst = pointer to newly created object data */
814                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
815                 mono_mb_emit_byte (mb, CEE_LDIND_I);
816                 mono_mb_emit_icon (mb, sizeof (MonoObject));
817                 mono_mb_emit_byte (mb, CEE_ADD);
818                 mono_mb_emit_byte (mb, CEE_STLOC_1); 
819
820                 emit_struct_conv (mb, klass, TRUE);
821                 
822                 /* restore the old src pointer */
823                 mono_mb_emit_ldloc (mb, src_var);
824                 mono_mb_emit_byte (mb, CEE_STLOC_0);
825                 /* restore the old dst pointer */
826                 mono_mb_emit_ldloc (mb, dst_var);
827                 mono_mb_emit_byte (mb, CEE_STLOC_1);
828                 break;
829         }
830         case MONO_MARSHAL_CONV_DEL_FTN: {
831                 /* fixme: we never convert functions back to delegates, dont 
832                 // know if thats the correct behaviour
833                 */
834                 break;
835         }
836         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
837                 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
838                 break;
839         case MONO_MARSHAL_CONV_STR_LPWSTR:
840         case MONO_MARSHAL_CONV_STR_BSTR:
841         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
842         case MONO_MARSHAL_CONV_STR_TBSTR:
843         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
844         case MONO_MARSHAL_CONV_STR_BYVALWSTR: 
845         default:
846                 g_warning ("marshaling conversion %d not implemented", conv);
847                 g_assert_not_reached ();
848         }
849 }
850
851 static gpointer
852 conv_to_icall (MonoMarshalConv conv)
853 {
854         switch (conv) {
855         case MONO_MARSHAL_CONV_STR_LPWSTR:
856                 return mono_string_to_utf16;            
857         case MONO_MARSHAL_CONV_LPWSTR_STR:
858                 return mono_string_from_utf16;
859         case MONO_MARSHAL_CONV_LPSTR_STR:
860                 return mono_string_new_wrapper;
861         case MONO_MARSHAL_CONV_STR_LPTSTR:
862         case MONO_MARSHAL_CONV_STR_LPSTR:
863                 return mono_string_to_utf8;
864         case MONO_MARSHAL_CONV_STR_BSTR:
865                 return mono_string_to_bstr;
866         case MONO_MARSHAL_CONV_STR_TBSTR:
867         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
868                 return mono_string_to_ansibstr;
869         case MONO_MARSHAL_CONV_SB_LPSTR:
870         case MONO_MARSHAL_CONV_SB_LPTSTR:
871                 return mono_string_builder_to_utf8;
872         case MONO_MARSHAL_CONV_SB_LPWSTR:
873                 return mono_string_builder_to_utf16;
874         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
875                 return mono_array_to_savearray;
876         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
877                 return mono_array_to_lparray;
878         case MONO_MARSHAL_CONV_DEL_FTN:
879                 return mono_delegate_to_ftnptr;
880         case MONO_MARSHAL_CONV_FTN_DEL:
881                 return mono_ftnptr_to_delegate;
882         case MONO_MARSHAL_CONV_LPSTR_SB:
883         case MONO_MARSHAL_CONV_LPTSTR_SB:
884                 return mono_string_utf8_to_builder;
885         case MONO_MARSHAL_CONV_LPWSTR_SB:
886                 return mono_string_utf16_to_builder;
887         case MONO_MARSHAL_FREE_ARRAY:
888                 return mono_marshal_free_array;
889         case MONO_MARSHAL_CONV_STR_BYVALSTR:
890                 return mono_string_to_byvalstr;
891         case MONO_MARSHAL_CONV_STR_BYVALWSTR:
892                 return mono_string_to_byvalwstr;
893         default:
894                 g_assert_not_reached ();
895         }
896
897         return NULL;
898 }
899
900 static void
901 emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, int usize, int msize,
902                       MonoMarshalSpec *mspec)
903 {
904         int pos;
905
906         switch (conv) {
907         case MONO_MARSHAL_CONV_BOOL_I4:
908                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
909                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
910                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
911                 mono_mb_emit_byte (mb, CEE_STIND_I4);
912                 break;
913         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
914                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
915                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
916                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
917                 mono_mb_emit_byte (mb, CEE_NEG);
918                 mono_mb_emit_byte (mb, CEE_STIND_I2);
919                 break;
920         case MONO_MARSHAL_CONV_STR_LPWSTR:
921         case MONO_MARSHAL_CONV_STR_LPSTR:
922         case MONO_MARSHAL_CONV_STR_LPTSTR:
923         case MONO_MARSHAL_CONV_STR_BSTR:
924         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
925         case MONO_MARSHAL_CONV_STR_TBSTR: {
926                 int pos;
927
928                 /* free space if free == true */
929                 mono_mb_emit_byte (mb, CEE_LDLOC_2);
930                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
931                 pos = mb->pos;
932                 mono_mb_emit_byte (mb, 0);
933                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
934                 mono_mb_emit_byte (mb, CEE_LDIND_I);
935                 mono_mb_emit_icall (mb, g_free);
936                 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
937
938                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
939                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
940                 mono_mb_emit_byte (mb, CEE_LDIND_I);
941                 mono_mb_emit_icall (mb, conv_to_icall (conv));
942                 mono_mb_emit_byte (mb, CEE_STIND_I);    
943                 break;
944         }
945         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
946         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
947         case MONO_MARSHAL_CONV_DEL_FTN:
948                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
949                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
950                 mono_mb_emit_byte (mb, CEE_LDIND_I);
951                 mono_mb_emit_icall (mb, conv_to_icall (conv));
952                 mono_mb_emit_byte (mb, CEE_STIND_I);    
953                 break;
954         case MONO_MARSHAL_CONV_STR_BYVALSTR: 
955         case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
956                 if (!usize)
957                         break;
958
959                 mono_mb_emit_byte (mb, CEE_LDLOC_1); /* dst */
960                 mono_mb_emit_byte (mb, CEE_LDLOC_0);    
961                 mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */
962                 mono_mb_emit_icon (mb, usize);
963                 mono_mb_emit_icall (mb, conv_to_icall (conv));
964                 break;
965         }
966         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
967                 MonoClass *eclass = NULL;
968                 int esize;
969
970                 if (type->type == MONO_TYPE_SZARRAY) {
971                         eclass = type->data.klass;
972                 } else {
973                         g_assert_not_reached ();
974                 }
975
976                 if (eclass->valuetype)
977                         esize = mono_class_native_size (eclass, NULL);
978                 else
979                         esize = sizeof (gpointer);
980
981                 if (!usize) 
982                         break;
983
984                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
985                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
986                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
987                 pos = mb->pos;
988                 mono_mb_emit_byte (mb, 0);
989
990                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
991                 mono_mb_emit_byte (mb, CEE_LDLOC_0);    
992                 mono_mb_emit_byte (mb, CEE_LDIND_I);    
993                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
994                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
995                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
996                 mono_mb_emit_byte (mb, CEE_ADD);
997                 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
998                 mono_mb_emit_byte (mb, CEE_PREFIX1);
999                 mono_mb_emit_byte (mb, CEE_CPBLK);                      
1000                 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1001                 break;
1002         }
1003         case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1004                 int src_var, dst_var;
1005
1006                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1007                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1008                 
1009                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1010                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
1011                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1012                 pos = mb->pos;
1013                 mono_mb_emit_byte (mb, 0);
1014                 
1015                 /* save the old src pointer */
1016                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1017                 mono_mb_emit_stloc (mb, src_var);
1018                 /* save the old dst pointer */
1019                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1020                 mono_mb_emit_stloc (mb, dst_var);
1021
1022                 /* src = pointer to object data */
1023                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1024                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
1025                 mono_mb_emit_icon (mb, sizeof (MonoObject));
1026                 mono_mb_emit_byte (mb, CEE_ADD);
1027                 mono_mb_emit_byte (mb, CEE_STLOC_0); 
1028
1029                 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
1030                 
1031                 /* restore the old src pointer */
1032                 mono_mb_emit_ldloc (mb, src_var);
1033                 mono_mb_emit_byte (mb, CEE_STLOC_0);
1034                 /* restore the old dst pointer */
1035                 mono_mb_emit_ldloc (mb, dst_var);
1036                 mono_mb_emit_byte (mb, CEE_STLOC_1);
1037
1038                 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
1039                 break;
1040         }
1041         default: {
1042                 char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
1043                 MonoException *exc = mono_get_exception_not_implemented (msg);
1044                 g_warning (msg);
1045                 g_free (msg);
1046                 mono_raise_exception (exc);
1047         }
1048         }
1049 }
1050
1051 static void
1052 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
1053 {
1054         MonoMarshalType *info;
1055         int i;
1056
1057         if (klass->parent)
1058                 emit_struct_conv(mb, klass->parent, to_object);
1059
1060         info = mono_marshal_load_type_info (klass);
1061
1062         if (info->native_size == 0)
1063                 return;
1064
1065         if (klass->blittable) {
1066                 int msize = mono_class_value_size (klass, NULL);
1067                 g_assert (msize == info->native_size);
1068                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1069                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1070                 mono_mb_emit_icon (mb, msize);
1071                 mono_mb_emit_byte (mb, CEE_PREFIX1);
1072                 mono_mb_emit_byte (mb, CEE_CPBLK);
1073
1074                 mono_mb_emit_add_to_local (mb, 0, msize);
1075                 mono_mb_emit_add_to_local (mb, 1, msize);
1076                 return;
1077         }
1078
1079         for (i = 0; i < info->num_fields; i++) {
1080                 MonoMarshalNative ntype;
1081                 MonoMarshalConv conv;
1082                 MonoType *ftype = info->fields [i].field->type;
1083                 int msize = 0;
1084                 int usize = 0;
1085                 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
1086
1087                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
1088                         continue;
1089
1090                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
1091                         
1092                 if (last_field) {
1093                         msize = klass->instance_size - info->fields [i].field->offset;
1094                         usize = info->native_size - info->fields [i].offset;
1095                 } else {
1096                         msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
1097                         usize = info->fields [i + 1].offset - info->fields [i].offset;
1098                 }
1099                 if ((msize < 0) || (usize < 0))
1100                         /* This happens with GC aware auto layout */
1101                         g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg));
1102
1103                 g_assert ((msize >= 0) && (usize >= 0));
1104
1105                 switch (conv) {
1106                 case MONO_MARSHAL_CONV_NONE: {
1107                         int t;
1108
1109                         if (ftype->byref || ftype->type == MONO_TYPE_I ||
1110                             ftype->type == MONO_TYPE_U) {
1111                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1112                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1113                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1114                                 mono_mb_emit_byte (mb, CEE_STIND_I);
1115                                 break;
1116                         }
1117
1118                         t = ftype->type;
1119                 handle_enum:
1120                         switch (t) {
1121                         case MONO_TYPE_I4:
1122                         case MONO_TYPE_U4:
1123 #if SIZEOF_VOID_P == 4
1124                         case MONO_TYPE_PTR:
1125 #endif
1126                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1127                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1128                                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1129                                 mono_mb_emit_byte (mb, CEE_STIND_I4);
1130                                 break;
1131                         case MONO_TYPE_I1:
1132                         case MONO_TYPE_U1:
1133                         case MONO_TYPE_BOOLEAN:
1134                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1135                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1136                                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
1137                                 mono_mb_emit_byte (mb, CEE_STIND_I1);
1138                                 break;
1139                         case MONO_TYPE_I2:
1140                         case MONO_TYPE_U2:
1141                         case MONO_TYPE_CHAR:
1142                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1143                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1144                                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1145                                 mono_mb_emit_byte (mb, CEE_STIND_I2);
1146                                 break;
1147                         case MONO_TYPE_I8:
1148                         case MONO_TYPE_U8:
1149 #if SIZEOF_VOID_P == 8
1150                         case MONO_TYPE_PTR:
1151 #endif
1152                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1153                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1154                                 mono_mb_emit_byte (mb, CEE_LDIND_I8);
1155                                 mono_mb_emit_byte (mb, CEE_STIND_I8);
1156                                 break;
1157                         case MONO_TYPE_R4:
1158                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1159                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1160                                 mono_mb_emit_byte (mb, CEE_LDIND_R4);
1161                                 mono_mb_emit_byte (mb, CEE_STIND_R4);
1162                                 break;
1163                         case MONO_TYPE_R8:
1164                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
1165                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1166                                 mono_mb_emit_byte (mb, CEE_LDIND_R8);
1167                                 mono_mb_emit_byte (mb, CEE_STIND_R8);
1168                                 break;
1169                         case MONO_TYPE_VALUETYPE:
1170                                 if (ftype->data.klass->enumtype) {
1171                                         t = ftype->data.klass->enum_basetype->type;
1172                                         goto handle_enum;
1173                                 }
1174                                 emit_struct_conv (mb, ftype->data.klass, to_object);
1175                                 continue;
1176                         default:
1177                                 g_warning ("marshaling type %02x not implemented", ftype->type);
1178                                 g_assert_not_reached ();
1179                         }
1180                         break;
1181                 }
1182                 default:
1183                         if (to_object) 
1184                                 emit_ptr_to_str_conv (mb, ftype, conv, usize, msize, info->fields [i].mspec);
1185                         else
1186                                 emit_str_to_ptr_conv (mb, ftype, conv, usize, msize, info->fields [i].mspec);   
1187                 }
1188                 
1189                 if (to_object) {
1190                         mono_mb_emit_add_to_local (mb, 0, usize);
1191                         mono_mb_emit_add_to_local (mb, 1, msize);
1192                 } else {
1193                         mono_mb_emit_add_to_local (mb, 0, msize);
1194                         mono_mb_emit_add_to_local (mb, 1, usize);
1195                 }                               
1196         }
1197 }
1198
1199 static void
1200 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
1201 {
1202         static MonoMethodSignature *state_check_sig = NULL;
1203         int pos_noabort;
1204         
1205         if (!state_check_sig) {
1206                 state_check_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
1207                 state_check_sig->ret = &mono_defaults.void_class->byval_arg;
1208                 state_check_sig->pinvoke = 0;
1209         }
1210         
1211         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1212         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1213         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, (gpointer) mono_thread_interruption_request_flag ()));
1214         mono_mb_emit_byte (mb, CEE_LDIND_I4);
1215         pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
1216
1217         mono_mb_emit_native_call (mb, state_check_sig, mono_thread_interruption_checkpoint);
1218         
1219         mono_mb_patch_addr (mb, pos_noabort, mb->pos - (pos_noabort + 4));
1220 }
1221
1222 static MonoAsyncResult *
1223 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
1224 {
1225         MonoMethodMessage *msg;
1226         MonoDelegate *async_callback;
1227         MonoObject *state;
1228         MonoMethod *im;
1229         MonoClass *klass;
1230         MonoMethod *method = NULL;
1231         int i;
1232
1233         g_assert (delegate);
1234
1235         if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
1236
1237                 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
1238                 if (!tp->remote_class->proxy_class->contextbound || tp->rp->context != (MonoObject *) mono_context_get ()) {
1239
1240                         /* If the target is a proxy, make a direct call. Is proxy's work
1241                         // to make the call asynchronous.
1242                         */
1243                         MonoAsyncResult *ares;
1244                         MonoObject *exc;
1245                         MonoArray *out_args;
1246                         HANDLE handle;
1247                         method = delegate->method_info->method;
1248
1249                         msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
1250                         handle = CreateEvent (NULL, TRUE, FALSE, NULL);
1251                         ares = mono_async_result_new (mono_domain_get (), handle, state, handle);
1252                         ares->async_delegate = (MonoObject *)delegate;
1253                         ares->async_callback = (MonoObject *)async_callback;
1254                         msg->async_result = ares;
1255                         msg->call_type = CallType_BeginInvoke;
1256
1257                         mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
1258                         return ares;
1259                 }
1260         }
1261
1262         klass = delegate->object.vtable->klass;
1263
1264         method = mono_get_delegate_invoke (klass);
1265         for (i = 0; i < klass->method.count; ++i) {
1266                 if (klass->methods [i]->name[0] == 'B' && 
1267                     !strcmp ("BeginInvoke", klass->methods [i]->name)) {
1268                         method = klass->methods [i];
1269                         break;
1270                 }
1271         }
1272
1273         g_assert (method != NULL);
1274
1275         im = mono_get_delegate_invoke (method->klass);
1276         msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
1277
1278         return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
1279 }
1280
1281 static int
1282 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
1283 {
1284         int i, params_var, tmp_var;
1285
1286         /* allocate local (pointer) *params[] */
1287         params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1288         /* allocate local (pointer) tmp */
1289         tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1290
1291         /* alloate space on stack to store an array of pointers to the arguments */
1292         mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
1293         mono_mb_emit_byte (mb, CEE_PREFIX1);
1294         mono_mb_emit_byte (mb, CEE_LOCALLOC);
1295         mono_mb_emit_stloc (mb, params_var);
1296
1297         /* tmp = params */
1298         mono_mb_emit_ldloc (mb, params_var);
1299         mono_mb_emit_stloc (mb, tmp_var);
1300
1301         if (save_this && sig->hasthis) {
1302                 mono_mb_emit_ldloc (mb, tmp_var);
1303                 mono_mb_emit_ldarg_addr (mb, 0);
1304                 mono_mb_emit_byte (mb, CEE_STIND_I);
1305                 /* tmp = tmp + sizeof (gpointer) */
1306                 if (sig->param_count)
1307                         mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
1308
1309         }
1310
1311         for (i = 0; i < sig->param_count; i++) {
1312                 mono_mb_emit_ldloc (mb, tmp_var);
1313                 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
1314                 mono_mb_emit_byte (mb, CEE_STIND_I);
1315                 /* tmp = tmp + sizeof (gpointer) */
1316                 if (i < (sig->param_count - 1))
1317                         mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
1318         }
1319
1320         return params_var;
1321 }
1322
1323 static char*
1324 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
1325 {
1326         int i;
1327         char *result;
1328         GString *res = g_string_new ("");
1329
1330         if (prefix) {
1331                 g_string_append (res, prefix);
1332                 g_string_append_c (res, '_');
1333         }
1334
1335         mono_type_get_desc (res, sig->ret, FALSE);
1336
1337         for (i = 0; i < sig->param_count; ++i) {
1338                 g_string_append_c (res, '_');
1339                 mono_type_get_desc (res, sig->params [i], FALSE);
1340         }
1341         result = res->str;
1342         g_string_free (res, FALSE);
1343         return result;
1344 }
1345
1346 /**
1347  * mono_marshal_get_string_encoding:
1348  *
1349  *  Return the string encoding which should be used for a given parameter.
1350  */
1351 static MonoMarshalNative
1352 mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1353 {
1354         /* First try the parameter marshal info */
1355         if (spec) {
1356                 if (spec->native == MONO_NATIVE_LPARRAY) {
1357                         if (spec->data.array_data.elem_type != 0)
1358                                 return spec->data.array_data.elem_type;
1359                 }
1360                 else
1361                         return spec->native;
1362         }
1363
1364         if (!piinfo)
1365                 return MONO_NATIVE_LPSTR;
1366
1367         /* Then try the method level marshal info */
1368         switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
1369         case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
1370                 return MONO_NATIVE_LPSTR;
1371         case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
1372                 return MONO_NATIVE_LPWSTR;
1373         case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
1374                 return MONO_NATIVE_LPTSTR;
1375         default:
1376                 return MONO_NATIVE_LPSTR;
1377         }
1378 }
1379
1380 static MonoMarshalNative
1381 mono_marshal_get_stringbuilder_to_ptr_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
1382 {
1383         MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1384
1385         switch (encoding) {
1386         case MONO_NATIVE_LPWSTR:
1387                 return MONO_MARSHAL_CONV_SB_LPWSTR;
1388                 break;
1389         case MONO_NATIVE_LPSTR:
1390                 return MONO_MARSHAL_CONV_SB_LPSTR;
1391                 break;
1392         case MONO_NATIVE_LPTSTR:
1393                 return MONO_MARSHAL_CONV_SB_LPTSTR;
1394                 break;
1395         default:
1396                 return -1;
1397         }
1398 }
1399
1400 static MonoMarshalNative
1401 mono_marshal_get_ptr_to_stringbuilder_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
1402 {
1403         MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
1404
1405         *need_free = TRUE;
1406
1407         switch (encoding) {
1408         case MONO_NATIVE_LPWSTR:
1409                 /* 
1410                  * mono_string_builder_to_utf16 does not allocate a 
1411                  * new buffer, so no need to free it.
1412                  */
1413                 *need_free = FALSE;
1414                 return MONO_MARSHAL_CONV_LPWSTR_SB;
1415         case MONO_NATIVE_LPSTR:
1416                 return MONO_MARSHAL_CONV_LPSTR_SB;
1417                 break;
1418         case MONO_NATIVE_LPTSTR:
1419                 return MONO_MARSHAL_CONV_LPTSTR_SB;
1420                 break;
1421         default:
1422                 return -1;
1423         }
1424 }
1425
1426 static inline MonoMethod*
1427 mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
1428 {
1429         MonoMethod *res;
1430
1431         EnterCriticalSection (&marshal_mutex);
1432         res = g_hash_table_lookup (cache, key);
1433         LeaveCriticalSection (&marshal_mutex);
1434         return res;
1435 }
1436
1437 /* Create the method from the builder and place it in the cache */
1438 static inline MonoMethod*
1439 mono_mb_create_and_cache (GHashTable *cache, gpointer key,
1440                                                            MonoMethodBuilder *mb, MonoMethodSignature *sig,
1441                                                            int max_stack)
1442 {
1443         MonoMethod *res;
1444
1445         EnterCriticalSection (&marshal_mutex);
1446         res = g_hash_table_lookup (cache, key);
1447         if (!res) {
1448                 /* This does not acquire any locks */
1449                 res = mono_mb_create_method (mb, sig, max_stack);
1450                 g_hash_table_insert (cache, key, res);
1451                 mono_g_hash_table_insert (wrapper_hash, res, key);
1452         }
1453         else
1454                 /* Somebody created it before us */
1455                 ;
1456         LeaveCriticalSection (&marshal_mutex);
1457
1458         return res;
1459 }               
1460
1461 MonoMethod *
1462 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
1463 {
1464         MonoMethod *res;
1465
1466         if (wrapper->wrapper_type == MONO_WRAPPER_NONE)
1467                 return wrapper;
1468
1469         EnterCriticalSection (&marshal_mutex);
1470         res = mono_g_hash_table_lookup (wrapper_hash, wrapper);
1471         LeaveCriticalSection (&marshal_mutex);
1472
1473         if (res && wrapper->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
1474                 /* See mono_marshal_get_remoting_invoke_with_check */
1475                 return (MonoMethod*)((char*)res - 1);
1476         else
1477                 return res;
1478 }
1479
1480 MonoMethod *
1481 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
1482 {
1483         MonoMethodSignature *sig;
1484         static MonoMethodSignature *csig = NULL;
1485         MonoMethodBuilder *mb;
1486         MonoMethod *res;
1487         GHashTable *cache;
1488         int params_var;
1489         char *name;
1490
1491         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1492                   !strcmp (method->name, "BeginInvoke"));
1493
1494         sig = method->signature;
1495
1496         cache = method->klass->image->delegate_begin_invoke_cache;
1497         if ((res = mono_marshal_find_in_cache (cache, sig)))
1498                 return res;
1499
1500         g_assert (sig->hasthis);
1501
1502         if (!csig) {
1503                 csig = mono_metadata_signature_alloc (method->klass->image, 2);
1504
1505                 /* MonoAsyncResult * begin_invoke (MonoDelegate *delegate, gpointer params[]) */
1506                 csig->ret = &mono_defaults.object_class->byval_arg;
1507                 csig->params [0] = &mono_defaults.object_class->byval_arg;
1508                 csig->params [1] = &mono_defaults.int_class->byval_arg;
1509         }
1510
1511         name = mono_signature_to_name (sig, "begin_invoke");
1512         mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
1513         g_free (name);
1514
1515         mb->method->save_lmf = 1;
1516
1517         params_var = mono_mb_emit_save_args (mb, sig, FALSE);
1518
1519         mono_mb_emit_ldarg (mb, 0);
1520         mono_mb_emit_ldloc (mb, params_var);
1521         mono_mb_emit_native_call (mb, csig, mono_delegate_begin_invoke);
1522         emit_thread_interrupt_checkpoint (mb);
1523         mono_mb_emit_byte (mb, CEE_RET);
1524
1525         res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
1526         mono_mb_free (mb);
1527         return res;
1528 }
1529
1530 static MonoObject *
1531 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
1532 {
1533         MonoDomain *domain = mono_domain_get ();
1534         MonoAsyncResult *ares;
1535         MonoMethod *method = NULL;
1536         MonoMethodSignature *sig;
1537         MonoMethodMessage *msg;
1538         MonoObject *res, *exc;
1539         MonoArray *out_args;
1540         MonoClass *klass;
1541         int i;
1542
1543         g_assert (delegate);
1544
1545         if (!delegate->method_info || !delegate->method_info->method)
1546                 g_assert_not_reached ();
1547
1548         klass = delegate->object.vtable->klass;
1549
1550         for (i = 0; i < klass->method.count; ++i) {
1551                 if (klass->methods [i]->name[0] == 'E' && 
1552                     !strcmp ("EndInvoke", klass->methods [i]->name)) {
1553                         method = klass->methods [i];
1554                         break;
1555                 }
1556         }
1557
1558         g_assert (method != NULL);
1559
1560         sig = method->signature;
1561
1562         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
1563
1564         ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
1565         g_assert (ares);
1566
1567         if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
1568                 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
1569                 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
1570                 mono_message_init (domain, msg, delegate->method_info, NULL);
1571                 msg->call_type = CallType_EndInvoke;
1572                 msg->async_result = ares;
1573                 res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
1574         }
1575         else
1576                 res = mono_thread_pool_finish (ares, &out_args, &exc);
1577
1578         if (exc) {
1579                 if (((MonoException*)exc)->stack_trace) {
1580                         char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
1581                         char  *tmp;
1582                         tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
1583                         g_free (strace);        
1584                         ((MonoException*)exc)->stack_trace = mono_string_new (domain, tmp);
1585                         g_free (tmp);
1586                 }
1587                 mono_raise_exception ((MonoException*)exc);
1588         }
1589
1590         mono_method_return_message_restore (method, params, out_args);
1591         return res;
1592 }
1593
1594 static void
1595 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
1596 {
1597         if (return_type->byref)
1598                 return_type = &mono_defaults.int_class->byval_arg;
1599         else if (return_type->type == MONO_TYPE_VALUETYPE && return_type->data.klass->enumtype)
1600                 return_type = return_type->data.klass->enum_basetype;
1601
1602         switch (return_type->type) {
1603         case MONO_TYPE_VOID:
1604                 g_assert_not_reached ();
1605                 break;
1606         case MONO_TYPE_PTR:
1607         case MONO_TYPE_STRING:
1608         case MONO_TYPE_CLASS: 
1609         case MONO_TYPE_OBJECT: 
1610         case MONO_TYPE_ARRAY: 
1611         case MONO_TYPE_SZARRAY: 
1612                 /* nothing to do */
1613                 break;
1614         case MONO_TYPE_U1:
1615         case MONO_TYPE_BOOLEAN:
1616                 mono_mb_emit_byte (mb, CEE_UNBOX);
1617                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1618                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1619                 break;
1620         case MONO_TYPE_I1:
1621                 mono_mb_emit_byte (mb, CEE_UNBOX);
1622                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1623                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
1624                 break;
1625         case MONO_TYPE_U2:
1626         case MONO_TYPE_CHAR:
1627                 mono_mb_emit_byte (mb, CEE_UNBOX);
1628                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1629                 mono_mb_emit_byte (mb, CEE_LDIND_U2);
1630                 break;
1631         case MONO_TYPE_I2:
1632                 mono_mb_emit_byte (mb, CEE_UNBOX);
1633                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1634                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1635                 break;
1636         case MONO_TYPE_I:
1637         case MONO_TYPE_U:
1638                 mono_mb_emit_byte (mb, CEE_UNBOX);
1639                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1640                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1641                 break;
1642         case MONO_TYPE_I4:
1643                 mono_mb_emit_byte (mb, CEE_UNBOX);
1644                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1645                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1646                 break;
1647         case MONO_TYPE_U4:
1648                 mono_mb_emit_byte (mb, CEE_UNBOX);
1649                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1650                 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1651                 break;
1652         case MONO_TYPE_U8:
1653         case MONO_TYPE_I8:
1654                 mono_mb_emit_byte (mb, CEE_UNBOX);
1655                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1656                 mono_mb_emit_byte (mb, CEE_LDIND_I8);
1657                 break;
1658         case MONO_TYPE_R4:
1659                 mono_mb_emit_byte (mb, CEE_UNBOX);
1660                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1661                 mono_mb_emit_byte (mb, CEE_LDIND_R4);
1662                 break;
1663         case MONO_TYPE_R8:
1664                 mono_mb_emit_byte (mb, CEE_UNBOX);
1665                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1666                 mono_mb_emit_byte (mb, CEE_LDIND_R8);
1667                 break;
1668         case MONO_TYPE_VALUETYPE: {
1669                 int class;
1670                 mono_mb_emit_byte (mb, CEE_UNBOX);
1671                 class = mono_mb_add_data (mb, mono_class_from_mono_type (return_type));
1672                 mono_mb_emit_i4 (mb, class);
1673                 mono_mb_emit_byte (mb, CEE_LDOBJ);
1674                 mono_mb_emit_i4 (mb, class);
1675                 break;
1676         }
1677         default:
1678                 g_warning ("type 0x%x not handled", return_type->type);
1679                 g_assert_not_reached ();
1680         }
1681
1682         mono_mb_emit_byte (mb, CEE_RET);
1683 }
1684
1685 MonoMethod *
1686 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
1687 {
1688         MonoMethodSignature *sig;
1689         static MonoMethodSignature *csig = NULL;
1690         MonoMethodBuilder *mb;
1691         MonoMethod *res;
1692         GHashTable *cache;
1693         int params_var;
1694         char *name;
1695
1696         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1697                   !strcmp (method->name, "EndInvoke"));
1698
1699         sig = method->signature;
1700
1701         cache = method->klass->image->delegate_end_invoke_cache;
1702         if ((res = mono_marshal_find_in_cache (cache, sig)))
1703                 return res;
1704
1705         g_assert (sig->hasthis);
1706
1707         if (!csig) {
1708                 csig = mono_metadata_signature_alloc (method->klass->image, 2);
1709
1710                 /* MonoObject *end_invoke (MonoDelegate *delegate, gpointer params[]) */
1711                 csig->ret = &mono_defaults.object_class->byval_arg;
1712                 csig->params [0] = &mono_defaults.object_class->byval_arg;
1713                 csig->params [1] = &mono_defaults.int_class->byval_arg;
1714         }
1715
1716         name = mono_signature_to_name (sig, "end_invoke");
1717         mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
1718         g_free (name);
1719
1720         mb->method->save_lmf = 1;
1721
1722         params_var = mono_mb_emit_save_args (mb, sig, FALSE);
1723
1724         mono_mb_emit_ldarg (mb, 0);
1725         mono_mb_emit_ldloc (mb, params_var);
1726         mono_mb_emit_native_call (mb, csig, mono_delegate_end_invoke);
1727         emit_thread_interrupt_checkpoint (mb);
1728
1729         if (sig->ret->type == MONO_TYPE_VOID) {
1730                 mono_mb_emit_byte (mb, CEE_POP);
1731                 mono_mb_emit_byte (mb, CEE_RET);
1732         } else
1733                 mono_mb_emit_restore_result (mb, sig->ret);
1734
1735         res = mono_mb_create_and_cache (cache, sig,
1736                                                                                  mb, sig, sig->param_count + 16);
1737         mono_mb_free (mb);
1738
1739         return res;
1740 }
1741
1742 static MonoObject *
1743 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
1744 {
1745         MonoMethodMessage *msg;
1746         MonoTransparentProxy *this;
1747         MonoObject *res, *exc;
1748         MonoArray *out_args;
1749
1750         this = *((MonoTransparentProxy **)params [0]);
1751
1752         g_assert (this);
1753         g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
1754         
1755         /* skip the this pointer */
1756         params++;
1757
1758         if (this->remote_class->proxy_class->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
1759         {
1760                 int i;
1761                 MonoMethodSignature *sig = method->signature;
1762                 int count = sig->param_count;
1763                 gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
1764
1765                 for (i=0; i<count; i++) {
1766                         MonoClass *class = mono_class_from_mono_type (sig->params [i]);
1767                         if (class->valuetype) {
1768                                 if (sig->params [i]->byref)
1769                                         mparams[i] = *((gpointer *)params [i]);
1770                                 else 
1771                                         mparams[i] = params [i];
1772                         } else {
1773                                 mparams[i] = *((gpointer**)params [i]);
1774                         }
1775                 }
1776
1777                 return mono_runtime_invoke (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this): this, mparams, NULL);
1778         }
1779
1780         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
1781
1782         res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
1783
1784         if (exc)
1785                 mono_raise_exception ((MonoException *)exc);
1786
1787         mono_method_return_message_restore (method, params, out_args);
1788
1789         return res;
1790
1791
1792 MonoMethod *
1793 mono_marshal_get_remoting_invoke (MonoMethod *method)
1794 {
1795         MonoMethodSignature *sig;
1796         static MonoMethodSignature *csig = NULL;
1797         MonoMethodBuilder *mb;
1798         MonoMethod *res;
1799         GHashTable *cache;
1800         int params_var;
1801
1802         g_assert (method);
1803
1804         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
1805                 return method;
1806
1807         sig = method->signature;
1808
1809         /* we cant remote methods without this pointer */
1810         if (!sig->hasthis)
1811                 return method;
1812
1813         cache = method->klass->image->remoting_invoke_cache;
1814         if ((res = mono_marshal_find_in_cache (cache, method)))
1815                 return res;
1816
1817         if (!csig) {
1818                 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
1819                 csig->params [0] = &mono_defaults.int_class->byval_arg;
1820                 csig->params [1] = &mono_defaults.int_class->byval_arg;
1821                 csig->ret = &mono_defaults.object_class->byval_arg;
1822                 csig->pinvoke = 1;
1823         }
1824
1825         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
1826         mb->method->save_lmf = 1;
1827
1828         params_var = mono_mb_emit_save_args (mb, sig, TRUE);
1829
1830         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1831         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1832         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
1833         mono_mb_emit_ldloc (mb, params_var);
1834         mono_mb_emit_native_call (mb, csig, mono_remoting_wrapper);
1835         emit_thread_interrupt_checkpoint (mb);
1836
1837         if (sig->ret->type == MONO_TYPE_VOID) {
1838                 mono_mb_emit_byte (mb, CEE_POP);
1839                 mono_mb_emit_byte (mb, CEE_RET);
1840         } else {
1841                  mono_mb_emit_restore_result (mb, sig->ret);
1842         }
1843
1844         res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1845         mono_mb_free (mb);
1846
1847         return res;
1848 }
1849
1850 MonoMethod *
1851 mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
1852 {
1853         MonoMethodSignature *sig;
1854         MonoMethodBuilder *mb;
1855         MonoMethod *res, *native;
1856         GHashTable *cache;
1857         int i, pos;
1858
1859         g_assert (method);
1860
1861         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
1862                 return method;
1863
1864         sig = method->signature;
1865
1866         /* we cant remote methods without this pointer */
1867         g_assert (sig->hasthis);
1868
1869         cache = method->klass->image->remoting_invoke_cache;
1870         if ((res = mono_marshal_find_in_cache (cache, (char *)method + 1)))
1871                 return res;
1872
1873         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
1874
1875         mono_mb_emit_ldarg (mb, 0);
1876         pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
1877
1878         native = mono_marshal_get_remoting_invoke (method);
1879
1880         for (i = 0; i <= sig->param_count; i++)
1881                 mono_mb_emit_ldarg (mb, i);
1882         
1883         mono_mb_emit_managed_call (mb, native, native->signature);
1884         mono_mb_emit_byte (mb, CEE_RET);
1885
1886         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
1887
1888         for (i = 0; i <= sig->param_count; i++)
1889                 mono_mb_emit_ldarg (mb, i);
1890                 
1891         mono_mb_emit_managed_call (mb, method, method->signature);
1892         mono_mb_emit_byte (mb, CEE_RET);
1893
1894         res = mono_mb_create_and_cache (cache, (char*)method + 1,
1895                                                                                  mb, sig, sig->param_count + 16);
1896         mono_mb_free (mb);
1897
1898         return res;
1899 }
1900
1901 /*
1902  * the returned method invokes all methods in a multicast delegate 
1903  */
1904 MonoMethod *
1905 mono_marshal_get_delegate_invoke (MonoMethod *method)
1906 {
1907         MonoMethodSignature *sig, *static_sig;
1908         int i;
1909         MonoMethodBuilder *mb;
1910         MonoMethod *res;
1911         GHashTable *cache;
1912         int pos0, pos1;
1913         char *name;
1914
1915         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1916                   !strcmp (method->name, "Invoke"));
1917                 
1918         sig = method->signature;
1919
1920         cache = method->klass->image->delegate_invoke_cache;
1921         if ((res = mono_marshal_find_in_cache (cache, sig)))
1922                 return res;
1923
1924         static_sig = mono_metadata_signature_dup (sig);
1925         static_sig->hasthis = 0;
1926
1927         name = mono_signature_to_name (sig, "invoke");
1928         mb = mono_mb_new (mono_defaults.multicastdelegate_class, name,  MONO_WRAPPER_DELEGATE_INVOKE);
1929         g_free (name);
1930
1931         /* allocate local 0 (object) */
1932         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1933
1934         g_assert (sig->hasthis);
1935         
1936         /*
1937          * if (prev != null)
1938          *      prev.Invoke( args .. );
1939          * return this.<target>( args .. );
1940          */
1941         
1942         /* this wrapper can be used in unmanaged-managed transitions */
1943         emit_thread_interrupt_checkpoint (mb);
1944         
1945         /* get this->prev */
1946         mono_mb_emit_ldarg (mb, 0);
1947         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
1948         mono_mb_emit_byte (mb, CEE_LDIND_I );
1949         mono_mb_emit_stloc (mb, 0);
1950
1951         /* if prev != null */
1952         mono_mb_emit_ldloc (mb, 0);
1953         mono_mb_emit_byte (mb, CEE_BRFALSE);
1954
1955         pos0 = mb->pos;
1956         mono_mb_emit_i4 (mb, 0);
1957
1958         /* then recurse */
1959         mono_mb_emit_ldloc (mb, 0);
1960         for (i = 0; i < sig->param_count; i++)
1961                 mono_mb_emit_ldarg (mb, i + 1);
1962         mono_mb_emit_managed_call (mb, method, method->signature);
1963         if (sig->ret->type != MONO_TYPE_VOID)
1964                 mono_mb_emit_byte (mb, CEE_POP);
1965
1966         /* continued or prev == null */
1967         mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
1968
1969         /* get this->target */
1970         mono_mb_emit_ldarg (mb, 0);
1971         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, target));
1972         mono_mb_emit_byte (mb, CEE_LDIND_I );
1973         mono_mb_emit_stloc (mb, 0);
1974
1975         /* if target != null */
1976         mono_mb_emit_ldloc (mb, 0);
1977         mono_mb_emit_byte (mb, CEE_BRFALSE);
1978         pos0 = mb->pos;
1979         mono_mb_emit_i4 (mb, 0);
1980         
1981         /* then call this->method_ptr nonstatic */
1982         mono_mb_emit_ldloc (mb, 0); 
1983         for (i = 0; i < sig->param_count; ++i)
1984                 mono_mb_emit_ldarg (mb, i + 1);
1985         mono_mb_emit_ldarg (mb, 0);
1986         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
1987         mono_mb_emit_byte (mb, CEE_LDIND_I );
1988         mono_mb_emit_byte (mb, CEE_CALLI);
1989         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
1990
1991         mono_mb_emit_byte (mb, CEE_BR);
1992         pos1 = mb->pos;
1993         mono_mb_emit_i4 (mb, 0);
1994
1995         /* else [target == null] call this->method_ptr static */
1996         mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
1997
1998         for (i = 0; i < sig->param_count; ++i)
1999                 mono_mb_emit_ldarg (mb, i + 1);
2000         mono_mb_emit_ldarg (mb, 0);
2001         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
2002         mono_mb_emit_byte (mb, CEE_LDIND_I );
2003         mono_mb_emit_byte (mb, CEE_CALLI);
2004         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
2005
2006         /* return */
2007         mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
2008         mono_mb_emit_byte (mb, CEE_RET);
2009
2010         res = mono_mb_create_and_cache (cache, sig,
2011                                                                                  mb, sig, sig->param_count + 16);
2012         mono_mb_free (mb);
2013
2014         return res;     
2015 }
2016
2017 /*
2018  * signature_dup_add_this:
2019  *
2020  *  Make a copy of @sig, adding an explicit this argument.
2021  */
2022 static MonoMethodSignature*
2023 signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass)
2024 {
2025         MonoMethodSignature *res;
2026         int i;
2027
2028         res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1);
2029         memcpy (res, sig, sizeof (MonoMethodSignature));
2030         res->param_count = sig->param_count + 1;
2031         res->hasthis = FALSE;
2032         for (i = sig->param_count - 1; i >= 0; i --)
2033                 res->params [i + 1] = sig->params [i];
2034         res->params [0] = &mono_ptr_class_get (&klass->byval_arg)->byval_arg;
2035
2036         return res;
2037 }
2038
2039 typedef struct {
2040         MonoMethod *ctor;
2041         MonoMethodSignature *sig;
2042 } CtorSigPair;
2043
2044 /*
2045  * generates IL code for the runtime invoke function 
2046  * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
2047  *
2048  * we also catch exceptions if exc != null
2049  */
2050 MonoMethod *
2051 mono_marshal_get_runtime_invoke (MonoMethod *method)
2052 {
2053         MonoMethodSignature *sig, *csig, *callsig;
2054         MonoExceptionClause *clause;
2055         MonoMethodHeader *header;
2056         MonoMethodBuilder *mb;
2057         GHashTable *cache = NULL;
2058         MonoClass *target_klass;
2059         MonoMethod *res = NULL;
2060         GSList *item;
2061         static MonoString *string_dummy = NULL;
2062         int i, pos;
2063         char *name;
2064
2065         g_assert (method);
2066
2067         target_klass = method->klass;
2068         
2069         EnterCriticalSection (&marshal_mutex);
2070
2071         if (method->string_ctor) {
2072                 static GSList *strsig_list = NULL;
2073                 CtorSigPair *cs;
2074
2075                 callsig = NULL;
2076                 for (item = strsig_list; item; item = item->next) {
2077                         cs = item->data;
2078                         if (mono_metadata_signature_equal (method->signature, cs->ctor->signature)) {
2079                                 callsig = cs->sig;
2080                                 break;
2081                         }
2082                 }
2083                 if (!callsig) {
2084                         callsig = mono_metadata_signature_dup (method->signature);
2085                         callsig->ret = &mono_defaults.string_class->byval_arg;
2086                         cs = g_new (CtorSigPair, 1);
2087                         cs->sig = callsig;
2088                         cs->ctor = method;
2089                         strsig_list = g_slist_prepend (strsig_list, cs);
2090                 }
2091         } else {
2092                 if (method->klass->valuetype && method->signature->hasthis) {
2093                         /* 
2094                          * Valuetype methods receive a managed pointer as the this argument.
2095                          * Create a new signature to reflect this.
2096                          */
2097                         callsig = signature_dup_add_this (method->signature, method->klass);
2098                 }
2099                 else
2100                         callsig = method->signature;
2101         }
2102
2103         cache = method->klass->image->runtime_invoke_cache;
2104
2105         /* from mono_marshal_find_in_cache */
2106         res = g_hash_table_lookup (cache, callsig);
2107         LeaveCriticalSection (&marshal_mutex);
2108
2109         if (res) {
2110                 return res;
2111         }
2112
2113         target_klass = mono_defaults.object_class;
2114
2115         /* to make it work with our special string constructors */
2116         if (!string_dummy) {
2117                 MONO_GC_REGISTER_ROOT (string_dummy);
2118                 string_dummy = mono_string_new_wrapper ("dummy");
2119         }
2120         
2121         sig = method->signature;
2122
2123         csig = mono_metadata_signature_alloc (method->klass->image, 4);
2124
2125         csig->ret = &mono_defaults.object_class->byval_arg;
2126         if (method->klass->valuetype && method->signature->hasthis)
2127                 csig->params [0] = callsig->params [0];
2128         else
2129                 csig->params [0] = &mono_defaults.object_class->byval_arg;
2130         csig->params [1] = &mono_defaults.int_class->byval_arg;
2131         csig->params [2] = &mono_defaults.int_class->byval_arg;
2132         csig->params [3] = &mono_defaults.int_class->byval_arg;
2133
2134         name = mono_signature_to_name (callsig, "runtime_invoke");
2135         mb = mono_mb_new (target_klass, name,  MONO_WRAPPER_RUNTIME_INVOKE);
2136         g_free (name);
2137
2138         /* allocate local 0 (object) tmp */
2139         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2140         /* allocate local 1 (object) exc */
2141         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2142
2143         /* cond set *exc to null */
2144         mono_mb_emit_byte (mb, CEE_LDARG_2);
2145         mono_mb_emit_byte (mb, CEE_BRFALSE_S);
2146         mono_mb_emit_byte (mb, 3);      
2147         mono_mb_emit_byte (mb, CEE_LDARG_2);
2148         mono_mb_emit_byte (mb, CEE_LDNULL);
2149         mono_mb_emit_byte (mb, CEE_STIND_I);
2150
2151         if (sig->hasthis) {
2152                 if (method->string_ctor) {
2153                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2154                         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
2155                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
2156                 } else {
2157                         mono_mb_emit_ldarg (mb, 0);
2158                 }
2159         }
2160
2161         for (i = 0; i < sig->param_count; i++) {
2162                 MonoType *t = sig->params [i];
2163                 int type;
2164
2165                 mono_mb_emit_ldarg (mb, 1);
2166                 if (i) {
2167                         mono_mb_emit_icon (mb, sizeof (gpointer) * i);
2168                         mono_mb_emit_byte (mb, CEE_ADD);
2169                 }
2170                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2171
2172                 if (t->byref)
2173                         continue;
2174
2175                 type = sig->params [i]->type;
2176 handle_enum:
2177                 switch (type) {
2178                 case MONO_TYPE_I1:
2179                         mono_mb_emit_byte (mb, CEE_LDIND_I1);
2180                         break;
2181                 case MONO_TYPE_BOOLEAN:
2182                 case MONO_TYPE_U1:
2183                         mono_mb_emit_byte (mb, CEE_LDIND_U1);
2184                         break;
2185                 case MONO_TYPE_I2:
2186                         mono_mb_emit_byte (mb, CEE_LDIND_I2);
2187                         break;
2188                 case MONO_TYPE_U2:
2189                 case MONO_TYPE_CHAR:
2190                         mono_mb_emit_byte (mb, CEE_LDIND_U2);
2191                         break;
2192                 case MONO_TYPE_I:
2193                 case MONO_TYPE_U:
2194                         mono_mb_emit_byte (mb, CEE_LDIND_I);
2195                         break;
2196                 case MONO_TYPE_I4:
2197                         mono_mb_emit_byte (mb, CEE_LDIND_I4);
2198                         break;
2199                 case MONO_TYPE_U4:
2200                         mono_mb_emit_byte (mb, CEE_LDIND_U4);
2201                         break;
2202                 case MONO_TYPE_R4:
2203                         mono_mb_emit_byte (mb, CEE_LDIND_R4);
2204                         break;
2205                 case MONO_TYPE_R8:
2206                         mono_mb_emit_byte (mb, CEE_LDIND_R8);
2207                         break;
2208                 case MONO_TYPE_I8:
2209                 case MONO_TYPE_U8:
2210                         mono_mb_emit_byte (mb, CEE_LDIND_I8);
2211                         break;
2212                 case MONO_TYPE_STRING:
2213                 case MONO_TYPE_CLASS:  
2214                 case MONO_TYPE_ARRAY:
2215                 case MONO_TYPE_PTR:
2216                 case MONO_TYPE_SZARRAY:
2217                 case MONO_TYPE_OBJECT:
2218                         /* do nothing */
2219                         break;
2220                 case MONO_TYPE_VALUETYPE:
2221                         if (t->data.klass->enumtype) {
2222                                 type = t->data.klass->enum_basetype->type;
2223                                 goto handle_enum;
2224                         }
2225                         mono_mb_emit_byte (mb, CEE_LDOBJ);
2226                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
2227                         break;
2228                 default:
2229                         g_assert_not_reached ();
2230                 }               
2231         }
2232         
2233         mono_mb_emit_ldarg (mb, 3);
2234         mono_mb_emit_calli (mb, callsig);
2235
2236         if (sig->ret->byref) {
2237                 /* fixme: */
2238                 g_assert_not_reached ();
2239         }
2240
2241
2242         switch (sig->ret->type) {
2243         case MONO_TYPE_VOID:
2244                 if (!method->string_ctor)
2245                         mono_mb_emit_byte (mb, CEE_LDNULL);
2246                 break;
2247         case MONO_TYPE_BOOLEAN:
2248         case MONO_TYPE_CHAR:
2249         case MONO_TYPE_I1:
2250         case MONO_TYPE_U1:
2251         case MONO_TYPE_I2:
2252         case MONO_TYPE_U2:
2253         case MONO_TYPE_I4:
2254         case MONO_TYPE_U4:
2255         case MONO_TYPE_I:
2256         case MONO_TYPE_U:
2257         case MONO_TYPE_R4:
2258         case MONO_TYPE_R8:
2259         case MONO_TYPE_I8:
2260         case MONO_TYPE_U8:
2261         case MONO_TYPE_VALUETYPE:
2262                 /* box value types */
2263                 mono_mb_emit_byte (mb, CEE_BOX);
2264                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret)));
2265                 break;
2266         case MONO_TYPE_STRING:
2267         case MONO_TYPE_CLASS:  
2268         case MONO_TYPE_ARRAY:
2269         case MONO_TYPE_SZARRAY:
2270         case MONO_TYPE_OBJECT:
2271                 /* nothing to do */
2272                 break;
2273         case MONO_TYPE_PTR:
2274         default:
2275                 g_assert_not_reached ();
2276         }
2277
2278         mono_mb_emit_stloc (mb, 0);
2279                 
2280         mono_mb_emit_byte (mb, CEE_LEAVE);
2281         pos = mb->pos;
2282         mono_mb_emit_i4 (mb, 0);
2283
2284         clause = g_new0 (MonoExceptionClause, 1);
2285         clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
2286         clause->try_len = mb->pos;
2287
2288         /* filter code */
2289         clause->token_or_filter = mb->pos;
2290         
2291         mono_mb_emit_byte (mb, CEE_POP);
2292         mono_mb_emit_byte (mb, CEE_LDARG_2);
2293         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2294         mono_mb_emit_byte (mb, CEE_PREFIX1);
2295         mono_mb_emit_byte (mb, CEE_CGT_UN);
2296         mono_mb_emit_byte (mb, CEE_PREFIX1);
2297         mono_mb_emit_byte (mb, CEE_ENDFILTER);
2298
2299         clause->handler_offset = mb->pos;
2300
2301         /* handler code */
2302         /* store exception */
2303         mono_mb_emit_stloc (mb, 1);
2304         
2305         mono_mb_emit_byte (mb, CEE_LDARG_2);
2306         mono_mb_emit_ldloc (mb, 1);
2307         mono_mb_emit_byte (mb, CEE_STIND_I);
2308
2309         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2310         mono_mb_emit_stloc (mb, 0);
2311
2312         mono_mb_emit_byte (mb, CEE_LEAVE);
2313         mono_mb_emit_i4 (mb, 0);
2314
2315         clause->handler_len = mb->pos - clause->handler_offset;
2316
2317         /* return result */
2318         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2319         mono_mb_emit_ldloc (mb, 0);
2320         mono_mb_emit_byte (mb, CEE_RET);
2321
2322         /* taken from mono_mb_create_and_cache */
2323         EnterCriticalSection (&marshal_mutex);
2324
2325         res = g_hash_table_lookup (cache, callsig);
2326         /* Somebody may have created it before us */
2327         if (!res) {
2328                 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
2329                 g_hash_table_insert (cache, callsig, res);
2330                 mono_g_hash_table_insert (wrapper_hash, res, callsig);
2331         }
2332
2333         LeaveCriticalSection (&marshal_mutex);
2334         /* end mono_mb_create_and_cache */
2335
2336         mono_mb_free (mb);
2337
2338         header = ((MonoMethodNormal *)res)->header;
2339         header->num_clauses = 1;
2340         header->clauses = clause;
2341
2342         return res;     
2343 }
2344
2345 /*
2346  * generates IL code to call managed methods from unmanaged code 
2347  */
2348 MonoMethod *
2349 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMarshalSpec **mspecs)
2350 {
2351         MonoMethodSignature *sig, *csig;
2352         MonoMethodBuilder *mb;
2353         MonoClass *klass = NULL;
2354         MonoMethod *res;
2355         GHashTable *cache;
2356         int i, pos = 0, *tmp_locals;
2357         static MonoMethodSignature *alloc_sig = NULL;
2358         int retobj_var = 0;
2359
2360         g_assert (method != NULL);
2361         g_assert (!method->signature->pinvoke);
2362
2363         cache = method->klass->image->managed_wrapper_cache;
2364         if (!this && (res = mono_marshal_find_in_cache (cache, method)))
2365                 return res;
2366
2367         /* Under MS, the allocation should be done using CoTaskMemAlloc */
2368         if (!alloc_sig) {
2369                 alloc_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
2370                 alloc_sig->params [0] = &mono_defaults.int_class->byval_arg;
2371                 alloc_sig->ret = &mono_defaults.int_class->byval_arg;
2372                 alloc_sig->pinvoke = 1;
2373         }
2374
2375         sig = method->signature;
2376
2377         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2378
2379         /* allocate local 0 (pointer) src_ptr */
2380         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2381         /* allocate local 1 (pointer) dst_ptr */
2382         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2383         /* allocate local 2 (boolean) delete_old */
2384         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
2385
2386         if (!MONO_TYPE_IS_VOID(sig->ret)) {
2387                 /* allocate local 3 to store the return value */
2388                 mono_mb_add_local (mb, sig->ret);
2389         }
2390
2391         mono_mb_emit_icon (mb, 0);
2392         mono_mb_emit_byte (mb, CEE_STLOC_2);
2393
2394         /* we copy the signature, so that we can modify it */
2395         csig = mono_metadata_signature_dup (sig);
2396         csig->hasthis = 0;
2397         csig->pinvoke = 1;
2398
2399 #ifdef PLATFORM_WIN32
2400         /* 
2401          * Under windows, delegates passed to native code must use the STDCALL
2402          * calling convention.
2403          */
2404         csig->call_convention = MONO_CALL_STDCALL;
2405 #endif
2406
2407         /* fixme: howto handle this ? */
2408         if (sig->hasthis) {
2409
2410                 if (this) {
2411                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2412                         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
2413                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, this));
2414
2415
2416                 } else {
2417                         /* fixme: */
2418                         g_assert_not_reached ();
2419                 }
2420         } 
2421
2422
2423         /* we first do all conversions */
2424         tmp_locals = alloca (sizeof (int) * sig->param_count);
2425         for (i = 0; i < sig->param_count; i ++) {
2426                 MonoType *t = sig->params [i];
2427                 MonoMarshalSpec *spec = mspecs [i + 1];
2428
2429                 tmp_locals [i] = 0;
2430                 
2431                 /* Ensure that we have marshalling info for this param */
2432                 mono_marshal_load_type_info (mono_class_from_mono_type (t));
2433
2434                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
2435                         MonoType *mtype;
2436                         MonoClass *mklass;
2437                         MonoMethod *marshal_native_to_managed;
2438                         MonoMethod *get_instance;
2439
2440                         mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
2441                         g_assert (mtype != NULL);
2442                         mklass = mono_class_from_mono_type (mtype);
2443                         g_assert (mklass != NULL);
2444
2445                         marshal_native_to_managed = mono_find_method_by_name (mklass, "MarshalNativeToManaged", 1);
2446                         g_assert (marshal_native_to_managed);
2447                         get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
2448                         g_assert (get_instance);
2449                         
2450                         switch (t->type) {
2451                         case MONO_TYPE_CLASS:
2452                         case MONO_TYPE_OBJECT:
2453                         case MONO_TYPE_STRING:
2454                         case MONO_TYPE_ARRAY:
2455                         case MONO_TYPE_SZARRAY:
2456                                 if (t->byref)
2457                                         break;
2458
2459                                 tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2460
2461                                 mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
2462
2463                                 mono_mb_emit_byte (mb, CEE_CALL);
2464                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
2465                                 
2466                                 mono_mb_emit_ldarg (mb, i);
2467                                 
2468                                 mono_mb_emit_byte (mb, CEE_CALLVIRT);
2469                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
2470                                 
2471                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
2472                                 break;
2473                         default:
2474                                 g_warning ("custom marshalling of type %x is currently not supported", t->type);
2475                                 g_assert_not_reached ();
2476                                 break;
2477                         }
2478                         continue;
2479                 }
2480
2481                 switch (t->type) {
2482                 case MONO_TYPE_CLASS: {
2483                         klass = t->data.klass;
2484
2485                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2486
2487                         if (klass->delegate) {
2488                                 g_assert (!t->byref);
2489                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2490                                 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
2491                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
2492                                 mono_mb_emit_ldarg (mb, i);
2493                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
2494                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
2495                                 break;
2496                         }
2497
2498                         /* FIXME: Raise a MarshalDirectiveException here */
2499                         g_assert ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT);
2500
2501                         if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2502                                 mono_mb_emit_byte (mb, CEE_LDNULL);
2503                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
2504                                 break;
2505                         }
2506
2507                         /* Set src */
2508                         mono_mb_emit_ldarg (mb, i);
2509                         if (t->byref) {
2510                                 int pos2;
2511
2512                                 /* Check for NULL and raise an exception */
2513                                 mono_mb_emit_byte (mb, CEE_BRTRUE);
2514                                 pos2 = mb->pos;
2515                                 mono_mb_emit_i4 (mb, 0);
2516
2517                                 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
2518
2519                                 mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
2520                                 mono_mb_emit_ldarg (mb, i);
2521                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2522                         }                               
2523
2524                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2525
2526                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2527                         mono_mb_emit_stloc (mb, tmp_locals [i]);
2528
2529                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
2530                         mono_mb_emit_byte (mb, CEE_BRFALSE);
2531                         pos = mb->pos;
2532                         mono_mb_emit_i4 (mb, 0);
2533
2534                         /* Create and set dst */
2535                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2536                         mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
2537                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
2538                         mono_mb_emit_stloc (mb, tmp_locals [i]);
2539                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
2540                         mono_mb_emit_icon (mb, sizeof (MonoObject));
2541                         mono_mb_emit_byte (mb, CEE_ADD);
2542                         mono_mb_emit_byte (mb, CEE_STLOC_1); 
2543
2544                         /* emit valuetype conversion code */
2545                         emit_struct_conv (mb, klass, TRUE);
2546
2547                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2548                         break;
2549                 }
2550                 case MONO_TYPE_VALUETYPE:
2551                         
2552                         klass = sig->params [i]->data.klass;
2553                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2554                             klass->blittable || klass->enumtype)
2555                                 break;
2556
2557                         tmp_locals [i] = mono_mb_add_local (mb, &klass->byval_arg);
2558
2559                         if (t->attrs & PARAM_ATTRIBUTE_OUT)
2560                                 break;
2561
2562                         if (t->byref) 
2563                                 mono_mb_emit_ldarg (mb, i);
2564                         else
2565                                 mono_mb_emit_ldarg_addr (mb, i);
2566                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2567
2568                         if (t->byref) {
2569                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
2570                                 mono_mb_emit_byte (mb, CEE_BRFALSE);
2571                                 pos = mb->pos;
2572                                 mono_mb_emit_i4 (mb, 0);
2573                         }                       
2574
2575                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2576                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2577
2578                         /* emit valuetype conversion code */
2579                         emit_struct_conv (mb, klass, TRUE);
2580
2581                         if (t->byref)
2582                                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2583                         break;
2584                 case MONO_TYPE_STRING: {
2585                         MonoMarshalNative encoding = mono_marshal_get_string_encoding (NULL, spec);
2586
2587                         if (t->byref)
2588                                 continue;
2589
2590                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2591                         csig->params [i] = &mono_defaults.int_class->byval_arg;
2592
2593                         mono_mb_emit_ldarg (mb, i);
2594
2595                         switch (encoding) {
2596                         case MONO_NATIVE_LPWSTR:
2597                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPWSTR_STR));
2598                                 break;
2599                         case MONO_NATIVE_LPSTR:
2600                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
2601                                 break;
2602                         default: {
2603                                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
2604                                         MonoException *exc = mono_get_exception_not_implemented (msg);
2605                                         g_warning (msg);
2606                                         g_free (msg);
2607                                         mono_raise_exception (exc);
2608                                 }
2609                         }
2610
2611                         mono_mb_emit_stloc (mb, tmp_locals [i]);
2612                         break;  
2613                 }
2614                 case MONO_TYPE_ARRAY:
2615                 case MONO_TYPE_SZARRAY:
2616                         if (t->byref)
2617                                 continue;
2618
2619                         klass = mono_class_from_mono_type (t);
2620
2621                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2622                         csig->params [i] = &mono_defaults.int_class->byval_arg;
2623
2624                         g_warning ("array marshaling not implemented");
2625                         g_assert_not_reached ();
2626                         break;
2627                 }
2628         }
2629
2630         for (i = 0; i < sig->param_count; i++) {
2631                 MonoType *t = sig->params [i];
2632
2633                 switch (t->type) {
2634                 case MONO_TYPE_BOOLEAN:
2635                 case MONO_TYPE_I1:
2636                 case MONO_TYPE_U1:
2637                 case MONO_TYPE_I2:
2638                 case MONO_TYPE_U2:
2639                 case MONO_TYPE_I4:
2640                 case MONO_TYPE_U4:
2641                 case MONO_TYPE_I:
2642                 case MONO_TYPE_U:
2643                 case MONO_TYPE_PTR:
2644                 case MONO_TYPE_R4:
2645                 case MONO_TYPE_R8:
2646                 case MONO_TYPE_I8:
2647                 case MONO_TYPE_U8:
2648                         mono_mb_emit_ldarg (mb, i);
2649                         break;
2650                 case MONO_TYPE_STRING:
2651                         if (t->byref) {
2652                                 mono_mb_emit_ldarg (mb, i);
2653                         } else {
2654                                 g_assert (tmp_locals [i]);
2655                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2656                         }
2657                         break;  
2658                 case MONO_TYPE_CLASS:  
2659                         if (t->byref)
2660                                 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2661                         else
2662                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2663                         break;
2664                 case MONO_TYPE_ARRAY:
2665                 case MONO_TYPE_SZARRAY:
2666                 case MONO_TYPE_OBJECT:
2667                         if (tmp_locals [i])
2668                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2669                         else
2670                                 mono_mb_emit_ldarg (mb, i);
2671                         break;
2672                 case MONO_TYPE_VALUETYPE:
2673                         klass = sig->params [i]->data.klass;
2674                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2675                             klass->blittable || klass->enumtype) {
2676                                 mono_mb_emit_ldarg (mb, i);
2677                                 break;
2678                         }
2679
2680                         g_assert (tmp_locals [i]);
2681                         if (t->byref)
2682                                 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2683                         else
2684                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2685                         break;
2686                 default:
2687                         g_warning ("type 0x%02x unknown", t->type);     
2688                         g_assert_not_reached ();
2689                 }
2690         }
2691
2692         emit_thread_interrupt_checkpoint (mb);
2693         mono_mb_emit_managed_call (mb, method, NULL);
2694
2695         /* Ensure that we have marshalling info for the return */
2696         mono_marshal_load_type_info (mono_class_from_mono_type (sig->ret));
2697
2698         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
2699                 MonoMarshalSpec *spec = mspecs [0];
2700                 MonoType *mtype;
2701                 MonoClass *mklass;
2702                 guint32 loc1;
2703
2704                 g_assert (!sig->ret->byref);
2705
2706                 mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
2707                 g_assert (mtype);
2708                 mklass = mono_class_from_mono_type (mtype);
2709                 g_assert (mklass);
2710
2711                 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2712                         
2713                 switch (sig->ret->type) {
2714                 case MONO_TYPE_CLASS:
2715                 case MONO_TYPE_OBJECT:
2716                 case MONO_TYPE_STRING:
2717                 case MONO_TYPE_ARRAY:
2718                 case MONO_TYPE_SZARRAY:
2719                         mono_mb_emit_byte (mb, CEE_STLOC_3);
2720                         
2721                         mono_mb_emit_byte (mb, CEE_LDLOC_3);
2722                         mono_mb_emit_stloc (mb, loc1);
2723
2724                         mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
2725                         mono_mb_emit_byte (mb, CEE_CALL);
2726                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_find_method_by_name (mklass, "GetInstance", 1)));
2727                         mono_mb_emit_byte (mb, CEE_DUP);
2728
2729                         mono_mb_emit_byte (mb, CEE_LDLOC_3);
2730                         mono_mb_emit_byte (mb, CEE_CALLVIRT);
2731                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_find_method_by_name (mklass, "MarshalManagedToNative", 1)));
2732                         mono_mb_emit_byte (mb, CEE_STLOC_3);
2733
2734                         mono_mb_emit_ldloc (mb, loc1);
2735                         mono_mb_emit_byte (mb, CEE_CALLVIRT);
2736                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_find_method_by_name (mklass, "CleanUpManagedData", 1)));
2737
2738                         break;
2739                 default:
2740                         g_warning ("custom marshalling of type %x is currently not supported", sig->ret->type);
2741                         g_assert_not_reached ();
2742                         break;
2743                 }
2744         }
2745         else
2746         if (!sig->ret->byref) { 
2747                 switch (sig->ret->type) {
2748                 case MONO_TYPE_VOID:
2749                         break;
2750                 case MONO_TYPE_BOOLEAN:
2751                 case MONO_TYPE_I1:
2752                 case MONO_TYPE_U1:
2753                 case MONO_TYPE_I2:
2754                 case MONO_TYPE_U2:
2755                 case MONO_TYPE_I4:
2756                 case MONO_TYPE_U4:
2757                 case MONO_TYPE_I:
2758                 case MONO_TYPE_U:
2759                 case MONO_TYPE_PTR:
2760                 case MONO_TYPE_R4:
2761                 case MONO_TYPE_R8:
2762                 case MONO_TYPE_I8:
2763                 case MONO_TYPE_U8:
2764                 case MONO_TYPE_OBJECT:
2765                         mono_mb_emit_byte (mb, CEE_STLOC_3);
2766                         break;
2767                 case MONO_TYPE_STRING:          
2768                         csig->ret = &mono_defaults.int_class->byval_arg;
2769
2770                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPSTR));
2771                         mono_mb_emit_byte (mb, CEE_STLOC_3);
2772                         break;
2773                 case MONO_TYPE_VALUETYPE:
2774                         klass = sig->ret->data.klass;
2775                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2776                             klass->blittable || klass->enumtype)
2777                                 break;
2778                         
2779                         /* load pointer to returned value type */
2780                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2781                         mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
2782                         
2783                         /* store the address of the source into local variable 0 */
2784                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2785                         /* allocate space for the native struct and
2786                          * store the address into dst_ptr */
2787                         retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2788                         g_assert (retobj_var);
2789                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
2790                         mono_mb_emit_byte (mb, CEE_CONV_I);
2791                         mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
2792                         emit_thread_interrupt_checkpoint (mb);
2793                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2794                         mono_mb_emit_byte (mb, CEE_LDLOC_1);
2795                         mono_mb_emit_stloc (mb, retobj_var);
2796
2797                         /* emit valuetype conversion code */
2798                         emit_struct_conv (mb, klass, FALSE);
2799                         break;
2800                 case MONO_TYPE_CLASS: {
2801                         int pos2;
2802
2803                         klass = sig->ret->data.klass;
2804
2805                         if (klass->delegate) {
2806                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
2807                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
2808                                 break;
2809                         }
2810
2811                         /* FIXME: Raise a MarshalDirectiveException here */
2812                         g_assert ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT);
2813
2814                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2815                         /* Check for null */
2816                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
2817                         pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
2818                         mono_mb_emit_byte (mb, CEE_LDNULL);
2819                         mono_mb_emit_byte (mb, CEE_STLOC_3);
2820                         pos2 = mono_mb_emit_branch (mb, CEE_BR);
2821
2822                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2823
2824                         /* Set src */
2825                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
2826                         mono_mb_emit_icon (mb, sizeof (MonoObject));
2827                         mono_mb_emit_byte (mb, CEE_ADD);
2828                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2829
2830                         /* Allocate and set dest */
2831                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
2832                         mono_mb_emit_byte (mb, CEE_CONV_I);
2833                         mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
2834                         emit_thread_interrupt_checkpoint (mb);
2835                         mono_mb_emit_byte (mb, CEE_DUP);
2836                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2837                         mono_mb_emit_byte (mb, CEE_STLOC_3);
2838
2839                         emit_struct_conv (mb, klass, FALSE);
2840
2841                         mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
2842                         break;
2843                 }
2844                 default:
2845                         g_warning ("return type 0x%02x unknown", sig->ret->type);       
2846                         g_assert_not_reached ();
2847                 }
2848         } else {
2849                 mono_mb_emit_byte (mb, CEE_STLOC_3);
2850         }
2851
2852         /* Convert byref arguments back */
2853         for (i = 0; i < sig->param_count; i ++) {
2854                 MonoType *t = sig->params [i];
2855                 MonoMarshalSpec *spec = mspecs [i + 1];
2856
2857                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
2858                         MonoType *mtype;
2859                         MonoClass *mklass;
2860                         MonoMethod *cleanup_managed;
2861                         MonoMethod *get_instance;
2862
2863                         mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
2864                         g_assert (mtype != NULL);
2865                         mklass = mono_class_from_mono_type (mtype);
2866                         g_assert (mklass != NULL);
2867
2868                         get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
2869                         g_assert (get_instance);
2870                         cleanup_managed = mono_find_method_by_name (mklass, "CleanUpManagedData", 1);
2871                         g_assert (cleanup_managed);
2872
2873                         switch (t->type) {
2874                         case MONO_TYPE_CLASS:
2875                         case MONO_TYPE_OBJECT:
2876                         case MONO_TYPE_STRING:
2877                         case MONO_TYPE_ARRAY:
2878                         case MONO_TYPE_SZARRAY:
2879                                 if (t->byref)
2880                                         g_assert_not_reached ();
2881
2882                                 /* Call CleanUpManagedData */
2883
2884                                 mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
2885
2886                                 mono_mb_emit_byte (mb, CEE_CALL);
2887                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
2888                                 
2889                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2890                                 mono_mb_emit_byte (mb, CEE_CALLVIRT);
2891                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_managed));
2892                                 
2893                                 break;
2894                         default:
2895                                 g_warning ("custom marshalling of type %x is currently not supported", t->type);
2896                                 g_assert_not_reached ();
2897                                 break;
2898                         }
2899                         continue;
2900                 }
2901
2902                 if (!t->byref)
2903                         continue;
2904
2905                 switch (t->type) {
2906                 case MONO_TYPE_CLASS: {
2907                         int pos2;
2908
2909                         klass = t->data.klass;
2910
2911                         /* Check for null */
2912                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
2913                         pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
2914                         mono_mb_emit_ldarg (mb, i);
2915                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2916                         mono_mb_emit_byte (mb, CEE_STIND_I);
2917                         pos2 = mono_mb_emit_branch (mb, CEE_BR);
2918
2919                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));                      
2920                         
2921                         /* Set src */
2922                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
2923                         mono_mb_emit_icon (mb, sizeof (MonoObject));
2924                         mono_mb_emit_byte (mb, CEE_ADD);
2925                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2926
2927                         /* Allocate and set dest */
2928                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
2929                         mono_mb_emit_byte (mb, CEE_CONV_I);
2930                         mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
2931                         emit_thread_interrupt_checkpoint (mb);
2932                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2933
2934                         /* Update argument pointer */
2935                         mono_mb_emit_ldarg (mb, i);
2936                         mono_mb_emit_byte (mb, CEE_LDLOC_1);
2937                         mono_mb_emit_byte (mb, CEE_STIND_I);
2938
2939                         /* emit valuetype conversion code */
2940                         emit_struct_conv (mb, klass, FALSE);
2941
2942                         mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
2943                         break;
2944                 }
2945                 case MONO_TYPE_VALUETYPE: {
2946                         int pos2;
2947
2948                         klass = t->data.klass;
2949
2950                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
2951                             klass->blittable || klass->enumtype) {
2952                                 break;
2953                         }
2954
2955                         /* Check for null */
2956                         mono_mb_emit_ldarg (mb, i);
2957                         pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
2958
2959                         /* Set src */
2960                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
2961                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2962
2963                         /* Set dest */
2964                         mono_mb_emit_ldarg (mb, i);
2965                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2966
2967                         /* emit valuetype conversion code */
2968                         emit_struct_conv (mb, klass, FALSE);
2969
2970                         mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
2971                         break;
2972                 }
2973                 }
2974         }
2975
2976         if (retobj_var) {
2977                 mono_mb_emit_ldloc (mb, retobj_var);
2978                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2979                 mono_mb_emit_byte (mb, CEE_MONO_RETOBJ);
2980                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
2981         }
2982         else {
2983                 if (!MONO_TYPE_IS_VOID(sig->ret))
2984                         mono_mb_emit_byte (mb, CEE_LDLOC_3);
2985                 mono_mb_emit_byte (mb, CEE_RET);
2986         }
2987
2988         if (!this)
2989                 res = mono_mb_create_and_cache (cache, method,
2990                                                                                          mb, csig, sig->param_count + 16);
2991         else {
2992                 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
2993                 res->dynamic = 1;
2994         }
2995         mono_mb_free (mb);
2996
2997         /* 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)); */
2998
2999         return res;
3000 }
3001
3002 /*
3003  * mono_marshal_get_ldfld_wrapper:
3004  * @type: the type of the field
3005  *
3006  * This method generates a function which can be use to load a field with type
3007  * @type from an object. The generated function has the following signature:
3008  * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
3009  */
3010 MonoMethod *
3011 mono_marshal_get_ldfld_wrapper (MonoType *type)
3012 {
3013         MonoMethodSignature *sig, *csig;
3014         MonoMethodBuilder *mb;
3015         MonoMethod *res;
3016         MonoClass *klass;
3017         static GHashTable *ldfld_hash = NULL; 
3018         char *name;
3019         int t, pos0, pos1 = 0;
3020
3021         t = type->type;
3022
3023         if (!type->byref) {
3024                 if (type->type == MONO_TYPE_SZARRAY) {
3025                         klass = mono_defaults.array_class;
3026                 } else if (type->type == MONO_TYPE_VALUETYPE) {
3027                         klass = type->data.klass;
3028                         if (klass->enumtype) {
3029                                 t = klass->enum_basetype->type;
3030                                 klass = mono_class_from_mono_type (klass->enum_basetype);
3031                         }
3032                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
3033                            t == MONO_TYPE_CLASS) { 
3034                         klass = mono_defaults.object_class;
3035                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
3036                         klass = mono_defaults.int_class;
3037                 } else {
3038                         klass = mono_class_from_mono_type (type);                       
3039                 }
3040         } else {
3041                 klass = mono_defaults.int_class;
3042         }
3043
3044         EnterCriticalSection (&marshal_mutex);
3045         if (!ldfld_hash) 
3046                 ldfld_hash = g_hash_table_new (NULL, NULL);
3047         res = g_hash_table_lookup (ldfld_hash, klass);
3048         LeaveCriticalSection (&marshal_mutex);
3049         if (res)
3050                 return res;
3051
3052         name = g_strdup_printf ("__ldfld_wrapper_%s.%s", klass->name_space, klass->name); 
3053         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
3054         g_free (name);
3055
3056         mb->method->save_lmf = 1;
3057
3058         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
3059         sig->params [0] = &mono_defaults.object_class->byval_arg;
3060         sig->params [1] = &mono_defaults.int_class->byval_arg;
3061         sig->params [2] = &mono_defaults.int_class->byval_arg;
3062         sig->params [3] = &mono_defaults.int_class->byval_arg;
3063         sig->ret = &klass->byval_arg;
3064
3065         mono_mb_emit_ldarg (mb, 0);
3066         pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3067
3068         mono_mb_emit_ldarg (mb, 0);
3069         mono_mb_emit_ldarg (mb, 1);
3070         mono_mb_emit_ldarg (mb, 2);
3071
3072         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
3073         csig->params [0] = &mono_defaults.object_class->byval_arg;
3074         csig->params [1] = &mono_defaults.int_class->byval_arg;
3075         csig->params [2] = &mono_defaults.int_class->byval_arg;
3076         csig->ret = &klass->this_arg;
3077         csig->pinvoke = 1;
3078
3079         mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
3080         emit_thread_interrupt_checkpoint (mb);
3081
3082         if (klass->valuetype) {
3083                 mono_mb_emit_byte (mb, CEE_UNBOX);
3084                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));             
3085                 mono_mb_emit_byte (mb, CEE_BR);
3086                 pos1 = mb->pos;
3087                 mono_mb_emit_i4 (mb, 0);
3088         } else {
3089                 mono_mb_emit_byte (mb, CEE_RET);
3090         }
3091
3092
3093         mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
3094
3095         mono_mb_emit_ldarg (mb, 0);
3096         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3097         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3098         mono_mb_emit_ldarg (mb, 3);
3099         mono_mb_emit_byte (mb, CEE_ADD);
3100
3101         if (klass->valuetype)
3102                 mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
3103
3104         switch (t) {
3105         case MONO_TYPE_I1:
3106         case MONO_TYPE_U1:
3107         case MONO_TYPE_BOOLEAN:
3108                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
3109                 break;
3110         case MONO_TYPE_CHAR:
3111         case MONO_TYPE_I2:
3112         case MONO_TYPE_U2:
3113                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
3114                 break;
3115         case MONO_TYPE_I4:
3116         case MONO_TYPE_U4:
3117                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3118                 break;
3119         case MONO_TYPE_I8:
3120         case MONO_TYPE_U8:
3121                 mono_mb_emit_byte (mb, CEE_LDIND_I8);
3122                 break;
3123         case MONO_TYPE_R4:
3124                 mono_mb_emit_byte (mb, CEE_LDIND_R4);
3125                 break;
3126         case MONO_TYPE_R8:
3127                 mono_mb_emit_byte (mb, CEE_LDIND_R8);
3128                 break;
3129         case MONO_TYPE_ARRAY:
3130         case MONO_TYPE_PTR:
3131         case MONO_TYPE_FNPTR:
3132         case MONO_TYPE_SZARRAY:
3133         case MONO_TYPE_OBJECT:
3134         case MONO_TYPE_CLASS:
3135         case MONO_TYPE_STRING:
3136         case MONO_TYPE_I:
3137         case MONO_TYPE_U:
3138                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3139                 break;
3140         case MONO_TYPE_VALUETYPE:
3141                 g_assert (!klass->enumtype);
3142                 mono_mb_emit_byte (mb, CEE_LDOBJ);
3143                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3144                 break;
3145         default:
3146                 g_warning ("type %x not implemented", type->type);
3147                 g_assert_not_reached ();
3148         }
3149
3150         mono_mb_emit_byte (mb, CEE_RET);
3151        
3152         res = mono_mb_create_and_cache (ldfld_hash, klass,
3153                                                                                  mb, sig, sig->param_count + 16);
3154         mono_mb_free (mb);
3155         
3156         return res;
3157 }
3158
3159 /*
3160  * mono_marshal_get_stfld_wrapper:
3161  * @type: the type of the field
3162  *
3163  * This method generates a function which can be use to store a field with type
3164  * @type. The generated function has the following signature:
3165  * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
3166  */
3167 MonoMethod *
3168 mono_marshal_get_stfld_wrapper (MonoType *type)
3169 {
3170         MonoMethodSignature *sig, *csig;
3171         MonoMethodBuilder *mb;
3172         MonoMethod *res;
3173         MonoClass *klass;
3174         static GHashTable *stfld_hash = NULL; 
3175         char *name;
3176         int t, pos;
3177
3178         t = type->type;
3179
3180         if (!type->byref) {
3181                 if (type->type == MONO_TYPE_SZARRAY) {
3182                         klass = mono_defaults.array_class;
3183                 } else if (type->type == MONO_TYPE_VALUETYPE) {
3184                         klass = type->data.klass;
3185                         if (klass->enumtype) {
3186                                 t = klass->enum_basetype->type;
3187                                 klass = mono_class_from_mono_type (klass->enum_basetype);
3188                         }
3189                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
3190                            t == MONO_TYPE_CLASS) { 
3191                         klass = mono_defaults.object_class;
3192                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
3193                         klass = mono_defaults.int_class;
3194                 } else {
3195                         klass = mono_class_from_mono_type (type);                       
3196                 }
3197         } else {
3198                 klass = mono_defaults.int_class;
3199         }
3200
3201         EnterCriticalSection (&marshal_mutex);
3202         if (!stfld_hash) 
3203                 stfld_hash = g_hash_table_new (NULL, NULL);
3204         res = g_hash_table_lookup (stfld_hash, klass);
3205         LeaveCriticalSection (&marshal_mutex);
3206         if (res)
3207                 return res;
3208
3209         name = g_strdup_printf ("__stfld_wrapper_%s.%s", klass->name_space, klass->name); 
3210         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
3211         g_free (name);
3212
3213         mb->method->save_lmf = 1;
3214
3215         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
3216         sig->params [0] = &mono_defaults.object_class->byval_arg;
3217         sig->params [1] = &mono_defaults.int_class->byval_arg;
3218         sig->params [2] = &mono_defaults.int_class->byval_arg;
3219         sig->params [3] = &mono_defaults.int_class->byval_arg;
3220         sig->params [4] = &klass->byval_arg;
3221         sig->ret = &mono_defaults.void_class->byval_arg;
3222
3223         mono_mb_emit_ldarg (mb, 0);
3224         pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
3225
3226         mono_mb_emit_ldarg (mb, 0);
3227         mono_mb_emit_ldarg (mb, 1);
3228         mono_mb_emit_ldarg (mb, 2);
3229         mono_mb_emit_ldarg (mb, 4);
3230
3231         if (klass->valuetype) {
3232                 mono_mb_emit_byte (mb, CEE_BOX);
3233                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));             
3234         }
3235
3236         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
3237         csig->params [0] = &mono_defaults.object_class->byval_arg;
3238         csig->params [1] = &mono_defaults.int_class->byval_arg;
3239         csig->params [2] = &mono_defaults.int_class->byval_arg;
3240         csig->params [3] = &klass->this_arg;
3241         csig->ret = &mono_defaults.void_class->byval_arg;
3242         csig->pinvoke = 1;
3243
3244         mono_mb_emit_native_call (mb, csig, mono_store_remote_field_new);
3245         emit_thread_interrupt_checkpoint (mb);
3246
3247         mono_mb_emit_byte (mb, CEE_RET);
3248
3249         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3250
3251         mono_mb_emit_ldarg (mb, 0);
3252         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3253         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3254         mono_mb_emit_ldarg (mb, 3);
3255         mono_mb_emit_byte (mb, CEE_ADD);
3256         mono_mb_emit_ldarg (mb, 4);
3257
3258         switch (t) {
3259         case MONO_TYPE_I1:
3260         case MONO_TYPE_U1:
3261         case MONO_TYPE_BOOLEAN:
3262                 mono_mb_emit_byte (mb, CEE_STIND_I1);
3263                 break;
3264         case MONO_TYPE_CHAR:
3265         case MONO_TYPE_I2:
3266         case MONO_TYPE_U2:
3267                 mono_mb_emit_byte (mb, CEE_STIND_I2);
3268                 break;
3269         case MONO_TYPE_I4:
3270         case MONO_TYPE_U4:
3271                 mono_mb_emit_byte (mb, CEE_STIND_I4);
3272                 break;
3273         case MONO_TYPE_I8:
3274         case MONO_TYPE_U8:
3275                 mono_mb_emit_byte (mb, CEE_STIND_I8);
3276                 break;
3277         case MONO_TYPE_R4:
3278                 mono_mb_emit_byte (mb, CEE_STIND_R4);
3279                 break;
3280         case MONO_TYPE_R8:
3281                 mono_mb_emit_byte (mb, CEE_STIND_R8);
3282                 break;
3283         case MONO_TYPE_ARRAY:
3284         case MONO_TYPE_PTR:
3285         case MONO_TYPE_FNPTR:
3286         case MONO_TYPE_SZARRAY:
3287         case MONO_TYPE_OBJECT:
3288         case MONO_TYPE_CLASS:
3289         case MONO_TYPE_STRING:
3290         case MONO_TYPE_I:
3291         case MONO_TYPE_U:
3292                 mono_mb_emit_byte (mb, CEE_STIND_I);
3293                 break;
3294         case MONO_TYPE_VALUETYPE:
3295                 g_assert (!klass->enumtype);
3296                 mono_mb_emit_byte (mb, CEE_STOBJ);
3297                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3298                 break;
3299         default:
3300                 g_warning ("type %x not implemented", type->type);
3301                 g_assert_not_reached ();
3302         }
3303
3304         mono_mb_emit_byte (mb, CEE_RET);
3305        
3306         res = mono_mb_create_and_cache (stfld_hash, klass,
3307                                                                         mb, sig, sig->param_count + 16);
3308         mono_mb_free (mb);
3309         
3310         return res;
3311 }
3312
3313 /*
3314  * generates IL code for the icall wrapper (the generated method
3315  * calls the unmanaged code in func)
3316  */
3317 MonoMethod *
3318 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func)
3319 {
3320         MonoMethodSignature *csig;
3321         MonoMethodBuilder *mb;
3322         MonoMethod *res;
3323         int i;
3324         
3325         g_assert (sig->pinvoke);
3326
3327         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
3328
3329         mb->method->save_lmf = 1;
3330
3331         /* we copy the signature, so that we can modify it */
3332
3333         if (sig->hasthis)
3334                 mono_mb_emit_byte (mb, CEE_LDARG_0);
3335
3336         for (i = 0; i < sig->param_count; i++)
3337                 mono_mb_emit_ldarg (mb, i + sig->hasthis);
3338
3339         mono_mb_emit_native_call (mb, sig, (gpointer) func);
3340         emit_thread_interrupt_checkpoint (mb);
3341         mono_mb_emit_byte (mb, CEE_RET);
3342
3343         csig = mono_metadata_signature_dup (sig);
3344         csig->pinvoke = 0;
3345         if (csig->call_convention == MONO_CALL_VARARG)
3346                 csig->call_convention = 0;
3347
3348         res = mono_mb_create_method (mb, csig, csig->param_count + 16);
3349         mono_mb_free (mb);
3350         
3351         return res;
3352 }
3353
3354 typedef struct {
3355         MonoMethodBuilder *mb;
3356         MonoMethodPInvoke *piinfo;
3357 } EmitMarshalContext;
3358
3359 typedef enum {
3360         MARSHAL_ACTION_CONV_IN,
3361         MARSHAL_ACTION_PUSH,
3362         MARSHAL_ACTION_CONV_OUT,
3363         MARSHAL_ACTION_CONV_RESULT
3364 } MarshalAction;
3365
3366 static int
3367 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
3368                                          MonoMarshalSpec *spec, 
3369                                          int conv_arg, MonoType **conv_arg_type, 
3370                                          MarshalAction action)
3371 {
3372         MonoType *mtype;
3373         MonoClass *mklass;
3374         MonoMethod *get_instance, *cleanup_native;
3375         MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
3376         MonoMethodBuilder *mb = m->mb;
3377         guint32 loc1;
3378
3379         mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, mb->method->klass->image);
3380         g_assert (mtype != NULL);
3381         mklass = mono_class_from_mono_type (mtype);
3382         g_assert (mklass != NULL);
3383
3384         get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
3385         g_assert (get_instance);
3386         cleanup_native = mono_find_method_by_name (mklass, "CleanUpNativeData", 1);
3387         g_assert (cleanup_native);
3388         marshal_managed_to_native = mono_find_method_by_name (mklass, "MarshalManagedToNative", 1);
3389         g_assert (marshal_managed_to_native);
3390         marshal_native_to_managed = mono_find_method_by_name (mklass, "MarshalNativeToManaged", 1);
3391         g_assert (marshal_native_to_managed);
3392
3393         switch (action) {
3394         case MARSHAL_ACTION_CONV_IN:
3395                 switch (t->type) {
3396                 case MONO_TYPE_CLASS:
3397                 case MONO_TYPE_OBJECT:
3398                 case MONO_TYPE_STRING:
3399                 case MONO_TYPE_ARRAY:
3400                 case MONO_TYPE_SZARRAY:
3401                 case MONO_TYPE_VALUETYPE:
3402                         if (t->byref)
3403                                 break;
3404
3405                         conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3406
3407                         mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
3408
3409                         mono_mb_emit_byte (mb, CEE_CALL);
3410                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3411                                 
3412                         mono_mb_emit_ldarg (mb, argnum);
3413
3414                         if (t->type == MONO_TYPE_VALUETYPE) {
3415                                 /*
3416                                  * Since we can't determine the type of the argument, we
3417                                  * will assume the unmanaged function takes a pointer.
3418                                  */
3419                                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3420
3421                                 mono_mb_emit_byte (mb, CEE_BOX);
3422                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (t)));
3423                         }
3424
3425                         mono_mb_emit_byte (mb, CEE_CALLVIRT);
3426                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native));
3427                         mono_mb_emit_stloc (mb, conv_arg);
3428                         break;
3429
3430                 default:
3431                         g_warning ("custom marshalling of type %x is currently not supported", t->type);
3432                         g_assert_not_reached ();
3433                         break;
3434                 }
3435                 
3436                 break;
3437
3438         case MARSHAL_ACTION_CONV_OUT:
3439                 switch (t->type) {
3440                 case MONO_TYPE_CLASS:
3441                 case MONO_TYPE_OBJECT:
3442                 case MONO_TYPE_STRING:
3443                 case MONO_TYPE_ARRAY:
3444                 case MONO_TYPE_SZARRAY:
3445                 case MONO_TYPE_VALUETYPE:
3446                         mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
3447                         
3448                         mono_mb_emit_byte (mb, CEE_CALL);
3449                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3450                                 
3451                         mono_mb_emit_ldloc (mb, conv_arg);
3452
3453                         mono_mb_emit_byte (mb, CEE_CALLVIRT);
3454                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native));
3455
3456                         break;
3457
3458                 default:
3459                         g_warning ("custom marshalling of type %x is currently not supported", t->type);
3460                         g_assert_not_reached ();
3461                         break;
3462                 }
3463                 break;
3464
3465         case MARSHAL_ACTION_PUSH:
3466                 mono_mb_emit_ldloc (mb, conv_arg);
3467                 break;
3468
3469         case MARSHAL_ACTION_CONV_RESULT:
3470                 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3471                         
3472                 switch (t->type) {
3473                 case MONO_TYPE_CLASS:
3474                 case MONO_TYPE_OBJECT:
3475                 case MONO_TYPE_STRING:
3476                 case MONO_TYPE_ARRAY:
3477                 case MONO_TYPE_SZARRAY:
3478                         mono_mb_emit_byte (mb, CEE_STLOC_3);
3479
3480                         mono_mb_emit_byte (mb, CEE_LDLOC_3);
3481                         mono_mb_emit_stloc (mb, loc1);
3482
3483                         mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
3484
3485                         mono_mb_emit_byte (mb, CEE_CALL);
3486                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
3487                         mono_mb_emit_byte (mb, CEE_DUP);
3488
3489                         mono_mb_emit_byte (mb, CEE_LDLOC_3);
3490                         mono_mb_emit_byte (mb, CEE_CALLVIRT);
3491                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
3492                         mono_mb_emit_byte (mb, CEE_STLOC_3);
3493
3494                         mono_mb_emit_ldloc (mb, loc1);
3495                         mono_mb_emit_byte (mb, CEE_CALLVIRT);
3496                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native));
3497
3498                         break;
3499                 default:
3500                         g_assert_not_reached ();
3501                         break;
3502                 }
3503                 break;
3504
3505         default:
3506                 g_assert_not_reached ();
3507         }
3508                 
3509         return conv_arg;
3510 }
3511
3512 static int
3513 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
3514                                         MonoMarshalSpec *spec, 
3515                                         int conv_arg, MonoType **conv_arg_type, 
3516                                         MarshalAction action)
3517 {
3518         MonoMethodBuilder *mb = m->mb;
3519
3520         switch (action) {
3521         case MARSHAL_ACTION_CONV_IN: {
3522                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
3523
3524                 g_assert (t->type == MONO_TYPE_OBJECT);
3525                 g_assert (!t->byref);
3526
3527                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3528                 mono_mb_emit_ldarg (mb, argnum);
3529                 mono_mb_emit_icon (mb, encoding);
3530                 mono_mb_emit_icall (mb, mono_marshal_asany);
3531                 mono_mb_emit_stloc (mb, conv_arg);
3532                 break;
3533         }
3534
3535         case MARSHAL_ACTION_PUSH:
3536                 mono_mb_emit_ldloc (mb, conv_arg);
3537                 break;
3538
3539         case MARSHAL_ACTION_CONV_OUT: {
3540                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
3541
3542                 mono_mb_emit_ldarg (mb, argnum);
3543                 mono_mb_emit_ldloc (mb, conv_arg);
3544                 mono_mb_emit_icon (mb, encoding);
3545                 mono_mb_emit_icall (mb, mono_marshal_free_asany);
3546                 break;
3547         }
3548
3549         default:
3550                 g_assert_not_reached ();
3551         }
3552
3553         return conv_arg;
3554 }
3555
3556 static int
3557 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
3558                                         MonoMarshalSpec *spec, 
3559                                         int conv_arg, MonoType **conv_arg_type, 
3560                                         MarshalAction action)
3561 {
3562         MonoMethodBuilder *mb = m->mb;
3563         MonoClass *klass;
3564         int pos;
3565
3566         klass = t->data.klass;
3567
3568         switch (action) {
3569         case MARSHAL_ACTION_CONV_IN:
3570                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3571                         klass->blittable || klass->enumtype)
3572                         break;
3573
3574                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3575                         
3576                 /* store the address of the source into local variable 0 */
3577                 if (t->byref)
3578                         mono_mb_emit_ldarg (mb, argnum);
3579                 else
3580                         mono_mb_emit_ldarg_addr (mb, argnum);
3581                 
3582                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3583                         
3584                 /* allocate space for the native struct and
3585                  * store the address into local variable 1 (dest) */
3586                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
3587                 mono_mb_emit_byte (mb, CEE_PREFIX1);
3588                 mono_mb_emit_byte (mb, CEE_LOCALLOC);
3589                 mono_mb_emit_stloc (mb, conv_arg);
3590
3591                 if (t->byref) {
3592                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
3593                         mono_mb_emit_byte (mb, CEE_BRFALSE);
3594                         pos = mb->pos;
3595                         mono_mb_emit_i4 (mb, 0);
3596                 }
3597
3598                 /* set dst_ptr */
3599                 mono_mb_emit_ldloc (mb, conv_arg);
3600                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3601
3602                 /* emit valuetype conversion code */
3603                 emit_struct_conv (mb, klass, FALSE);
3604                         
3605                 if (t->byref)
3606                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3607                 break;
3608
3609         case MARSHAL_ACTION_PUSH:
3610                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3611                         klass->blittable || klass->enumtype) {
3612                         mono_mb_emit_ldarg (mb, argnum);
3613                         break;
3614                 }                       
3615                 mono_mb_emit_ldloc (mb, conv_arg);
3616                 if (!t->byref) {
3617                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3618                         mono_mb_emit_byte (mb, CEE_MONO_LDNATIVEOBJ);
3619                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3620                 }
3621                 break;
3622
3623         case MARSHAL_ACTION_CONV_OUT:
3624                 if (!t->byref)
3625                         break;
3626         
3627                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3628                         klass->blittable || klass->enumtype)
3629                         break;
3630
3631                 /* dst = argument */
3632                 mono_mb_emit_ldarg (mb, argnum);
3633                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3634
3635                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
3636                 mono_mb_emit_byte (mb, CEE_BRFALSE);
3637                 pos = mb->pos;
3638                 mono_mb_emit_i4 (mb, 0);
3639
3640                 /* src = tmp_locals [i] */
3641                 mono_mb_emit_ldloc (mb, conv_arg);
3642                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3643
3644                 /* emit valuetype conversion code */
3645                 emit_struct_conv (mb, klass, TRUE);
3646                         
3647                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3648                 break;
3649
3650         case MARSHAL_ACTION_CONV_RESULT:
3651                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
3652                         klass->blittable) {
3653                         mono_mb_emit_byte (mb, CEE_STLOC_3);
3654                         break;
3655                 }
3656                 /* load pointer to returned value type */
3657                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3658                 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
3659                 /* store the address of the source into local variable 0 */
3660                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3661                 /* set dst_ptr */
3662                 mono_mb_emit_ldloc_addr (mb, 3);
3663                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3664                                 
3665                 /* emit valuetype conversion code */
3666                 emit_struct_conv (mb, klass, TRUE);
3667                 break;
3668
3669         default:
3670                 g_assert_not_reached ();
3671         }
3672
3673         return conv_arg;
3674 }
3675
3676 static int
3677 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
3678                                          MonoMarshalSpec *spec, 
3679                                          int conv_arg, MonoType **conv_arg_type, 
3680                                          MarshalAction action)
3681 {
3682         MonoMethodBuilder *mb = m->mb;
3683         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
3684
3685         switch (action) {
3686         case MARSHAL_ACTION_CONV_IN:
3687                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3688                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3689
3690                 if (t->byref) {
3691                         if (t->attrs & PARAM_ATTRIBUTE_OUT)
3692                                 break;
3693
3694                         mono_mb_emit_ldarg (mb, argnum);
3695                         mono_mb_emit_byte (mb, CEE_LDIND_I);                            
3696                 } else {
3697                         mono_mb_emit_ldarg (mb, argnum);
3698                 }
3699
3700                 switch (encoding) {
3701                 case MONO_NATIVE_LPWSTR:
3702                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPWSTR));
3703                         break;
3704                 case MONO_NATIVE_LPSTR:
3705                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPSTR));
3706                         break;
3707                 case MONO_NATIVE_LPTSTR:
3708                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPTSTR));
3709                         break;
3710                 default: {
3711                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
3712                         MonoException *exc = mono_get_exception_not_implemented (msg);
3713                         g_warning (msg);
3714                         g_free (msg);
3715                         mono_raise_exception (exc);
3716                 }
3717                 }
3718
3719                 mono_mb_emit_stloc (mb, conv_arg);
3720                 break;
3721
3722         case MARSHAL_ACTION_CONV_OUT:
3723                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
3724                         mono_mb_emit_ldarg (mb, argnum);
3725                         mono_mb_emit_ldloc (mb, conv_arg);
3726                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
3727                         mono_mb_emit_byte (mb, CEE_STIND_I);            
3728                 } else {
3729                         mono_mb_emit_ldloc (mb, conv_arg);
3730                         mono_mb_emit_icall (mb, g_free);
3731                 }
3732                 break;
3733
3734         case MARSHAL_ACTION_CONV_RESULT:
3735                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3736                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3737                                 
3738                 if (spec) {
3739                         switch (spec->native) {
3740                         case MONO_NATIVE_LPWSTR:
3741                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPWSTR_STR));
3742                                 break;
3743                         default:
3744                                 g_warning ("marshalling conversion not implemented");
3745                                 g_assert_not_reached ();
3746                         }
3747                 } else {
3748                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
3749                 }
3750                 mono_mb_emit_byte (mb, CEE_STLOC_3);
3751
3752                 /* free the string */
3753                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3754                 mono_mb_emit_icall (mb, g_free);
3755                 break;
3756
3757         default:
3758                 g_assert_not_reached ();
3759         }
3760
3761         return conv_arg;
3762 }
3763
3764 static int
3765 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
3766                                          MonoMarshalSpec *spec, 
3767                                          int conv_arg, MonoType **conv_arg_type, 
3768                                          MarshalAction action)
3769 {
3770         MonoMethodBuilder *mb = m->mb;
3771         MonoClass *klass = t->data.klass;
3772         int pos;
3773
3774         switch (action) {
3775         case MARSHAL_ACTION_CONV_IN:
3776                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3777                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3778
3779                 if (klass->delegate) {
3780                         g_assert (!t->byref);
3781                         mono_mb_emit_ldarg (mb, argnum);
3782                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
3783                         mono_mb_emit_stloc (mb, conv_arg);
3784                 } else if (klass == mono_defaults.stringbuilder_class) {
3785                         MonoMarshalNative encoding = mono_marshal_get_stringbuilder_to_ptr_encoding (m->piinfo, spec);
3786                         
3787                         g_assert (!t->byref);
3788                         mono_mb_emit_ldarg (mb, argnum);
3789
3790                         if (encoding != -1)
3791                                 mono_mb_emit_icall (mb, conv_to_icall (encoding));
3792                         else {
3793                                 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
3794                                 MonoException *exc = mono_get_exception_not_implemented (msg);
3795                                 g_warning (msg);
3796                                 g_free (msg);
3797                                 mono_raise_exception (exc);
3798                         }
3799
3800                         mono_mb_emit_stloc (mb, conv_arg);
3801                 } else if (klass->blittable) {
3802                         mono_mb_emit_ldarg (mb, argnum);
3803                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3804                         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3805                         mono_mb_emit_icon (mb, sizeof (MonoObject));
3806                         mono_mb_emit_byte (mb, CEE_ADD);
3807                         mono_mb_emit_stloc (mb, conv_arg);
3808                         break;
3809                 } else {
3810                         mono_mb_emit_byte (mb, CEE_LDNULL);
3811                         mono_mb_emit_stloc (mb, conv_arg);
3812
3813                         if (t->byref) {
3814                                 /* we dont need any conversions for out parameters */
3815                                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
3816                                         break;
3817
3818                                 mono_mb_emit_ldarg (mb, argnum);                                
3819                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3820
3821                         } else {
3822                                 mono_mb_emit_ldarg (mb, argnum);
3823                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3824                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3825                         }
3826                                 
3827                         /* store the address of the source into local variable 0 */
3828                         mono_mb_emit_byte (mb, CEE_STLOC_0);
3829                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
3830                         mono_mb_emit_byte (mb, CEE_BRFALSE);
3831                         pos = mb->pos;
3832                         mono_mb_emit_i4 (mb, 0);
3833
3834                         /* allocate space for the native struct and store the address */
3835                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
3836                         mono_mb_emit_byte (mb, CEE_PREFIX1);
3837                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
3838                         mono_mb_emit_stloc (mb, conv_arg);
3839                                 
3840                         /* set the src_ptr */
3841                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
3842                         mono_mb_emit_icon (mb, sizeof (MonoObject));
3843                         mono_mb_emit_byte (mb, CEE_ADD);
3844                         mono_mb_emit_byte (mb, CEE_STLOC_0);
3845
3846                         /* set dst_ptr */
3847                         mono_mb_emit_ldloc (mb, conv_arg);
3848                         mono_mb_emit_byte (mb, CEE_STLOC_1);
3849
3850                         /* emit valuetype conversion code */
3851                         emit_struct_conv (mb, klass, FALSE);
3852
3853                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3854                 }
3855                 break;
3856
3857         case MARSHAL_ACTION_CONV_OUT:
3858                 if (klass == mono_defaults.stringbuilder_class) {
3859                         gboolean need_free;
3860                         MonoMarshalNative encoding;
3861
3862                         encoding = mono_marshal_get_ptr_to_stringbuilder_encoding (m->piinfo, spec, &need_free);
3863
3864                         g_assert (!t->byref);
3865                         g_assert (encoding != -1);
3866
3867                         mono_mb_emit_ldarg (mb, argnum);
3868                         mono_mb_emit_ldloc (mb, conv_arg);
3869
3870                         mono_mb_emit_icall (mb, conv_to_icall (encoding));
3871
3872                         if (need_free) {
3873                                 mono_mb_emit_ldloc (mb, conv_arg);
3874                                 mono_mb_emit_icall (mb, g_free);
3875                         }
3876                         break;
3877                 }
3878                         
3879                 if (!(t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)))
3880                         break;
3881
3882                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
3883                         /* allocate a new object */
3884                         mono_mb_emit_ldarg (mb, argnum);
3885                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3886                         mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
3887                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
3888                         mono_mb_emit_byte (mb, CEE_STIND_I);
3889                 }
3890
3891                 /* dst = *argument */
3892                 mono_mb_emit_ldarg (mb, argnum);
3893
3894                 if (t->byref)
3895                         mono_mb_emit_byte (mb, CEE_LDIND_I);
3896
3897                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3898
3899                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
3900                 mono_mb_emit_byte (mb, CEE_BRFALSE);
3901                 pos = mb->pos;
3902                 mono_mb_emit_i4 (mb, 0);
3903
3904                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
3905                 mono_mb_emit_icon (mb, sizeof (MonoObject));
3906                 mono_mb_emit_byte (mb, CEE_ADD);
3907                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3908                         
3909                 /* src = tmp_locals [i] */
3910                 mono_mb_emit_ldloc (mb, conv_arg);
3911                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3912
3913                 /* emit valuetype conversion code */
3914                 emit_struct_conv (mb, t->data.klass, TRUE);
3915
3916                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3917                 break;
3918
3919         case MARSHAL_ACTION_CONV_RESULT:
3920                 /* set src */
3921                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3922
3923                 mono_mb_emit_byte (mb, CEE_LDNULL);
3924                 mono_mb_emit_byte (mb, CEE_STLOC_3);
3925
3926                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
3927                 mono_mb_emit_byte (mb, CEE_BRFALSE);
3928                 pos = mb->pos;
3929                 mono_mb_emit_i4 (mb, 0);
3930
3931                 /* allocate result object */
3932
3933                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3934                 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
3935                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
3936                 mono_mb_emit_byte (mb, CEE_STLOC_3);
3937                                 
3938                 /* set dst  */
3939
3940                 mono_mb_emit_byte (mb, CEE_LDLOC_3);
3941                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3942                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3943                 mono_mb_emit_icon (mb, sizeof (MonoObject));
3944                 mono_mb_emit_byte (mb, CEE_ADD);
3945                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3946                                                         
3947                 /* emit conversion code */
3948                 emit_struct_conv (mb, klass, TRUE);
3949
3950                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3951                 break;
3952
3953         default:
3954                 g_assert_not_reached ();
3955         }
3956
3957         return conv_arg;
3958 }
3959
3960 static int
3961 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
3962                                         MonoMarshalSpec *spec, 
3963                                         int conv_arg, MonoType **conv_arg_type, 
3964                                         MarshalAction action)
3965 {
3966         MonoMethodBuilder *mb = m->mb;
3967         MonoClass *klass = mono_class_from_mono_type (t);
3968         int pos;
3969
3970         switch (action) {
3971         case MARSHAL_ACTION_CONV_IN:
3972                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3973                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3974
3975                 if (klass->element_class == mono_defaults.string_class) {
3976                         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
3977
3978                         mono_mb_emit_ldarg (mb, argnum);
3979                         if (t->byref)
3980                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3981
3982                         switch (encoding) {
3983                         case MONO_NATIVE_LPSTR:
3984                                 mono_mb_emit_icall (mb, mono_marshal_string_array);
3985                                 break;
3986                         case MONO_NATIVE_LPWSTR:
3987                                 mono_mb_emit_icall (mb, mono_marshal_string_array_to_unicode);
3988                                 break;
3989                         default: {
3990                                 char *msg = g_strdup_printf ("string array marshalling conversion %d not implemented", encoding);
3991                                 MonoException *exc = mono_get_exception_not_implemented (msg);
3992                                 g_warning (msg);
3993                                 g_free (msg);
3994                                 mono_raise_exception (exc);
3995                         }
3996                         }
3997                         mono_mb_emit_stloc (mb, conv_arg);
3998                 }
3999                 else if (klass->element_class->blittable) {
4000                         mono_mb_emit_ldarg (mb, argnum);
4001                         if (t->byref)
4002                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4003                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
4004                         mono_mb_emit_stloc (mb, conv_arg);
4005                 }
4006                 else {
4007                         MonoClass *eklass;
4008                         guint32 label1, label2, label3;
4009                         int index_var, src_var, dest_ptr, esize;
4010                         MonoMarshalNative encoding = mono_marshal_get_stringbuilder_to_ptr_encoding (m->piinfo, spec);
4011
4012                         dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4013
4014                         eklass = klass->element_class;
4015
4016                         src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4017                         mono_mb_emit_ldarg (mb, argnum);
4018                         if (t->byref)
4019                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4020                         mono_mb_emit_stloc (mb, src_var);
4021
4022                         /* Check null */
4023                         mono_mb_emit_ldloc (mb, src_var);
4024                         mono_mb_emit_stloc (mb, conv_arg);
4025                         mono_mb_emit_ldloc (mb, src_var);
4026                         mono_mb_emit_byte (mb, CEE_BRFALSE);
4027                         label1 = mb->pos;
4028                         mono_mb_emit_i4 (mb, 0);
4029
4030                         if (eklass == mono_defaults.stringbuilder_class) {
4031                                 if (encoding == -1) {
4032                                         char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
4033                                         MonoException *exc = mono_get_exception_not_implemented (msg);
4034                                         g_warning (msg);
4035                                         g_free (msg);
4036                                         mono_raise_exception (exc);
4037                                 }
4038                         }
4039
4040                         if (eklass == mono_defaults.stringbuilder_class)
4041                                 esize = sizeof (gpointer);
4042                         else
4043                                 esize = mono_class_native_size (eklass, NULL);
4044
4045                         /* allocate space for the native struct and store the address */
4046                         mono_mb_emit_icon (mb, esize);
4047                         mono_mb_emit_ldloc (mb, src_var);
4048                         mono_mb_emit_byte (mb, CEE_LDLEN);
4049                         mono_mb_emit_byte (mb, CEE_MUL);
4050                         mono_mb_emit_byte (mb, CEE_PREFIX1);
4051                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
4052                         mono_mb_emit_stloc (mb, conv_arg);
4053
4054                         mono_mb_emit_ldloc (mb, conv_arg);
4055                         mono_mb_emit_stloc (mb, dest_ptr);
4056
4057                         /* Emit marshalling loop */
4058                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
4059                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4060                         mono_mb_emit_stloc (mb, index_var);
4061                         label2 = mb->pos;
4062                         mono_mb_emit_ldloc (mb, index_var);
4063                         mono_mb_emit_ldloc (mb, src_var);
4064                         mono_mb_emit_byte (mb, CEE_LDLEN);
4065                         mono_mb_emit_byte (mb, CEE_BGE);
4066                         label3 = mb->pos;
4067                         mono_mb_emit_i4 (mb, 0);
4068
4069                         /* Emit marshalling code */
4070
4071                         if (eklass == mono_defaults.stringbuilder_class) {
4072                                 mono_mb_emit_ldloc (mb, dest_ptr);
4073                                 mono_mb_emit_ldloc (mb, src_var);
4074                                 mono_mb_emit_ldloc (mb, index_var);
4075                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4076                                 mono_mb_emit_icall (mb, conv_to_icall (encoding));
4077                                 mono_mb_emit_byte (mb, CEE_STIND_I);
4078                         }
4079                         else {
4080                                 /* set the src_ptr */
4081                                 mono_mb_emit_ldloc (mb, src_var);
4082                                 mono_mb_emit_ldloc (mb, index_var);
4083                                 mono_mb_emit_byte (mb, CEE_LDELEMA);
4084                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
4085                                 mono_mb_emit_byte (mb, CEE_STLOC_0);
4086
4087                                 /* set dst_ptr */
4088                                 mono_mb_emit_ldloc (mb, dest_ptr);
4089                                 mono_mb_emit_byte (mb, CEE_STLOC_1);
4090
4091                                 /* emit valuetype conversion code */
4092                                 emit_struct_conv (mb, eklass, FALSE);
4093                         }
4094
4095                         mono_mb_emit_add_to_local (mb, index_var, 1);
4096                         mono_mb_emit_add_to_local (mb, dest_ptr, esize);
4097                         
4098                         mono_mb_emit_byte (mb, CEE_BR);
4099                         mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
4100
4101                         mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
4102                         mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
4103                 }
4104
4105                 break;
4106
4107         case MARSHAL_ACTION_CONV_OUT:
4108                 if (klass->element_class == mono_defaults.string_class) {
4109                         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
4110
4111                         mono_mb_emit_ldarg (mb, argnum);
4112                         if (t->byref)
4113                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4114                         mono_mb_emit_byte (mb, CEE_BRFALSE);
4115                         pos = mb->pos;
4116                         mono_mb_emit_i4 (mb, 0);
4117
4118                         mono_mb_emit_ldloc (mb, conv_arg);
4119
4120                         switch (encoding) {
4121                         case MONO_NATIVE_LPWSTR:
4122                                 /* 
4123                                  * The array elements point to the managed string data so 
4124                                  * they don't need to be freed.
4125                                  */
4126                                 mono_mb_emit_icall (mb, g_free);
4127                                 break;
4128                         default:
4129                                 mono_mb_emit_ldarg (mb, argnum);
4130                                 if (t->byref)
4131                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
4132                                 mono_mb_emit_byte (mb, CEE_LDLEN);                              
4133                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_ARRAY));
4134                                 break;                                  
4135                         }
4136
4137                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4138                 }
4139
4140                 if (t->byref)
4141                         /* 
4142                          * FIXME: Need to convert data back but we don't know the
4143                          * size of the array.
4144                          */
4145                         break;
4146
4147                 /* Character arrays are implicitly marshalled as [Out] */
4148                 if ((klass->element_class == mono_defaults.char_class) || (klass->element_class == mono_defaults.stringbuilder_class) || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4149                         /* FIXME: Optimize blittable case */
4150                         MonoClass *eklass;
4151                         guint32 label1, label2, label3;
4152                         int index_var, src_ptr, esize;
4153
4154                         eklass = klass->element_class;
4155                         if (eklass == mono_defaults.stringbuilder_class)
4156                                 esize = sizeof (gpointer);
4157                         else
4158                                 esize = mono_class_native_size (eklass, NULL);
4159                         src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4160
4161                         /* Check null */
4162                         mono_mb_emit_ldarg (mb, argnum);
4163                         mono_mb_emit_byte (mb, CEE_BRFALSE);
4164                         label1 = mb->pos;
4165                         mono_mb_emit_i4 (mb, 0);
4166
4167                         mono_mb_emit_ldloc (mb, conv_arg);
4168                         mono_mb_emit_stloc (mb, src_ptr);
4169
4170                         /* Emit marshalling loop */
4171                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
4172                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4173                         mono_mb_emit_stloc (mb, index_var);
4174                         label2 = mb->pos;
4175                         mono_mb_emit_ldloc (mb, index_var);
4176                         mono_mb_emit_ldarg (mb, argnum);
4177                         mono_mb_emit_byte (mb, CEE_LDLEN);
4178                         mono_mb_emit_byte (mb, CEE_BGE);
4179                         label3 = mb->pos;
4180                         mono_mb_emit_i4 (mb, 0);
4181
4182                         /* Emit marshalling code */
4183
4184                         if (eklass == mono_defaults.stringbuilder_class) {
4185                                 gboolean need_free;
4186                                 MonoMarshalNative encoding = mono_marshal_get_ptr_to_stringbuilder_encoding (m->piinfo, spec, &need_free);
4187
4188                                 g_assert (encoding != -1);
4189
4190                                 /* dest */
4191                                 mono_mb_emit_ldarg (mb, argnum);
4192                                 mono_mb_emit_ldloc (mb, index_var);
4193                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4194
4195                                 /* src */
4196                                 mono_mb_emit_ldloc (mb, src_ptr);
4197                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4198
4199                                 mono_mb_emit_icall (mb, conv_to_icall (encoding));
4200
4201                                 if (need_free) {
4202                                         /* src */
4203                                         mono_mb_emit_ldloc (mb, src_ptr);
4204                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
4205
4206                                         mono_mb_emit_icall (mb, g_free);
4207                                 }
4208                         }
4209                         else {
4210                                 /* set the src_ptr */
4211                                 mono_mb_emit_ldloc (mb, src_ptr);
4212                                 mono_mb_emit_byte (mb, CEE_STLOC_0);
4213
4214                                 /* set dst_ptr */
4215                                 mono_mb_emit_ldarg (mb, argnum);
4216                                 mono_mb_emit_ldloc (mb, index_var);
4217                                 mono_mb_emit_byte (mb, CEE_LDELEMA);
4218                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
4219                                 mono_mb_emit_byte (mb, CEE_STLOC_1);
4220
4221                                 /* emit valuetype conversion code */
4222                                 emit_struct_conv (mb, eklass, TRUE);
4223                         }
4224
4225                         mono_mb_emit_add_to_local (mb, index_var, 1);
4226                         mono_mb_emit_add_to_local (mb, src_ptr, esize);
4227
4228                         mono_mb_emit_byte (mb, CEE_BR);
4229                         mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
4230
4231                         mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
4232                         mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
4233                 }
4234                 break;
4235
4236         case MARSHAL_ACTION_CONV_RESULT:
4237                 /* fixme: we need conversions here */
4238                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4239
4240         default:
4241                 g_assert_not_reached ();
4242         }
4243
4244         return conv_arg;
4245 }
4246
4247 static int
4248 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
4249                                           MonoMarshalSpec *spec, 
4250                                           int conv_arg, MonoType **conv_arg_type, 
4251                                           MarshalAction action)
4252 {
4253         MonoMethodBuilder *mb = m->mb;
4254
4255         switch (action) {
4256         case MARSHAL_ACTION_CONV_IN: {
4257                 MonoType *local_type;
4258                 int variant_bool = 0;
4259                 if (!t->byref)
4260                         break;
4261                 if (spec == NULL) {
4262                         local_type = &mono_defaults.int32_class->byval_arg;
4263                 } else {
4264                         switch (spec->native) {
4265                         case MONO_NATIVE_I1:
4266                                 local_type = &mono_defaults.byte_class->byval_arg;
4267                                 break;
4268                         case MONO_NATIVE_VARIANTBOOL:
4269                                 local_type = &mono_defaults.int16_class->byval_arg;
4270                                 variant_bool = 1;
4271                                 break;
4272                         default:
4273                                 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
4274                                 break;
4275                         }
4276                 }
4277                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4278                 conv_arg = mono_mb_add_local (mb, local_type);
4279                 mono_mb_emit_ldarg (mb, argnum);
4280                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
4281                 if (variant_bool)
4282                         mono_mb_emit_byte (mb, CEE_NEG);
4283                 mono_mb_emit_stloc (mb, conv_arg);
4284                 break;
4285         }
4286
4287         case MARSHAL_ACTION_CONV_RESULT:
4288                 /* maybe we need to make sure that it fits within 8 bits */
4289                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4290                 break;
4291
4292         default:
4293                 g_assert_not_reached ();
4294         }
4295
4296         return conv_arg;
4297 }
4298
4299 static int
4300 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, 
4301                           MonoMarshalSpec *spec, int conv_arg, 
4302                           MonoType **conv_arg_type, MarshalAction action)
4303 {
4304         /* Ensure that we have marshalling info for this param */
4305         mono_marshal_load_type_info (mono_class_from_mono_type (t));
4306
4307         if (spec && spec->native == MONO_NATIVE_CUSTOM)
4308                 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4309
4310         if (spec && spec->native == MONO_NATIVE_ASANY)
4311                 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4312                         
4313         switch (t->type) {
4314         case MONO_TYPE_VALUETYPE:
4315                 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4316         case MONO_TYPE_STRING:
4317                 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4318         case MONO_TYPE_CLASS:
4319         case MONO_TYPE_OBJECT:
4320                 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4321         case MONO_TYPE_ARRAY:
4322         case MONO_TYPE_SZARRAY:
4323                 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4324         case MONO_TYPE_BOOLEAN:
4325                 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
4326         }
4327
4328         return conv_arg;
4329 }
4330
4331 /**
4332  * mono_marshal_get_native_wrapper:
4333  * @method: The MonoMethod to wrap.
4334  *
4335  * generates IL code for the pinvoke wrapper (the generated method
4336  * calls the unmanaged code in method->addr)
4337  */
4338 MonoMethod *
4339 mono_marshal_get_native_wrapper (MonoMethod *method)
4340 {
4341         EmitMarshalContext m;
4342         MonoMethodSignature *sig, *csig;
4343         MonoMethodPInvoke *piinfo;
4344         MonoMethodBuilder *mb;
4345         MonoMarshalSpec **mspecs;
4346         MonoMethod *res;
4347         GHashTable *cache;
4348         MonoClass *klass;
4349         gboolean pinvoke = FALSE;
4350         int i, argnum, *tmp_locals;
4351         int type;
4352         const char *exc_class = "MissingMethodException";
4353         const char *exc_arg = NULL;
4354
4355         g_assert (method != NULL);
4356         g_assert (method->signature->pinvoke);
4357
4358         cache = method->klass->image->native_wrapper_cache;
4359         if ((res = mono_marshal_find_in_cache (cache, method)))
4360                 return res;
4361
4362         sig = method->signature;
4363
4364         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
4365             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
4366                 pinvoke = TRUE;
4367
4368         if (!method->addr) {
4369                 if (pinvoke)
4370                         mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
4371                 else
4372                         method->addr = mono_lookup_internal_call (method);
4373         }
4374
4375         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
4376
4377         mb->method->save_lmf = 1;
4378
4379         piinfo = (MonoMethodPInvoke *)method;
4380
4381         if (!method->addr) {
4382                 mono_mb_emit_exception (mb, exc_class, exc_arg);
4383                 csig = mono_metadata_signature_dup (sig);
4384                 csig->pinvoke = 0;
4385                 res = mono_mb_create_and_cache (cache, method,
4386                                                                                 mb, csig, csig->param_count + 16);
4387                 mono_mb_free (mb);
4388                 return res;
4389         }
4390
4391         m.mb = mb;
4392         m.piinfo = piinfo;
4393
4394         /* internal calls: we simply push all arguments and call the method (no conversions) */
4395         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
4396
4397                 /* hack - string constructors returns a value */
4398                 if (method->string_ctor) {
4399                         csig = mono_metadata_signature_dup (sig);
4400                         csig->ret = &mono_defaults.string_class->byval_arg;
4401                 } else
4402                         csig = sig;
4403
4404                 if (sig->hasthis)
4405                         mono_mb_emit_byte (mb, CEE_LDARG_0);
4406
4407                 for (i = 0; i < sig->param_count; i++)
4408                         mono_mb_emit_ldarg (mb, i + sig->hasthis);
4409
4410                 g_assert (method->addr);
4411                 mono_mb_emit_native_call (mb, csig, method->addr);
4412                 emit_thread_interrupt_checkpoint (mb);
4413                 mono_mb_emit_byte (mb, CEE_RET);
4414
4415                 csig = mono_metadata_signature_dup (csig);
4416                 csig->pinvoke = 0;
4417                 res = mono_mb_create_and_cache (cache, method,
4418                                                                                 mb, csig, csig->param_count + 16);
4419                 mono_mb_free (mb);
4420                 return res;
4421         }
4422
4423         g_assert (pinvoke);
4424
4425         mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
4426         mono_method_get_marshal_info (method, mspecs);
4427
4428         /* pinvoke: we need to convert the arguments if necessary */
4429
4430         /* we copy the signature, so that we can set pinvoke to 0 */
4431         csig = mono_metadata_signature_dup (sig);
4432         csig->pinvoke = 1;
4433
4434         /* we allocate local for use with emit_struct_conv() */
4435         /* allocate local 0 (pointer) src_ptr */
4436         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4437         /* allocate local 1 (pointer) dst_ptr */
4438         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4439         /* allocate local 2 (boolean) delete_old */
4440         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
4441
4442         /* delete_old = FALSE */
4443         mono_mb_emit_icon (mb, 0);
4444         mono_mb_emit_byte (mb, CEE_STLOC_2);
4445
4446         if (!MONO_TYPE_IS_VOID(sig->ret)) {
4447                 /* allocate local 3 to store the return value */
4448                 mono_mb_add_local (mb, sig->ret);
4449         }
4450
4451         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
4452                 /* Return type custom marshaling */
4453                 /*
4454                  * Since we can't determine the return type of the unmanaged function,
4455                  * we assume it returns a pointer, and pass that pointer to
4456                  * MarshalNativeToManaged.
4457                  */
4458                 csig->ret = &mono_defaults.int_class->byval_arg;
4459         }
4460
4461         /* we first do all conversions */
4462         tmp_locals = alloca (sizeof (int) * sig->param_count);
4463
4464         for (i = 0; i < sig->param_count; i ++) {
4465                 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
4466         }
4467
4468         /* push all arguments */
4469
4470         if (sig->hasthis)
4471                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4472
4473         for (i = 0; i < sig->param_count; i++) {
4474                 MonoType *t = sig->params [i];
4475                 MonoMarshalSpec *spec = mspecs [i + 1];
4476
4477                 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY)))
4478                         emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
4479                 else {
4480                         argnum = i + sig->hasthis;
4481
4482                         switch (t->type) {
4483                         case MONO_TYPE_BOOLEAN:
4484                                 if (t->byref) {
4485                                         g_assert (tmp_locals [i]);
4486                                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
4487                                 } else
4488                                         mono_mb_emit_ldarg (mb, argnum);
4489                                 break;
4490                         case MONO_TYPE_I1:
4491                         case MONO_TYPE_U1:
4492                         case MONO_TYPE_I2:
4493                         case MONO_TYPE_U2:
4494                         case MONO_TYPE_I4:
4495                         case MONO_TYPE_U4:
4496                         case MONO_TYPE_I:
4497                         case MONO_TYPE_U:
4498                         case MONO_TYPE_PTR:
4499                         case MONO_TYPE_R4:
4500                         case MONO_TYPE_R8:
4501                         case MONO_TYPE_I8:
4502                         case MONO_TYPE_U8:
4503                                 mono_mb_emit_ldarg (mb, argnum);
4504                                 break;
4505                         case MONO_TYPE_VALUETYPE:
4506                                 emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
4507                                 break;
4508                         case MONO_TYPE_STRING:
4509                         case MONO_TYPE_CLASS:
4510                         case MONO_TYPE_OBJECT:
4511                         case MONO_TYPE_ARRAY:
4512                         case MONO_TYPE_SZARRAY:
4513                                 g_assert (tmp_locals [i]);
4514                                 if (t->byref) 
4515                                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
4516                                 else
4517                                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
4518                                 break;
4519                         case MONO_TYPE_CHAR:
4520                                 /* fixme: dont know how to marshal that. We cant simply
4521                                  * convert it to a one byte UTF8 character, because an
4522                                  * unicode character may need more that one byte in UTF8 */
4523                                 mono_mb_emit_ldarg (mb, argnum);
4524                                 break;
4525                         case MONO_TYPE_TYPEDBYREF:
4526                         case MONO_TYPE_FNPTR:
4527                         default:
4528                                 g_warning ("type 0x%02x unknown", t->type);     
4529                                 g_assert_not_reached ();
4530                         }
4531                 }
4532         }                       
4533
4534         /* call the native method */
4535         mono_mb_emit_native_call (mb, csig, method->addr);
4536
4537         /* Set LastError if needed */
4538         if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
4539                 MonoMethodSignature *lasterr_sig;
4540
4541                 lasterr_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4542                 lasterr_sig->ret = &mono_defaults.void_class->byval_arg;
4543                 lasterr_sig->pinvoke = 1;
4544
4545                 mono_mb_emit_native_call (mb, lasterr_sig, mono_marshal_set_last_error);
4546         }               
4547
4548         /* convert the result */
4549         if (!sig->ret->byref) {
4550                 MonoMarshalSpec *spec = mspecs [0];
4551                 type = sig->ret->type;
4552
4553                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
4554                         emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4555                 } else {
4556
4557                 handle_enum:
4558                         switch (type) {
4559                         case MONO_TYPE_VOID:
4560                                 break;
4561                         case MONO_TYPE_I1:
4562                         case MONO_TYPE_U1:
4563                         case MONO_TYPE_I2:
4564                         case MONO_TYPE_U2:
4565                         case MONO_TYPE_I4:
4566                         case MONO_TYPE_U4:
4567                         case MONO_TYPE_I:
4568                         case MONO_TYPE_U:
4569                         case MONO_TYPE_PTR:
4570                         case MONO_TYPE_R4:
4571                         case MONO_TYPE_R8:
4572                         case MONO_TYPE_I8:
4573                         case MONO_TYPE_U8:
4574                                 /* no conversions necessary */
4575                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4576                                 break;
4577                         case MONO_TYPE_VALUETYPE:
4578                                 klass = sig->ret->data.klass;
4579                                 if (klass->enumtype) {
4580                                         type = sig->ret->data.klass->enum_basetype->type;
4581                                         goto handle_enum;
4582                                 }
4583                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4584                                 break;
4585                         case MONO_TYPE_STRING:
4586                         case MONO_TYPE_CLASS:
4587                         case MONO_TYPE_OBJECT:
4588                         case MONO_TYPE_BOOLEAN:
4589                         case MONO_TYPE_ARRAY:
4590                         case MONO_TYPE_SZARRAY:
4591                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4592                                 break;
4593                         case MONO_TYPE_CHAR:
4594                                 /* fixme: we need conversions here */
4595                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4596                                 break;
4597                         case MONO_TYPE_TYPEDBYREF:
4598                         case MONO_TYPE_FNPTR:
4599                         default:
4600                                 g_warning ("return type 0x%02x unknown", sig->ret->type);       
4601                                 g_assert_not_reached ();
4602                         }
4603                 }
4604         } else {
4605                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4606         }
4607
4608         /* 
4609          * Need to call this after converting the result since MONO_VTADDR needs 
4610          * to be adjacent to the call instruction.
4611          */
4612         emit_thread_interrupt_checkpoint (mb);
4613
4614         /* we need to convert byref arguments back and free string arrays */
4615         for (i = 0; i < sig->param_count; i++) {
4616                 MonoType *t = sig->params [i];
4617                 MonoMarshalSpec *spec = mspecs [i + 1];
4618
4619                 argnum = i + sig->hasthis;
4620
4621                 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
4622                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
4623                         continue;
4624                 }
4625
4626                 switch (t->type) {
4627                 case MONO_TYPE_STRING:
4628                 case MONO_TYPE_VALUETYPE:
4629                 case MONO_TYPE_CLASS:
4630                 case MONO_TYPE_OBJECT:
4631                 case MONO_TYPE_SZARRAY:
4632                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
4633                         break;
4634                 case MONO_TYPE_BOOLEAN:
4635                         if (!t->byref)
4636                                 continue;
4637                         mono_mb_emit_ldarg (mb, argnum);
4638                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
4639                         if (mspecs [i + 1] != NULL && mspecs [i + 1]->native == MONO_NATIVE_VARIANTBOOL)
4640                                 mono_mb_emit_byte (mb, CEE_NEG);
4641                         mono_mb_emit_byte (mb, CEE_STIND_I1);
4642                 }
4643         }
4644
4645         if (!MONO_TYPE_IS_VOID(sig->ret))
4646                 mono_mb_emit_byte (mb, CEE_LDLOC_3);
4647
4648         mono_mb_emit_byte (mb, CEE_RET);
4649
4650         csig = mono_metadata_signature_dup (sig);
4651         csig->pinvoke = 0;
4652         res = mono_mb_create_and_cache (cache, method,
4653                                                                         mb, csig, csig->param_count + 16);
4654         mono_mb_free (mb);
4655
4656         for (i = sig->param_count; i >= 0; i--)
4657                 g_free (mspecs [i]);
4658         g_free (mspecs);
4659
4660         /* 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)); */
4661
4662         return res;
4663 }
4664
4665 void
4666 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
4667
4668 static MonoReflectionType *
4669 type_from_handle (MonoType *handle)
4670 {
4671         MonoDomain *domain = mono_domain_get (); 
4672         MonoClass *klass = mono_class_from_mono_type (handle);
4673
4674         MONO_ARCH_SAVE_REGS;
4675
4676         mono_class_init (klass);
4677         return mono_type_get_object (domain, handle);
4678 }
4679
4680 /*
4681  * mono_marshal_get_isinst:
4682  * @klass: the type of the field
4683  *
4684  * This method generates a function which can be used to check if an object is
4685  * an instance of the given type, icluding the case where the object is a proxy.
4686  * The generated function has the following signature:
4687  * MonoObject* __isinst_wrapper_ (MonoObject *obj)
4688  */
4689 MonoMethod *
4690 mono_marshal_get_isinst (MonoClass *klass)
4691 {
4692         static MonoMethodSignature *isint_sig = NULL;
4693         static GHashTable *isinst_hash = NULL; 
4694         MonoMethod *res;
4695         int pos_was_ok, pos_failed, pos_end, pos_end2;
4696         char *name;
4697         MonoMethodBuilder *mb;
4698
4699         EnterCriticalSection (&marshal_mutex);
4700         if (!isinst_hash) 
4701                 isinst_hash = g_hash_table_new (NULL, NULL);
4702         
4703         res = g_hash_table_lookup (isinst_hash, klass);
4704         LeaveCriticalSection (&marshal_mutex);
4705         if (res)
4706                 return res;
4707
4708         if (!isint_sig) {
4709                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4710                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
4711                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
4712                 isint_sig->pinvoke = 0;
4713         }
4714         
4715         name = g_strdup_printf ("__isinst_wrapper_%s", klass->name); 
4716         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
4717         g_free (name);
4718         
4719         mb->method->save_lmf = 1;
4720
4721         /* check if the object is a proxy that needs special cast */
4722         mono_mb_emit_ldarg (mb, 0);
4723         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4724         mono_mb_emit_byte (mb, CEE_MONO_CISINST);
4725         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4726
4727         /* The result of MONO_ISINST can be:
4728                 0) the type check succeeded
4729                 1) the type check did not succeed
4730                 2) a CanCastTo call is needed */
4731         
4732         mono_mb_emit_byte (mb, CEE_DUP);
4733         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
4734
4735         mono_mb_emit_byte (mb, CEE_LDC_I4_2);
4736         pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
4737         
4738         /* get the real proxy from the transparent proxy*/
4739
4740         mono_mb_emit_ldarg (mb, 0);
4741         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
4742         pos_end = mono_mb_emit_branch (mb, CEE_BR);
4743         
4744         /* fail */
4745         
4746         mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
4747         mono_mb_emit_byte (mb, CEE_LDNULL);
4748         pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
4749         
4750         /* success */
4751         
4752         mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
4753         mono_mb_emit_byte (mb, CEE_POP);
4754         mono_mb_emit_ldarg (mb, 0);
4755         
4756         /* the end */
4757         
4758         mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
4759         mono_mb_patch_addr (mb, pos_end2, mb->pos - (pos_end2 + 4));
4760         mono_mb_emit_byte (mb, CEE_RET);
4761
4762         res = mono_mb_create_and_cache (isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
4763         mono_mb_free (mb);
4764
4765         return res;
4766 }
4767
4768 /*
4769  * mono_marshal_get_castclass:
4770  * @klass: the type of the field
4771  *
4772  * This method generates a function which can be used to cast an object to
4773  * an instance of the given type, icluding the case where the object is a proxy.
4774  * The generated function has the following signature:
4775  * MonoObject* __castclass_wrapper_ (MonoObject *obj)
4776  */
4777 MonoMethod *
4778 mono_marshal_get_castclass (MonoClass *klass)
4779 {
4780         static MonoMethodSignature *castclass_sig = NULL;
4781         static GHashTable *castclass_hash = NULL; 
4782         MonoMethod *res;
4783         int pos_was_ok, pos_was_ok2;
4784         char *name;
4785         MonoMethodBuilder *mb;
4786
4787         EnterCriticalSection (&marshal_mutex);
4788         if (!castclass_hash) 
4789                 castclass_hash = g_hash_table_new (NULL, NULL);
4790         
4791         res = g_hash_table_lookup (castclass_hash, klass);
4792         LeaveCriticalSection (&marshal_mutex);
4793         if (res)
4794                 return res;
4795
4796         if (!castclass_sig) {
4797                 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4798                 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
4799                 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
4800                 castclass_sig->pinvoke = 0;
4801         }
4802         
4803         name = g_strdup_printf ("__castclass_wrapper_%s", klass->name); 
4804         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
4805         g_free (name);
4806         
4807         mb->method->save_lmf = 1;
4808
4809         /* check if the object is a proxy that needs special cast */
4810         mono_mb_emit_ldarg (mb, 0);
4811         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4812         mono_mb_emit_byte (mb, CEE_MONO_CCASTCLASS);
4813         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4814
4815         /* The result of MONO_ISINST can be:
4816                 0) the cast is valid
4817                 1) cast of unknown proxy type
4818                 or an exception if the cast is is invalid
4819         */
4820         
4821         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
4822
4823         /* get the real proxy from the transparent proxy*/
4824
4825         mono_mb_emit_ldarg (mb, 0);
4826         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
4827         pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
4828         
4829         /* fail */
4830         mono_mb_emit_exception (mb, "InvalidCastException", NULL);
4831         
4832         /* success */
4833         mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
4834         mono_mb_patch_addr (mb, pos_was_ok2, mb->pos - (pos_was_ok2 + 4));
4835         mono_mb_emit_ldarg (mb, 0);
4836         
4837         /* the end */
4838         mono_mb_emit_byte (mb, CEE_RET);
4839
4840         res = mono_mb_create_and_cache (castclass_hash, klass, mb, castclass_sig, castclass_sig->param_count + 16);
4841         mono_mb_free (mb);
4842
4843         return res;
4844 }
4845
4846 MonoMethod *
4847 mono_marshal_get_proxy_cancast (MonoClass *klass)
4848 {
4849         static MonoMethodSignature *from_handle_sig = NULL;
4850         static MonoMethodSignature *upgrade_proxy_sig = NULL;
4851         static MonoMethodSignature *isint_sig = NULL;
4852         static GHashTable *proxy_isinst_hash = NULL; 
4853         MonoMethod *res;
4854         int pos_failed, pos_end;
4855         char *name;
4856         MonoMethod *can_cast_to;
4857         MonoMethodDesc *desc;
4858         MonoMethodBuilder *mb;
4859
4860         EnterCriticalSection (&marshal_mutex);
4861         if (!proxy_isinst_hash) 
4862                 proxy_isinst_hash = g_hash_table_new (NULL, NULL);
4863         
4864         res = g_hash_table_lookup (proxy_isinst_hash, klass);
4865         LeaveCriticalSection (&marshal_mutex);
4866         if (res)
4867                 return res;
4868
4869         if (!isint_sig) {
4870                 upgrade_proxy_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4871                 upgrade_proxy_sig->params [0] = &mono_defaults.object_class->byval_arg;
4872                 upgrade_proxy_sig->params [1] = &mono_defaults.object_class->byval_arg;
4873                 upgrade_proxy_sig->ret = &mono_defaults.void_class->byval_arg;
4874                 upgrade_proxy_sig->pinvoke = 1;
4875
4876                 from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4877                 from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
4878                 from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
4879         
4880                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4881                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
4882                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
4883                 isint_sig->pinvoke = 0;
4884         }
4885         
4886         name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name); 
4887         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
4888         g_free (name);
4889         
4890         mb->method->save_lmf = 1;
4891
4892         /* get the real proxy from the transparent proxy*/
4893         mono_mb_emit_ldarg (mb, 0);
4894         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
4895         mono_mb_emit_byte (mb, CEE_LDIND_I);
4896         
4897         /* get the refletion type from the type handle */
4898         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4899         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
4900         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &klass->byval_arg));
4901         mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
4902         
4903         mono_mb_emit_ldarg (mb, 0);
4904         
4905         /* make the call to CanCastTo (type, ob) */
4906         desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
4907         can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
4908         g_assert (can_cast_to);
4909         mono_method_desc_free (desc);
4910         mono_mb_emit_byte (mb, CEE_CALLVIRT);
4911         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, can_cast_to));
4912
4913         
4914         pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
4915
4916         /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
4917         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4918         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
4919         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &klass->byval_arg));
4920         mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
4921         mono_mb_emit_ldarg (mb, 0);
4922         
4923         mono_mb_emit_native_call (mb, upgrade_proxy_sig, mono_upgrade_remote_class_wrapper);
4924         emit_thread_interrupt_checkpoint (mb);
4925         
4926         mono_mb_emit_ldarg (mb, 0);
4927         pos_end = mono_mb_emit_branch (mb, CEE_BR);
4928         
4929         /* fail */
4930         
4931         mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
4932         mono_mb_emit_byte (mb, CEE_LDNULL);
4933         
4934         /* the end */
4935         
4936         mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
4937         mono_mb_emit_byte (mb, CEE_RET);
4938
4939         res = mono_mb_create_and_cache (proxy_isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
4940         mono_mb_free (mb);
4941
4942         return res;
4943 }
4944
4945 void
4946 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
4947 {
4948         MonoClass *klass;
4949         klass = mono_class_from_mono_type (rtype->type);
4950         mono_upgrade_remote_class (((MonoObject*)tproxy)->vtable->domain, tproxy->remote_class, klass);
4951         ((MonoObject*)tproxy)->vtable = tproxy->remote_class->vtable;
4952 }
4953
4954 /**
4955  * mono_marshal_get_struct_to_ptr:
4956  * @klass:
4957  *
4958  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
4959  */
4960 MonoMethod *
4961 mono_marshal_get_struct_to_ptr (MonoClass *klass)
4962 {
4963         MonoMethodBuilder *mb;
4964         static MonoMethod *stoptr = NULL;
4965         MonoMethod *res;
4966
4967         g_assert (klass != NULL);
4968
4969         if (klass->str_to_ptr)
4970                 return klass->str_to_ptr;
4971
4972         if (!stoptr) 
4973                 stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
4974         g_assert (stoptr);
4975
4976         mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
4977
4978         if (klass->blittable) {
4979                 mono_mb_emit_byte (mb, CEE_LDARG_1);
4980                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4981                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
4982                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
4983                 mono_mb_emit_byte (mb, CEE_PREFIX1);
4984                 mono_mb_emit_byte (mb, CEE_CPBLK);
4985         } else {
4986
4987                 /* allocate local 0 (pointer) src_ptr */
4988                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4989                 /* allocate local 1 (pointer) dst_ptr */
4990                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4991                 /* allocate local 2 (boolean) delete_old */
4992                 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
4993                 mono_mb_emit_byte (mb, CEE_LDARG_2);
4994                 mono_mb_emit_byte (mb, CEE_STLOC_2);
4995
4996                 /* initialize src_ptr to point to the start of object data */
4997                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4998                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
4999                 mono_mb_emit_byte (mb, CEE_STLOC_0);
5000
5001                 /* initialize dst_ptr */
5002                 mono_mb_emit_byte (mb, CEE_LDARG_1);
5003                 mono_mb_emit_byte (mb, CEE_STLOC_1);
5004
5005                 emit_struct_conv (mb, klass, FALSE);
5006         }
5007
5008         mono_mb_emit_byte (mb, CEE_RET);
5009
5010         res = mono_mb_create_method (mb, stoptr->signature, 0);
5011         mono_mb_free (mb);
5012
5013         klass->str_to_ptr = res;
5014         return res;
5015 }
5016
5017 /**
5018  * mono_marshal_get_ptr_to_struct:
5019  * @klass:
5020  *
5021  * generates IL code for PtrToStructure (IntPtr src, object structure)
5022  */
5023 MonoMethod *
5024 mono_marshal_get_ptr_to_struct (MonoClass *klass)
5025 {
5026         MonoMethodBuilder *mb;
5027         static MonoMethod *ptostr = NULL;
5028         MonoMethod *res;
5029
5030         g_assert (klass != NULL);
5031
5032         if (klass->ptr_to_str)
5033                 return klass->ptr_to_str;
5034
5035         if (!ptostr) 
5036                 ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
5037         g_assert (ptostr);
5038
5039         mb = mono_mb_new (klass, ptostr->name, MONO_WRAPPER_UNKNOWN);
5040
5041         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
5042                 mono_mb_emit_byte (mb, CEE_LDARG_1);
5043                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5044                 mono_mb_emit_byte (mb, CEE_LDARG_0);
5045                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
5046                 mono_mb_emit_byte (mb, CEE_PREFIX1);
5047                 mono_mb_emit_byte (mb, CEE_CPBLK);
5048         } else {
5049
5050                 /* allocate local 0 (pointer) src_ptr */
5051                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5052                 /* allocate local 1 (pointer) dst_ptr */
5053                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5054                 
5055                 /* initialize src_ptr to point to the start of object data */
5056                 mono_mb_emit_byte (mb, CEE_LDARG_0);
5057                 mono_mb_emit_byte (mb, CEE_STLOC_0);
5058
5059                 /* initialize dst_ptr */
5060                 mono_mb_emit_byte (mb, CEE_LDARG_1);
5061                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5062                 mono_mb_emit_byte (mb, CEE_STLOC_1);
5063
5064                 emit_struct_conv (mb, klass, TRUE);
5065         }
5066
5067         mono_mb_emit_byte (mb, CEE_RET);
5068
5069         res = mono_mb_create_method (mb, ptostr->signature, 0);
5070         mono_mb_free (mb);
5071
5072         klass->ptr_to_str = res;
5073         return res;
5074 }
5075
5076 /*
5077  * generates IL code for the synchronized wrapper: the generated method
5078  * calls METHOD while locking 'this' or the parent type.
5079  */
5080 MonoMethod *
5081 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
5082 {
5083         static MonoMethodSignature *from_handle_sig = NULL;
5084         static MonoMethod *enter_method, *exit_method;
5085         MonoMethodSignature *sig;
5086         MonoExceptionClause *clause;
5087         MonoMethodHeader *header;
5088         MonoMethodBuilder *mb;
5089         MonoMethod *res;
5090         GHashTable *cache;
5091         int i, pos, this_local, ret_local;
5092
5093         g_assert (method);
5094
5095         if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
5096                 return method;
5097
5098         cache = method->klass->image->synchronized_cache;
5099         if ((res = mono_marshal_find_in_cache (cache, method)))
5100                 return res;
5101
5102         sig = method->signature;
5103
5104         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
5105
5106         /* result */
5107         if (!MONO_TYPE_IS_VOID (sig->ret))
5108                 ret_local = mono_mb_add_local (mb, sig->ret);
5109
5110         /* this */
5111         this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5112
5113         clause = g_new0 (MonoExceptionClause, 1);
5114         clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
5115
5116         if (!enter_method) {
5117                 MonoMethodDesc *desc;
5118
5119                 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
5120                 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
5121                 g_assert (enter_method);
5122                 mono_method_desc_free (desc);
5123                 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
5124                 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
5125                 g_assert (exit_method);
5126                 mono_method_desc_free (desc);
5127
5128                 /*
5129                  * GetTypeFromHandle isn't called as a managed method because it has
5130                  * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
5131                  * transformed into something else by the JIT.
5132                  */
5133                 from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5134                 from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
5135                 from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
5136         }
5137
5138         /* Push this or the type object */
5139         if (method->flags & METHOD_ATTRIBUTE_STATIC) {
5140                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5141                 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
5142                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &method->klass->byval_arg));
5143                 mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
5144         }
5145         else
5146                 mono_mb_emit_ldarg (mb, 0);
5147         mono_mb_emit_stloc (mb, this_local);
5148
5149         /* Call Monitor::Enter() */
5150         mono_mb_emit_ldloc (mb, this_local);
5151         mono_mb_emit_managed_call (mb, enter_method, NULL);
5152
5153         clause->try_offset = mb->pos;
5154
5155         /* Call the method */
5156         if (sig->hasthis)
5157                 mono_mb_emit_ldarg (mb, 0);
5158         for (i = 0; i < sig->param_count; i++)
5159                 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
5160         mono_mb_emit_managed_call (mb, method, method->signature);
5161         if (!MONO_TYPE_IS_VOID (sig->ret))
5162                 mono_mb_emit_stloc (mb, ret_local);
5163
5164         mono_mb_emit_byte (mb, CEE_LEAVE);
5165         pos = mb->pos;
5166         mono_mb_emit_i4 (mb, 0);
5167
5168         clause->try_len = mb->pos - clause->try_offset;
5169         clause->handler_offset = mb->pos;
5170
5171         /* Call Monitor::Exit() */
5172         mono_mb_emit_ldloc (mb, this_local);
5173 /*      mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */
5174         mono_mb_emit_managed_call (mb, exit_method, NULL);
5175         mono_mb_emit_byte (mb, CEE_ENDFINALLY);
5176
5177         clause->handler_len = mb->pos - clause->handler_offset;
5178
5179         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5180         if (!MONO_TYPE_IS_VOID (sig->ret))
5181                 mono_mb_emit_ldloc (mb, ret_local);
5182         mono_mb_emit_byte (mb, CEE_RET);
5183
5184         res = mono_mb_create_and_cache (cache, method,
5185                                                                         mb, sig, sig->param_count + 16);
5186         mono_mb_free (mb);
5187
5188         header = ((MonoMethodNormal *)res)->header;
5189         header->num_clauses = 1;
5190         header->clauses = clause;
5191
5192         return res;     
5193 }
5194
5195 MonoMethod*
5196 mono_marshal_get_stelemref ()
5197 {
5198         static MonoMethod* ret = NULL;
5199         MonoMethodSignature *sig;
5200         MonoMethodBuilder *mb;
5201         
5202         guint32 b1, b2, b3, b4;
5203         guint32 copy_pos;
5204         int aklass, vklass;
5205         
5206         if (ret)
5207                 return ret;
5208         
5209         mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
5210         
5211
5212         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5213
5214         /* void stelemref (void* array, int idx, void* value) */
5215         sig->ret = &mono_defaults.void_class->byval_arg;
5216         sig->params [0] = &mono_defaults.int_class->byval_arg;
5217         sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
5218         sig->params [2] = &mono_defaults.int_class->byval_arg;
5219                 
5220         aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5221         vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5222         
5223         /*
5224         the method:
5225         <check ABC>
5226         if (!value)
5227                 goto store;
5228         
5229         aklass = array->vtable->klass->element_class;
5230         vklass = value->vtable->klass;
5231         
5232         if (vklass->idepth < aklass->idepth)
5233                 goto long;
5234         
5235         if (vklass->supertypes [aklass->idepth - 1] != aklass)
5236                 goto long;
5237         
5238         store:
5239                 array [idx] = value;
5240                 return;
5241         
5242         long:
5243                 if (mono_object_isinst (value, aklass))
5244                         goto store;
5245                 
5246                 throw new ArrayTypeMismatchException ();
5247         */
5248         
5249         /* ABC */
5250         mono_mb_emit_ldarg (mb, 0);
5251         mono_mb_emit_ldarg (mb, 1);
5252         mono_mb_emit_byte (mb, CEE_LDELEMA);
5253         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.int_class));
5254         mono_mb_emit_byte (mb, CEE_POP);
5255                 
5256         /* if (!value) goto do_store */
5257         mono_mb_emit_ldarg (mb, 2);
5258         b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5259         
5260         /* aklass = array->vtable->klass->element_class */
5261         mono_mb_emit_ldarg (mb, 0);
5262         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
5263         mono_mb_emit_byte (mb, CEE_LDIND_I);
5264         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
5265         mono_mb_emit_byte (mb, CEE_LDIND_I);
5266         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
5267         mono_mb_emit_byte (mb, CEE_LDIND_I);
5268         mono_mb_emit_stloc (mb, aklass);
5269         
5270         /* vklass = value->vtable->klass */
5271         mono_mb_emit_ldarg (mb, 2);
5272         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
5273         mono_mb_emit_byte (mb, CEE_LDIND_I);
5274         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
5275         mono_mb_emit_byte (mb, CEE_LDIND_I);
5276         mono_mb_emit_stloc (mb, vklass);
5277         
5278         /* if (vklass->idepth < aklass->idepth) goto failue */
5279         mono_mb_emit_ldloc (mb, vklass);
5280         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5281         mono_mb_emit_byte (mb, CEE_LDIND_I4);
5282         
5283         mono_mb_emit_ldloc (mb, aklass);
5284         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5285         mono_mb_emit_byte (mb, CEE_LDIND_I4);
5286         
5287         b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
5288         
5289         /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
5290         mono_mb_emit_ldloc (mb, vklass);
5291         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
5292         mono_mb_emit_byte (mb, CEE_LDIND_I);
5293         
5294         mono_mb_emit_ldloc (mb, aklass);
5295         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5296         mono_mb_emit_byte (mb, CEE_LDIND_I4);
5297         mono_mb_emit_icon (mb, 1);
5298         mono_mb_emit_byte (mb, CEE_SUB);
5299         mono_mb_emit_icon (mb, sizeof (void*));
5300         mono_mb_emit_byte (mb, CEE_MUL);
5301         mono_mb_emit_byte (mb, CEE_ADD);
5302         mono_mb_emit_byte (mb, CEE_LDIND_I);
5303         
5304         mono_mb_emit_ldloc (mb, aklass);
5305         
5306         b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
5307         
5308         copy_pos = mb->pos;
5309         /* do_store */
5310         mono_mb_patch_addr (mb, b1, mb->pos - (b1 + 4));
5311         mono_mb_emit_ldarg (mb, 0);
5312         mono_mb_emit_ldarg (mb, 1);
5313         mono_mb_emit_ldarg (mb, 2);
5314         mono_mb_emit_byte (mb, CEE_STELEM_I);
5315         
5316         mono_mb_emit_byte (mb, CEE_RET);
5317         
5318         /* the hard way */
5319         mono_mb_patch_addr (mb, b2, mb->pos - (b2 + 4));
5320         mono_mb_patch_addr (mb, b3, mb->pos - (b3 + 4));
5321         
5322         mono_mb_emit_ldarg (mb, 2);
5323         mono_mb_emit_ldloc (mb, aklass);
5324         mono_mb_emit_icall (mb, mono_object_isinst);
5325         
5326         b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
5327         mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
5328         mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
5329         
5330         mono_mb_emit_byte (mb, CEE_RET);
5331         ret = mono_mb_create_method (mb, sig, 4);
5332         return ret;
5333 }
5334
5335 /* FIXME: on win32 we should probably use GlobalAlloc(). */
5336 void*
5337 mono_marshal_alloc (gpointer size) 
5338 {
5339         gpointer res;
5340
5341         MONO_ARCH_SAVE_REGS;
5342
5343         if ((gulong)size == 0)
5344                 /* This returns a valid pointer for size 0 on MS.NET */
5345                 size = (gpointer)4;
5346
5347         res = g_try_malloc ((gulong)size);
5348         if (!res)
5349                 mono_gc_out_of_memory ((gulong)size);
5350
5351         return res;
5352 }
5353
5354 void
5355 mono_marshal_free (gpointer ptr) 
5356 {
5357         MONO_ARCH_SAVE_REGS;
5358
5359         g_free (ptr);
5360 }
5361
5362 void
5363 mono_marshal_free_array (gpointer *ptr, int size) 
5364 {
5365         int i;
5366
5367         if (!ptr)
5368                 return;
5369
5370         for (i = 0; i < size; i++)
5371                 if (ptr [i])
5372                         g_free (ptr [i]);
5373 }
5374
5375 void *
5376 mono_marshal_realloc (gpointer ptr, gpointer size) 
5377 {
5378         MONO_ARCH_SAVE_REGS;
5379
5380         return g_try_realloc (ptr, (gulong)size);
5381 }
5382
5383 void *
5384 mono_marshal_string_array (MonoArray *array)
5385 {
5386         char **result;
5387         int i, len;
5388
5389         if (!array)
5390                 return NULL;
5391
5392         len = mono_array_length (array);
5393
5394         result = g_malloc (sizeof (char *) * (len + 1));
5395         for (i = 0; i < len; ++i) {
5396                 MonoString *s = (MonoString *)mono_array_get (array, gpointer, i);
5397                 result [i] = s ? mono_string_to_utf8 (s): NULL;
5398         }
5399         /* null terminate the array */
5400         result [i] = NULL;
5401
5402         return result;
5403 }
5404
5405 void *
5406 mono_marshal_string_array_to_unicode (MonoArray *array)
5407 {
5408         gunichar2 **result;
5409         int i, len;
5410
5411         if (!array)
5412                 return NULL;
5413
5414         len = mono_array_length (array);
5415
5416         result = g_malloc (sizeof (gunichar2 *) * (len + 1));
5417         for (i = 0; i < len; ++i) {
5418                 MonoString *s = (MonoString *)mono_array_get (array, gpointer, i);
5419                 result [i] = s ? mono_string_chars (s) : NULL;
5420         }
5421         /* null terminate the array */
5422         result [i] = NULL;
5423
5424         return result;
5425 }
5426
5427 /**
5428  * mono_marshal_set_last_error:
5429  *
5430  * This function is invoked to set the last error value from a P/Invoke call
5431  * which has SetLastError set.
5432  */
5433 void
5434 mono_marshal_set_last_error (void)
5435 {
5436 #ifdef WIN32
5437         TlsSetValue (last_error_tls_id, (gpointer)GetLastError ());
5438 #else
5439         TlsSetValue (last_error_tls_id, (gpointer)errno);
5440 #endif
5441 }
5442
5443 void
5444 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
5445                                                                     gpointer dest, gint32 length)
5446 {
5447         int element_size;
5448         void *source_addr;
5449
5450         MONO_ARCH_SAVE_REGS;
5451
5452         MONO_CHECK_ARG_NULL (src);
5453         MONO_CHECK_ARG_NULL (dest);
5454
5455         g_assert (src->obj.vtable->klass->rank == 1);
5456         g_assert (start_index >= 0);
5457         g_assert (length >= 0);
5458         g_assert (start_index + length <= mono_array_length (src));
5459
5460         element_size = mono_array_element_size (src->obj.vtable->klass);
5461           
5462         source_addr = mono_array_addr_with_size (src, element_size, start_index);
5463
5464         memcpy (dest, source_addr, length * element_size);
5465 }
5466
5467 void
5468 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
5469                                                                       MonoArray *dest, gint32 length)
5470 {
5471         int element_size;
5472         void *dest_addr;
5473
5474         MONO_ARCH_SAVE_REGS;
5475
5476         MONO_CHECK_ARG_NULL (src);
5477         MONO_CHECK_ARG_NULL (dest);
5478
5479         g_assert (dest->obj.vtable->klass->rank == 1);
5480         g_assert (start_index >= 0);
5481         g_assert (length >= 0);
5482         g_assert (start_index + length <= mono_array_length (dest));
5483
5484         element_size = mono_array_element_size (dest->obj.vtable->klass);
5485           
5486         dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
5487
5488         memcpy (dest_addr, src, length * element_size);
5489 }
5490
5491 #if NO_UNALIGNED_ACCESS
5492 #define RETURN_UNALIGNED(type, addr) \
5493         { \
5494                 type val; \
5495                 memcpy(&val, p + offset, sizeof(val)); \
5496                 return val; \
5497         }
5498 #define WRITE_UNALIGNED(type, addr, val) \
5499         memcpy(addr, &val, sizeof(type))
5500 #else
5501 #define RETURN_UNALIGNED(type, addr) \
5502         return *(type*)(p + offset);
5503 #define WRITE_UNALIGNED(type, addr, val) \
5504         (*(type *)(addr) = (val))
5505 #endif
5506
5507 gpointer
5508 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
5509 {
5510         char *p = ptr;
5511
5512         MONO_ARCH_SAVE_REGS;
5513
5514         RETURN_UNALIGNED(gpointer, p + offset);
5515 }
5516
5517 unsigned char
5518 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
5519 {
5520         char *p = ptr;
5521
5522         MONO_ARCH_SAVE_REGS;
5523
5524         return *(unsigned char*)(p + offset);
5525 }
5526
5527 gint16
5528 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
5529 {
5530         char *p = ptr;
5531
5532         MONO_ARCH_SAVE_REGS;
5533
5534         RETURN_UNALIGNED(gint16, p + offset);
5535 }
5536
5537 gint32
5538 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
5539 {
5540         char *p = ptr;
5541
5542         MONO_ARCH_SAVE_REGS;
5543
5544         RETURN_UNALIGNED(gint32, p + offset);
5545 }
5546
5547 gint64
5548 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
5549 {
5550         char *p = ptr;
5551
5552         MONO_ARCH_SAVE_REGS;
5553
5554         RETURN_UNALIGNED(gint64, p + offset);
5555 }
5556
5557 void
5558 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
5559 {
5560         char *p = ptr;
5561
5562         MONO_ARCH_SAVE_REGS;
5563
5564         *(unsigned char*)(p + offset) = val;
5565 }
5566
5567 void
5568 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
5569 {
5570         char *p = ptr;
5571
5572         MONO_ARCH_SAVE_REGS;
5573
5574         WRITE_UNALIGNED(gpointer, p + offset, val);
5575 }
5576
5577 void
5578 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
5579 {
5580         char *p = ptr;
5581
5582         MONO_ARCH_SAVE_REGS;
5583
5584         WRITE_UNALIGNED(gint16, p + offset, val);
5585 }
5586
5587 void
5588 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
5589 {
5590         char *p = ptr;
5591
5592         MONO_ARCH_SAVE_REGS;
5593
5594         WRITE_UNALIGNED(gint32, p + offset, val);
5595 }
5596
5597 void
5598 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
5599 {
5600         char *p = ptr;
5601
5602         MONO_ARCH_SAVE_REGS;
5603
5604         WRITE_UNALIGNED(gint64, p + offset, val);
5605 }
5606
5607 MonoString *
5608 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
5609 {
5610         MONO_ARCH_SAVE_REGS;
5611
5612         if (ptr == NULL)
5613                 return mono_string_new (mono_domain_get (), "");
5614         else
5615                 return mono_string_new (mono_domain_get (), ptr);
5616 }
5617
5618 MonoString *
5619 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
5620 {
5621         MONO_ARCH_SAVE_REGS;
5622
5623         if (ptr == NULL)
5624                 return mono_string_new (mono_domain_get (), "");
5625         else
5626                 return mono_string_new_len (mono_domain_get (), ptr, len);
5627 }
5628
5629 MonoString *
5630 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
5631 {
5632         MonoDomain *domain = mono_domain_get (); 
5633         int len = 0;
5634         guint16 *t = ptr;
5635
5636         MONO_ARCH_SAVE_REGS;
5637
5638         if (ptr == NULL)
5639                 return mono_string_new (mono_domain_get (), "");
5640
5641         while (*t++)
5642                 len++;
5643
5644         return mono_string_new_utf16 (domain, ptr, len);
5645 }
5646
5647 MonoString *
5648 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
5649 {
5650         MonoDomain *domain = mono_domain_get (); 
5651
5652         MONO_ARCH_SAVE_REGS;
5653
5654         if (ptr == NULL)
5655                 return mono_string_new (mono_domain_get (), "");
5656         else
5657                 return mono_string_new_utf16 (domain, ptr, len);
5658 }
5659
5660 MonoString *
5661 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
5662 {
5663         MONO_ARCH_SAVE_REGS;
5664
5665         g_warning ("PtrToStringBSTR not implemented");
5666         g_assert_not_reached ();
5667
5668         return NULL;
5669 }
5670
5671 guint32 
5672 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5673 {
5674         MONO_ARCH_SAVE_REGS;
5675
5676         return ((guint32)TlsGetValue (last_error_tls_id));
5677 }
5678
5679 guint32 
5680 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
5681 {
5682         MonoClass *klass;
5683         MonoType *type;
5684         guint32 layout;
5685
5686         MONO_ARCH_SAVE_REGS;
5687
5688         MONO_CHECK_ARG_NULL (rtype);
5689
5690         type = rtype->type;
5691         klass = mono_class_from_mono_type (type);
5692         layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
5693
5694         if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5695                 gchar *msg;
5696                 MonoException *exc;
5697
5698                 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
5699                 exc = mono_get_exception_argument ("t", msg);
5700                 g_free (msg);
5701                 mono_raise_exception (exc);
5702         }
5703
5704
5705         return mono_class_native_size (klass, NULL);
5706 }
5707
5708 void
5709 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
5710 {
5711         MonoMethod *method;
5712         gpointer pa [3];
5713
5714         MONO_ARCH_SAVE_REGS;
5715
5716         MONO_CHECK_ARG_NULL (obj);
5717         MONO_CHECK_ARG_NULL (dst);
5718
5719         method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
5720
5721         pa [0] = obj;
5722         pa [1] = &dst;
5723         pa [2] = &delete_old;
5724
5725         mono_runtime_invoke (method, NULL, pa, NULL);
5726 }
5727
5728 void
5729 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
5730 {
5731         MonoMethod *method;
5732         gpointer pa [2];
5733
5734         MONO_ARCH_SAVE_REGS;
5735
5736         MONO_CHECK_ARG_NULL (src);
5737         MONO_CHECK_ARG_NULL (dst);
5738
5739         method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
5740
5741         pa [0] = &src;
5742         pa [1] = dst;
5743
5744         mono_runtime_invoke (method, NULL, pa, NULL);
5745 }
5746
5747 MonoObject *
5748 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
5749 {
5750         MonoDomain *domain = mono_domain_get (); 
5751         MonoObject *res;
5752
5753         MONO_ARCH_SAVE_REGS;
5754
5755         MONO_CHECK_ARG_NULL (src);
5756         MONO_CHECK_ARG_NULL (type);
5757
5758         res = mono_object_new (domain, mono_class_from_mono_type (type->type));
5759
5760         ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res);
5761
5762         return res;
5763 }
5764
5765 int
5766 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
5767 {
5768         MonoMarshalType *info;
5769         MonoClass *klass;
5770         char *fname;
5771         int i, match_index = -1;
5772         
5773         MONO_ARCH_SAVE_REGS;
5774
5775         MONO_CHECK_ARG_NULL (type);
5776         MONO_CHECK_ARG_NULL (field_name);
5777
5778         fname = mono_string_to_utf8 (field_name);
5779         klass = mono_class_from_mono_type (type->type);
5780
5781         while(klass && match_index == -1) {
5782                 for (i = 0; i < klass->field.count; ++i) {
5783                         if (*fname == *klass->fields [i].name && strcmp (fname, klass->fields [i].name) == 0) {
5784                                 match_index = i;
5785                                 break;
5786                         }
5787                 }
5788
5789                 if(match_index == -1)
5790                         klass = klass->parent;
5791         }
5792
5793         g_free (fname);
5794
5795         if(match_index == -1) {
5796                MonoException* exc;
5797                gchar *tmp;
5798
5799                /* Get back original class instance */
5800                klass = mono_class_from_mono_type (type->type);
5801
5802                tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
5803                exc = mono_get_exception_argument ("fieldName", tmp);
5804                g_free (tmp);
5805  
5806                mono_raise_exception ((MonoException*)exc);
5807        }
5808
5809        info = mono_marshal_load_type_info (klass);     
5810        return info->fields [match_index].offset;
5811 }
5812
5813 gpointer
5814 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
5815 {
5816         MONO_ARCH_SAVE_REGS;
5817
5818         return mono_string_to_utf8 (string);
5819 }
5820
5821 gpointer
5822 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
5823 {
5824         MONO_ARCH_SAVE_REGS;
5825
5826         if (string == NULL)
5827                 return NULL;
5828         else
5829                 return g_memdup (mono_string_chars (string), mono_string_length (string)*2);
5830 }
5831
5832 static void
5833 mono_struct_delete_old (MonoClass *klass, char *ptr)
5834 {
5835         MonoMarshalType *info;
5836         int i;
5837
5838         info = mono_marshal_load_type_info (klass);
5839
5840         for (i = 0; i < info->num_fields; i++) {
5841                 MonoMarshalNative ntype;
5842                 MonoMarshalConv conv;
5843                 MonoType *ftype = info->fields [i].field->type;
5844                 char *cpos;
5845
5846                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
5847                         continue;
5848
5849                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, 
5850                                                 klass->unicode, &conv);
5851                         
5852                 cpos = ptr + info->fields [i].offset;
5853
5854                 switch (conv) {
5855                 case MONO_MARSHAL_CONV_NONE:
5856                         if (MONO_TYPE_ISSTRUCT (ftype)) {
5857                                 mono_struct_delete_old (ftype->data.klass, cpos);
5858                                 continue;
5859                         }
5860                         break;
5861                 case MONO_MARSHAL_CONV_STR_LPWSTR:
5862                 case MONO_MARSHAL_CONV_STR_LPSTR:
5863                 case MONO_MARSHAL_CONV_STR_LPTSTR:
5864                 case MONO_MARSHAL_CONV_STR_BSTR:
5865                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
5866                 case MONO_MARSHAL_CONV_STR_TBSTR:
5867                         g_free (*(gpointer *)cpos);
5868                         break;
5869                 default:
5870                         continue;
5871                 }
5872         }
5873 }
5874
5875 void
5876 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
5877 {
5878         MonoClass *klass;
5879
5880         MONO_ARCH_SAVE_REGS;
5881
5882         MONO_CHECK_ARG_NULL (src);
5883         MONO_CHECK_ARG_NULL (type);
5884
5885         klass = mono_class_from_mono_type (type->type);
5886
5887         mono_struct_delete_old (klass, (char *)src);
5888 }
5889
5890 void*
5891 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
5892 {
5893         /* FIXME: Call AllocCoTaskMem under windows */
5894         MONO_ARCH_SAVE_REGS;
5895
5896         return g_try_malloc ((gulong)size);
5897 }
5898
5899 void
5900 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
5901 {
5902         /* FIXME: Call FreeCoTaskMem under windows */
5903         MONO_ARCH_SAVE_REGS;
5904
5905         g_free (ptr);
5906 }
5907
5908 void*
5909 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
5910 {
5911         return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
5912 }
5913
5914 MonoMarshalType *
5915 mono_marshal_load_type_info (MonoClass* klass)
5916 {
5917         int i, j, count = 0, native_size = 0, min_align = 1;
5918         MonoMarshalType *info;
5919         guint32 layout;
5920
5921         g_assert (klass != NULL);
5922
5923         if (klass->marshal_info)
5924                 return klass->marshal_info;
5925
5926         if (!klass->inited)
5927                 mono_class_init (klass);
5928         
5929         for (i = 0; i < klass->field.count; ++i) {
5930                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
5931                         continue;
5932                 if (mono_field_is_deleted (&klass->fields [i]))
5933                         continue;
5934                 count++;
5935         }
5936
5937         layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
5938
5939         klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
5940         info->num_fields = count;
5941         
5942         /* Try to find a size for this type in metadata */
5943         mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
5944
5945         if (klass->parent) {
5946                 int parent_size = mono_class_native_size (klass->parent, NULL);
5947
5948                 /* Add parent size to real size */
5949                 native_size += parent_size;
5950                 info->native_size = parent_size;
5951         }
5952  
5953         for (j = i = 0; i < klass->field.count; ++i) {
5954                 int size, align;
5955                 
5956                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
5957                         continue;
5958
5959                 if (mono_field_is_deleted (&klass->fields [i]))
5960                         continue;
5961                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
5962                         mono_metadata_field_info (klass->image, klass->field.first + i, 
5963                                                   NULL, NULL, &info->fields [j].mspec);
5964
5965                 info->fields [j].field = &klass->fields [i];
5966
5967                 if ((klass->field.count == 1) && (klass->instance_size == sizeof (MonoObject)) &&
5968                         (strcmp (klass->fields [i].name, "$PRIVATE$") == 0)) {
5969                         /* This field is a hack inserted by MCS to empty structures */
5970                         continue;
5971                 }
5972
5973                 switch (layout) {
5974                 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
5975                 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
5976                         size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec, 
5977                                                        &align, TRUE, klass->unicode);
5978                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
5979                         min_align = MAX (align, min_align);
5980                         info->fields [j].offset = info->native_size;
5981                         info->fields [j].offset += align - 1;
5982                         info->fields [j].offset &= ~(align - 1);
5983                         info->native_size = info->fields [j].offset + size;
5984                         break;
5985                 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
5986                         size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec, 
5987                                                        &align, TRUE, klass->unicode);
5988                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
5989                         min_align = MAX (align, min_align);
5990                         info->fields [j].offset = klass->fields [i].offset - sizeof (MonoObject);
5991                         info->native_size = MAX (info->native_size, info->fields [j].offset + size);
5992                         break;
5993                 }       
5994                 j++;
5995         }
5996
5997         if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5998                 info->native_size = MAX (native_size, info->native_size);
5999         }
6000
6001         if (info->native_size & (min_align - 1)) {
6002                 info->native_size += min_align - 1;
6003                 info->native_size &= ~(min_align - 1);
6004         }
6005
6006         /* Update the class's blittable info, if the layouts don't match */
6007         if (info->native_size != mono_class_value_size (klass, NULL))
6008                 klass->blittable = FALSE;
6009
6010         /* If this is an array type, ensure that we have element info */
6011         if (klass->element_class) {
6012                 mono_marshal_load_type_info (klass->element_class);
6013         }
6014
6015         return klass->marshal_info;
6016 }
6017
6018 /**
6019  * mono_class_native_size:
6020  * @klass: a class 
6021  * 
6022  * Returns: the native size of an object instance (when marshaled 
6023  * to unmanaged code) 
6024  */
6025 gint32
6026 mono_class_native_size (MonoClass *klass, guint32 *align)
6027 {
6028         
6029         if (!klass->marshal_info)
6030                 mono_marshal_load_type_info (klass);
6031
6032         if (align)
6033                 *align = klass->min_align;
6034
6035         return klass->marshal_info->native_size;
6036 }
6037
6038 /*
6039  * mono_type_native_stack_size:
6040  * @t: the type to return the size it uses on the stack
6041  *
6042  * Returns: the number of bytes required to hold an instance of this
6043  * type on the native stack
6044  */
6045 int
6046 mono_type_native_stack_size (MonoType *t, gint *align)
6047 {
6048         int tmp;
6049
6050         g_assert (t != NULL);
6051
6052         if (!align)
6053                 align = &tmp;
6054
6055         if (t->byref) {
6056                 *align = 4;
6057                 return 4;
6058         }
6059
6060         switch (t->type){
6061         case MONO_TYPE_BOOLEAN:
6062         case MONO_TYPE_CHAR:
6063         case MONO_TYPE_I1:
6064         case MONO_TYPE_U1:
6065         case MONO_TYPE_I2:
6066         case MONO_TYPE_U2:
6067         case MONO_TYPE_I4:
6068         case MONO_TYPE_U4:
6069         case MONO_TYPE_I:
6070         case MONO_TYPE_U:
6071         case MONO_TYPE_STRING:
6072         case MONO_TYPE_OBJECT:
6073         case MONO_TYPE_CLASS:
6074         case MONO_TYPE_SZARRAY:
6075         case MONO_TYPE_PTR:
6076         case MONO_TYPE_FNPTR:
6077         case MONO_TYPE_ARRAY:
6078         case MONO_TYPE_TYPEDBYREF:
6079                 *align = 4;
6080                 return 4;
6081         case MONO_TYPE_R4:
6082                 *align = 4;
6083                 return 4;
6084         case MONO_TYPE_I8:
6085         case MONO_TYPE_U8:
6086         case MONO_TYPE_R8:
6087                 *align = 4;
6088                 return 8;
6089         case MONO_TYPE_VALUETYPE: {
6090                 guint32 size;
6091
6092                 if (t->data.klass->enumtype)
6093                         return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
6094                 else {
6095                         size = mono_class_native_size (t->data.klass, align);
6096                         *align = *align + 3;
6097                         *align &= ~3;
6098                         
6099                         size +=  3;
6100                         size &= ~3;
6101
6102                         return size;
6103                 }
6104         }
6105         default:
6106                 g_error ("type 0x%02x unknown", t->type);
6107         }
6108         return 0;
6109 }
6110
6111 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
6112    the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
6113    but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
6114 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
6115
6116 gint32
6117 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align, 
6118                         gboolean as_field, gboolean unicode)
6119 {
6120         MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
6121         MonoClass *klass;
6122
6123         switch (native_type) {
6124         case MONO_NATIVE_BOOLEAN:
6125                 *align = 4;
6126                 return 4;
6127         case MONO_NATIVE_I1:
6128         case MONO_NATIVE_U1:
6129                 *align = 1;
6130                 return 1;
6131         case MONO_NATIVE_I2:
6132         case MONO_NATIVE_U2:
6133         case MONO_NATIVE_VARIANTBOOL:
6134                 *align = 2;
6135                 return 2;
6136         case MONO_NATIVE_I4:
6137         case MONO_NATIVE_U4:
6138         case MONO_NATIVE_ERROR:
6139                 *align = 4;
6140                 return 4;
6141         case MONO_NATIVE_I8:
6142         case MONO_NATIVE_U8:
6143                 *align = ALIGNMENT(guint64);
6144                 return 8;
6145         case MONO_NATIVE_R4:
6146                 *align = 4;
6147                 return 4;
6148         case MONO_NATIVE_R8:
6149                 *align = ALIGNMENT(double);
6150                 return 8;
6151         case MONO_NATIVE_INT:
6152         case MONO_NATIVE_UINT:
6153         case MONO_NATIVE_LPSTR:
6154         case MONO_NATIVE_LPWSTR:
6155         case MONO_NATIVE_LPTSTR:
6156         case MONO_NATIVE_BSTR:
6157         case MONO_NATIVE_ANSIBSTR:
6158         case MONO_NATIVE_TBSTR:
6159         case MONO_NATIVE_LPARRAY:
6160         case MONO_NATIVE_SAFEARRAY:
6161         case MONO_NATIVE_IUNKNOWN:
6162         case MONO_NATIVE_IDISPATCH:
6163         case MONO_NATIVE_INTERFACE:
6164         case MONO_NATIVE_ASANY:
6165         case MONO_NATIVE_FUNC:
6166         case MONO_NATIVE_LPSTRUCT:
6167                 *align = ALIGNMENT(gpointer);
6168                 return sizeof (gpointer);
6169         case MONO_NATIVE_STRUCT: 
6170                 klass = mono_class_from_mono_type (type);
6171                 return mono_class_native_size (klass, align);
6172         case MONO_NATIVE_BYVALTSTR: {
6173                 int esize = unicode ? 2: 1;
6174                 g_assert (mspec);
6175                 *align = esize;
6176                 return mspec->data.array_data.num_elem * esize;
6177         }
6178         case MONO_NATIVE_BYVALARRAY: {
6179                 int esize;
6180                 klass = mono_class_from_mono_type (type);
6181                 esize = mono_class_native_size (klass->element_class, align);
6182                 g_assert (mspec);
6183                 return mspec->data.array_data.num_elem * esize;
6184         }
6185         case MONO_NATIVE_CUSTOM:
6186                 g_assert_not_reached ();
6187                 break;
6188         case MONO_NATIVE_CURRENCY:
6189         case MONO_NATIVE_VBBYREFSTR:
6190         default:
6191                 g_error ("native type %02x not implemented", native_type); 
6192                 break;
6193         }
6194         g_assert_not_reached ();
6195         return 0;
6196 }
6197
6198 gpointer
6199 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding)
6200 {
6201         MonoType *t;
6202         MonoClass *klass;
6203
6204         if (o == NULL)
6205                 return NULL;
6206
6207         t = &o->vtable->klass->byval_arg;
6208         switch (t->type) {
6209         case MONO_TYPE_I4:
6210         case MONO_TYPE_U4:
6211         case MONO_TYPE_PTR:
6212         case MONO_TYPE_I1:
6213         case MONO_TYPE_U1:
6214         case MONO_TYPE_BOOLEAN:
6215         case MONO_TYPE_I2:
6216         case MONO_TYPE_U2:
6217         case MONO_TYPE_CHAR:
6218         case MONO_TYPE_I8:
6219         case MONO_TYPE_U8:
6220         case MONO_TYPE_R4:
6221         case MONO_TYPE_R8:
6222                 return mono_object_unbox (o);
6223                 break;
6224         case MONO_TYPE_STRING:
6225                 switch (string_encoding) {
6226                 case MONO_NATIVE_LPWSTR:
6227                         return mono_string_to_utf16 ((MonoString*)o);
6228                         break;
6229                 case MONO_NATIVE_LPSTR:
6230                         return mono_string_to_utf8 ((MonoString*)o);
6231                         break;
6232                 default:
6233                         g_warning ("marshaling conversion %d not implemented", string_encoding);
6234                         g_assert_not_reached ();
6235                 }
6236                 break;
6237         case MONO_TYPE_CLASS:
6238         case MONO_TYPE_VALUETYPE: {
6239                 MonoMethod *method;
6240                 gpointer pa [3];
6241                 gpointer res;
6242                 MonoBoolean delete_old = FALSE;
6243
6244                 klass = t->data.klass;
6245
6246                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
6247                         break;
6248
6249                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6250                         klass->blittable || klass->enumtype)
6251                         return mono_object_unbox (o);
6252
6253                 res = g_malloc0 (mono_class_native_size (klass, NULL));
6254
6255                 method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
6256
6257                 pa [0] = o;
6258                 pa [1] = &res;
6259                 pa [2] = &delete_old;
6260
6261                 mono_runtime_invoke (method, NULL, pa, NULL);
6262
6263                 return res;
6264         }
6265         }
6266
6267         mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
6268
6269         return NULL;
6270 }
6271
6272 void
6273 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding)
6274 {
6275         MonoType *t;
6276         MonoClass *klass;
6277
6278         /* FIXME: Free embedded data as well */
6279
6280         if (o == NULL)
6281                 return;
6282
6283         t = &o->vtable->klass->byval_arg;
6284         switch (t->type) {
6285         case MONO_TYPE_STRING:
6286                 switch (string_encoding) {
6287                 case MONO_NATIVE_LPWSTR:
6288                         g_free (ptr);
6289                         break;
6290                 case MONO_NATIVE_LPSTR:
6291                         g_free (ptr);
6292                         break;
6293                 default:
6294                         g_warning ("marshaling conversion %d not implemented", string_encoding);
6295                         g_assert_not_reached ();
6296                 }
6297                 break;
6298         case MONO_TYPE_CLASS:
6299         case MONO_TYPE_VALUETYPE: {
6300                 klass = t->data.klass;
6301
6302                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6303                         klass->blittable || klass->enumtype)
6304                         break;
6305
6306                 g_free (ptr);
6307                 break;
6308         }
6309         default:
6310                 break;
6311         }
6312 }