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
157         method = delegate->method_info->method;
158         invoke = mono_find_method_by_name (klass, "Invoke", method->signature->param_count);
159
160         mspecs = g_new (MonoMarshalSpec*, invoke->signature->param_count + 1);
161         mono_method_get_marshal_info (invoke, mspecs);
162
163         wrapper = mono_marshal_get_managed_wrapper (method, delegate->target, mspecs);
164
165         for (i = invoke->signature->param_count; i >= 0; i--)
166                 g_free (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 (EmitMarshalContext *m, int argnum, MonoType *t, 
3678                                                           MonoMarshalSpec *spec, int conv_arg, 
3679                                                           MonoType **conv_arg_type, MarshalAction action)
3680 {
3681         MonoMethodBuilder *mb = m->mb;
3682         MonoClass *klass;
3683         int pos;
3684
3685         /* Ensure that we have marshalling info for this param */
3686         mono_marshal_load_type_info (mono_class_from_mono_type (t));
3687
3688         if (spec && spec->native == MONO_NATIVE_CUSTOM)
3689                 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
3690
3691         if (spec && spec->native == MONO_NATIVE_ASANY)
3692                 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
3693                         
3694         switch (t->type) {
3695         case MONO_TYPE_VALUETYPE:
3696                 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
3697         case MONO_TYPE_STRING: {
3698                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
3699                 
3700                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3701                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3702
3703                 if (t->byref) {
3704                         if (t->attrs & PARAM_ATTRIBUTE_OUT)
3705                                 break;
3706
3707                         mono_mb_emit_ldarg (mb, argnum);
3708                         mono_mb_emit_byte (mb, CEE_LDIND_I);                            
3709                 } else {
3710                         mono_mb_emit_ldarg (mb, argnum);
3711                 }
3712
3713                 switch (encoding) {
3714                 case MONO_NATIVE_LPWSTR:
3715                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPWSTR));
3716                         break;
3717                 case MONO_NATIVE_LPSTR:
3718                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPSTR));
3719                         break;
3720                 case MONO_NATIVE_LPTSTR:
3721                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_STR_LPTSTR));
3722                         break;
3723                 default: {
3724                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
3725                         MonoException *exc = mono_get_exception_not_implemented (msg);
3726                         g_warning (msg);
3727                         g_free (msg);
3728                         mono_raise_exception (exc);
3729                 }
3730                 }
3731
3732                 mono_mb_emit_stloc (mb, conv_arg);
3733                 break;
3734         }
3735         case MONO_TYPE_CLASS:
3736         case MONO_TYPE_OBJECT:
3737                 klass = t->data.klass;
3738
3739                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3740                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3741
3742                 if (klass->delegate) {
3743                         g_assert (!t->byref);
3744                         mono_mb_emit_ldarg (mb, argnum);
3745                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
3746                         mono_mb_emit_stloc (mb, conv_arg);
3747                 } else if (klass == mono_defaults.stringbuilder_class) {
3748                         MonoMarshalNative encoding = mono_marshal_get_stringbuilder_to_ptr_encoding (m->piinfo, spec);
3749                         
3750                         g_assert (!t->byref);
3751                         mono_mb_emit_ldarg (mb, argnum);
3752
3753                         if (encoding != -1)
3754                                 mono_mb_emit_icall (mb, conv_to_icall (encoding));
3755                         else {
3756                                 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
3757                                 MonoException *exc = mono_get_exception_not_implemented (msg);
3758                                 g_warning (msg);
3759                                 g_free (msg);
3760                                 mono_raise_exception (exc);
3761                         }
3762
3763                         mono_mb_emit_stloc (mb, conv_arg);
3764                 } else if (klass->blittable) {
3765                         mono_mb_emit_ldarg (mb, argnum);
3766                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3767                         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3768                         mono_mb_emit_icon (mb, sizeof (MonoObject));
3769                         mono_mb_emit_byte (mb, CEE_ADD);
3770                         mono_mb_emit_stloc (mb, conv_arg);
3771                         break;
3772                 } else {
3773                         mono_mb_emit_byte (mb, CEE_LDNULL);
3774                         mono_mb_emit_stloc (mb, conv_arg);
3775
3776                         if (t->byref) {
3777                                 /* we dont need any conversions for out parameters */
3778                                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
3779                                         break;
3780
3781                                 mono_mb_emit_ldarg (mb, argnum);                                
3782                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3783
3784                         } else {
3785                                 mono_mb_emit_ldarg (mb, argnum);
3786                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3787                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
3788                         }
3789                                 
3790                         /* store the address of the source into local variable 0 */
3791                         mono_mb_emit_byte (mb, CEE_STLOC_0);
3792                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
3793                         mono_mb_emit_byte (mb, CEE_BRFALSE);
3794                         pos = mb->pos;
3795                         mono_mb_emit_i4 (mb, 0);
3796
3797                         /* allocate space for the native struct and store the address */
3798                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
3799                         mono_mb_emit_byte (mb, CEE_PREFIX1);
3800                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
3801                         mono_mb_emit_stloc (mb, conv_arg);
3802                                 
3803                         /* set the src_ptr */
3804                         mono_mb_emit_byte (mb, CEE_LDLOC_0);
3805                         mono_mb_emit_icon (mb, sizeof (MonoObject));
3806                         mono_mb_emit_byte (mb, CEE_ADD);
3807                         mono_mb_emit_byte (mb, CEE_STLOC_0);
3808
3809                         /* set dst_ptr */
3810                         mono_mb_emit_ldloc (mb, conv_arg);
3811                         mono_mb_emit_byte (mb, CEE_STLOC_1);
3812
3813                         /* emit valuetype conversion code */
3814                         emit_struct_conv (mb, klass, FALSE);
3815
3816                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
3817                 }
3818
3819                 break;
3820         case MONO_TYPE_ARRAY:
3821         case MONO_TYPE_SZARRAY:
3822                 klass = mono_class_from_mono_type (t);
3823                 
3824                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3825                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3826
3827                 if (klass->element_class == mono_defaults.string_class) {
3828                         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
3829
3830                         mono_mb_emit_ldarg (mb, argnum);
3831                         if (t->byref)
3832                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3833
3834                         switch (encoding) {
3835                         case MONO_NATIVE_LPSTR:
3836                                 mono_mb_emit_icall (mb, mono_marshal_string_array);
3837                                 break;
3838                         case MONO_NATIVE_LPWSTR:
3839                                 mono_mb_emit_icall (mb, mono_marshal_string_array_to_unicode);
3840                                 break;
3841                         default: {
3842                                 char *msg = g_strdup_printf ("string array marshalling conversion %d not implemented", encoding);
3843                                 MonoException *exc = mono_get_exception_not_implemented (msg);
3844                                 g_warning (msg);
3845                                 g_free (msg);
3846                                 mono_raise_exception (exc);
3847                         }
3848                         }
3849                         mono_mb_emit_stloc (mb, conv_arg);
3850                 }
3851                 else if (klass->element_class->blittable) {
3852                         mono_mb_emit_ldarg (mb, argnum);
3853                         if (t->byref)
3854                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3855                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
3856                         mono_mb_emit_stloc (mb, conv_arg);
3857                 }
3858                 else {
3859                         MonoClass *eklass;
3860                         guint32 label1, label2, label3;
3861                         int index_var, src_var, dest_ptr, esize;
3862                         MonoMarshalNative encoding = mono_marshal_get_stringbuilder_to_ptr_encoding (m->piinfo, spec);
3863
3864                         dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3865
3866                         eklass = klass->element_class;
3867
3868                         src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3869                         mono_mb_emit_ldarg (mb, argnum);
3870                         if (t->byref)
3871                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
3872                         mono_mb_emit_stloc (mb, src_var);
3873
3874                         /* Check null */
3875                         mono_mb_emit_ldloc (mb, src_var);
3876                         mono_mb_emit_stloc (mb, conv_arg);
3877                         mono_mb_emit_ldloc (mb, src_var);
3878                         mono_mb_emit_byte (mb, CEE_BRFALSE);
3879                         label1 = mb->pos;
3880                         mono_mb_emit_i4 (mb, 0);
3881
3882                         if (eklass == mono_defaults.stringbuilder_class) {
3883                                 if (encoding == -1) {
3884                                         char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
3885                                         MonoException *exc = mono_get_exception_not_implemented (msg);
3886                                         g_warning (msg);
3887                                         g_free (msg);
3888                                         mono_raise_exception (exc);
3889                                 }
3890                         }
3891
3892                         if (eklass == mono_defaults.stringbuilder_class)
3893                                 esize = sizeof (gpointer);
3894                         else
3895                                 esize = mono_class_native_size (eklass, NULL);
3896
3897                         /* allocate space for the native struct and store the address */
3898                         mono_mb_emit_icon (mb, esize);
3899                         mono_mb_emit_ldloc (mb, src_var);
3900                         mono_mb_emit_byte (mb, CEE_LDLEN);
3901                         mono_mb_emit_byte (mb, CEE_MUL);
3902                         mono_mb_emit_byte (mb, CEE_PREFIX1);
3903                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
3904                         mono_mb_emit_stloc (mb, conv_arg);
3905
3906                         mono_mb_emit_ldloc (mb, conv_arg);
3907                         mono_mb_emit_stloc (mb, dest_ptr);
3908
3909                         /* Emit marshalling loop */
3910                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
3911                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3912                         mono_mb_emit_stloc (mb, index_var);
3913                         label2 = mb->pos;
3914                         mono_mb_emit_ldloc (mb, index_var);
3915                         mono_mb_emit_ldloc (mb, src_var);
3916                         mono_mb_emit_byte (mb, CEE_LDLEN);
3917                         mono_mb_emit_byte (mb, CEE_BGE);
3918                         label3 = mb->pos;
3919                         mono_mb_emit_i4 (mb, 0);
3920
3921                         /* Emit marshalling code */
3922
3923                         if (eklass == mono_defaults.stringbuilder_class) {
3924                                 mono_mb_emit_ldloc (mb, dest_ptr);
3925                                 mono_mb_emit_ldloc (mb, src_var);
3926                                 mono_mb_emit_ldloc (mb, index_var);
3927                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3928                                 mono_mb_emit_icall (mb, conv_to_icall (encoding));
3929                                 mono_mb_emit_byte (mb, CEE_STIND_I);
3930                         }
3931                         else {
3932                                 /* set the src_ptr */
3933                                 mono_mb_emit_ldloc (mb, src_var);
3934                                 mono_mb_emit_ldloc (mb, index_var);
3935                                 mono_mb_emit_byte (mb, CEE_LDELEMA);
3936                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
3937                                 mono_mb_emit_byte (mb, CEE_STLOC_0);
3938
3939                                 /* set dst_ptr */
3940                                 mono_mb_emit_ldloc (mb, dest_ptr);
3941                                 mono_mb_emit_byte (mb, CEE_STLOC_1);
3942
3943                                 /* emit valuetype conversion code */
3944                                 emit_struct_conv (mb, eklass, FALSE);
3945                         }
3946
3947                         mono_mb_emit_add_to_local (mb, index_var, 1);
3948                         mono_mb_emit_add_to_local (mb, dest_ptr, esize);
3949                         
3950                         mono_mb_emit_byte (mb, CEE_BR);
3951                         mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
3952
3953                         mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
3954                         mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
3955                 }
3956
3957                 break;
3958         case MONO_TYPE_BOOLEAN: {
3959                 MonoType *local_type;
3960                 int variant_bool = 0;
3961                 if (!t->byref)
3962                         break;
3963                 if (spec == NULL) {
3964                         local_type = &mono_defaults.int32_class->byval_arg;
3965                 } else {
3966                         switch (spec->native) {
3967                         case MONO_NATIVE_I1:
3968                                 local_type = &mono_defaults.byte_class->byval_arg;
3969                                 break;
3970                         case MONO_NATIVE_VARIANTBOOL:
3971                                 local_type = &mono_defaults.int16_class->byval_arg;
3972                                 variant_bool = 1;
3973                                 break;
3974                         default:
3975                                 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
3976                                 break;
3977                         }
3978                 }
3979                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
3980                 conv_arg = mono_mb_add_local (mb, local_type);
3981                 mono_mb_emit_ldarg (mb, argnum);
3982                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
3983                 if (variant_bool)
3984                         mono_mb_emit_byte (mb, CEE_NEG);
3985                 mono_mb_emit_stloc (mb, conv_arg);
3986                 break;
3987         }
3988         }
3989
3990         return conv_arg;
3991 }
3992
3993 /**
3994  * mono_marshal_get_native_wrapper:
3995  * @method: The MonoMethod to wrap.
3996  *
3997  * generates IL code for the pinvoke wrapper (the generated method
3998  * calls the unmanaged code in method->addr)
3999  */
4000 MonoMethod *
4001 mono_marshal_get_native_wrapper (MonoMethod *method)
4002 {
4003         EmitMarshalContext m;
4004         MonoMethodSignature *sig, *csig;
4005         MonoMethodPInvoke *piinfo;
4006         MonoMethodBuilder *mb;
4007         MonoMarshalSpec **mspecs;
4008         MonoMethod *res;
4009         GHashTable *cache;
4010         MonoClass *klass;
4011         gboolean pinvoke = FALSE;
4012         int i, pos, argnum, *tmp_locals;
4013         int type;
4014         const char *exc_class = "MissingMethodException";
4015         const char *exc_arg = NULL;
4016
4017         g_assert (method != NULL);
4018         g_assert (method->signature->pinvoke);
4019
4020         cache = method->klass->image->native_wrapper_cache;
4021         if ((res = mono_marshal_find_in_cache (cache, method)))
4022                 return res;
4023
4024         sig = method->signature;
4025
4026         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
4027             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
4028                 pinvoke = TRUE;
4029
4030         if (!method->addr) {
4031                 if (pinvoke)
4032                         mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
4033                 else
4034                         method->addr = mono_lookup_internal_call (method);
4035         }
4036
4037         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
4038
4039         mb->method->save_lmf = 1;
4040
4041         piinfo = (MonoMethodPInvoke *)method;
4042
4043         if (!method->addr) {
4044                 mono_mb_emit_exception (mb, exc_class, exc_arg);
4045                 csig = mono_metadata_signature_dup (sig);
4046                 csig->pinvoke = 0;
4047                 res = mono_mb_create_and_cache (cache, method,
4048                                                                                 mb, csig, csig->param_count + 16);
4049                 mono_mb_free (mb);
4050                 return res;
4051         }
4052
4053         m.mb = mb;
4054         m.piinfo = piinfo;
4055
4056         /* internal calls: we simply push all arguments and call the method (no conversions) */
4057         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
4058
4059                 /* hack - string constructors returns a value */
4060                 if (method->string_ctor) {
4061                         csig = mono_metadata_signature_dup (sig);
4062                         csig->ret = &mono_defaults.string_class->byval_arg;
4063                 } else
4064                         csig = sig;
4065
4066                 if (sig->hasthis)
4067                         mono_mb_emit_byte (mb, CEE_LDARG_0);
4068
4069                 for (i = 0; i < sig->param_count; i++)
4070                         mono_mb_emit_ldarg (mb, i + sig->hasthis);
4071
4072                 g_assert (method->addr);
4073                 mono_mb_emit_native_call (mb, csig, method->addr);
4074                 emit_thread_interrupt_checkpoint (mb);
4075                 mono_mb_emit_byte (mb, CEE_RET);
4076
4077                 csig = mono_metadata_signature_dup (csig);
4078                 csig->pinvoke = 0;
4079                 res = mono_mb_create_and_cache (cache, method,
4080                                                                                 mb, csig, csig->param_count + 16);
4081                 mono_mb_free (mb);
4082                 return res;
4083         }
4084
4085         g_assert (pinvoke);
4086
4087         mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
4088         mono_method_get_marshal_info (method, mspecs);
4089
4090         /* pinvoke: we need to convert the arguments if necessary */
4091
4092         /* we copy the signature, so that we can set pinvoke to 0 */
4093         csig = mono_metadata_signature_dup (sig);
4094         csig->pinvoke = 1;
4095
4096         /* we allocate local for use with emit_struct_conv() */
4097         /* allocate local 0 (pointer) src_ptr */
4098         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4099         /* allocate local 1 (pointer) dst_ptr */
4100         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4101         /* allocate local 2 (boolean) delete_old */
4102         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
4103
4104         /* delete_old = FALSE */
4105         mono_mb_emit_icon (mb, 0);
4106         mono_mb_emit_byte (mb, CEE_STLOC_2);
4107
4108         if (!MONO_TYPE_IS_VOID(sig->ret)) {
4109                 /* allocate local 3 to store the return value */
4110                 mono_mb_add_local (mb, sig->ret);
4111         }
4112
4113         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
4114                 /* Return type custom marshaling */
4115                 /*
4116                  * Since we can't determine the return type of the unmanaged function,
4117                  * we assume it returns a pointer, and pass that pointer to
4118                  * MarshalNativeToManaged.
4119                  */
4120                 csig->ret = &mono_defaults.int_class->byval_arg;
4121         }
4122
4123         /* we first do all conversions */
4124         tmp_locals = alloca (sizeof (int) * sig->param_count);
4125
4126         for (i = 0; i < sig->param_count; i ++) {
4127                 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
4128         }
4129
4130         /* push all arguments */
4131
4132         if (sig->hasthis)
4133                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4134
4135         for (i = 0; i < sig->param_count; i++) {
4136                 MonoType *t = sig->params [i];
4137                 MonoMarshalSpec *spec = mspecs [i + 1];
4138
4139                 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY)))
4140                         emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
4141                 else {
4142                         argnum = i + sig->hasthis;
4143
4144                         switch (t->type) {
4145                         case MONO_TYPE_BOOLEAN:
4146                                 if (t->byref) {
4147                                         g_assert (tmp_locals [i]);
4148                                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
4149                                 } else
4150                                         mono_mb_emit_ldarg (mb, argnum);
4151                                 break;
4152                         case MONO_TYPE_I1:
4153                         case MONO_TYPE_U1:
4154                         case MONO_TYPE_I2:
4155                         case MONO_TYPE_U2:
4156                         case MONO_TYPE_I4:
4157                         case MONO_TYPE_U4:
4158                         case MONO_TYPE_I:
4159                         case MONO_TYPE_U:
4160                         case MONO_TYPE_PTR:
4161                         case MONO_TYPE_R4:
4162                         case MONO_TYPE_R8:
4163                         case MONO_TYPE_I8:
4164                         case MONO_TYPE_U8:
4165                                 mono_mb_emit_ldarg (mb, argnum);
4166                                 break;
4167                         case MONO_TYPE_VALUETYPE:
4168                                 emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
4169                                 break;
4170                         case MONO_TYPE_STRING:
4171                         case MONO_TYPE_CLASS:
4172                         case MONO_TYPE_OBJECT:
4173                         case MONO_TYPE_ARRAY:
4174                         case MONO_TYPE_SZARRAY:
4175                                 g_assert (tmp_locals [i]);
4176                                 if (t->byref) 
4177                                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
4178                                 else
4179                                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
4180                                 break;
4181                         case MONO_TYPE_CHAR:
4182                                 /* fixme: dont know how to marshal that. We cant simply
4183                                  * convert it to a one byte UTF8 character, because an
4184                                  * unicode character may need more that one byte in UTF8 */
4185                                 mono_mb_emit_ldarg (mb, argnum);
4186                                 break;
4187                         case MONO_TYPE_TYPEDBYREF:
4188                         case MONO_TYPE_FNPTR:
4189                         default:
4190                                 g_warning ("type 0x%02x unknown", t->type);     
4191                                 g_assert_not_reached ();
4192                         }
4193                 }
4194         }                       
4195
4196         /* call the native method */
4197         mono_mb_emit_native_call (mb, csig, method->addr);
4198
4199         /* Set LastError if needed */
4200         if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
4201                 MonoMethodSignature *lasterr_sig;
4202
4203                 lasterr_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4204                 lasterr_sig->ret = &mono_defaults.void_class->byval_arg;
4205                 lasterr_sig->pinvoke = 1;
4206
4207                 mono_mb_emit_native_call (mb, lasterr_sig, mono_marshal_set_last_error);
4208         }               
4209
4210         /* Ensure that we have marshalling info for the return */
4211         mono_marshal_load_type_info (mono_class_from_mono_type (sig->ret));
4212
4213         /* convert the result */
4214         if (!sig->ret->byref) {
4215                 MonoMarshalSpec *spec = mspecs [0];
4216                 type = sig->ret->type;
4217
4218                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
4219                         emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4220                 } else {
4221
4222                 handle_enum:
4223                         switch (type) {
4224                         case MONO_TYPE_VOID:
4225                                 break;
4226                         case MONO_TYPE_I1:
4227                         case MONO_TYPE_U1:
4228                         case MONO_TYPE_I2:
4229                         case MONO_TYPE_U2:
4230                         case MONO_TYPE_I4:
4231                         case MONO_TYPE_U4:
4232                         case MONO_TYPE_I:
4233                         case MONO_TYPE_U:
4234                         case MONO_TYPE_PTR:
4235                         case MONO_TYPE_R4:
4236                         case MONO_TYPE_R8:
4237                         case MONO_TYPE_I8:
4238                         case MONO_TYPE_U8:
4239                                 /* no conversions necessary */
4240                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4241                                 break;
4242                         case MONO_TYPE_BOOLEAN:
4243                                 /* maybe we need to make sure that it fits within 8 bits */
4244                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4245                                 break;
4246                         case MONO_TYPE_VALUETYPE:
4247                                 klass = sig->ret->data.klass;
4248                                 if (klass->enumtype) {
4249                                         type = sig->ret->data.klass->enum_basetype->type;
4250                                         goto handle_enum;
4251                                 }
4252                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
4253                                 break;
4254                         case MONO_TYPE_STRING:
4255                                 mono_mb_emit_byte (mb, CEE_STLOC_0);
4256                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4257                                 
4258                                 if (spec) {
4259                                         switch (spec->native) {
4260                                         case MONO_NATIVE_LPWSTR:
4261                                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPWSTR_STR));
4262                                                 break;
4263                                         default:
4264                                                 g_warning ("marshalling conversion not implemented");
4265                                                 g_assert_not_reached ();
4266                                         }
4267                                 } else {
4268                                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
4269                                 }
4270                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4271
4272                                 /* free the string */
4273                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4274                                 mono_mb_emit_icall (mb, g_free);
4275                                 break;
4276                         case MONO_TYPE_CLASS:
4277                         case MONO_TYPE_OBJECT:
4278                                 klass = sig->ret->data.klass;
4279
4280                                 /* set src */
4281                                 mono_mb_emit_byte (mb, CEE_STLOC_0);
4282
4283                                 mono_mb_emit_byte (mb, CEE_LDNULL);
4284                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4285
4286
4287                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
4288                                 mono_mb_emit_byte (mb, CEE_BRFALSE);
4289                                 pos = mb->pos;
4290                                 mono_mb_emit_i4 (mb, 0);
4291
4292                                 /* allocate result object */
4293
4294                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4295                                 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
4296                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4297                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4298                                 
4299                                 /* set dst  */
4300
4301                                 mono_mb_emit_byte (mb, CEE_LDLOC_3);
4302                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4303                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
4304                                 mono_mb_emit_icon (mb, sizeof (MonoObject));
4305                                 mono_mb_emit_byte (mb, CEE_ADD);
4306                                 mono_mb_emit_byte (mb, CEE_STLOC_1);
4307                                                         
4308                                 /* emit conversion code */
4309                                 emit_struct_conv (mb, klass, TRUE);
4310
4311                                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4312                                 break;
4313                         case MONO_TYPE_ARRAY:
4314                         case MONO_TYPE_SZARRAY:
4315                                 /* fixme: we need conversions here */
4316                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4317                                 break;
4318                         case MONO_TYPE_CHAR:
4319                                 /* fixme: we need conversions here */
4320                                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4321                                 break;
4322                         case MONO_TYPE_TYPEDBYREF:
4323                         case MONO_TYPE_FNPTR:
4324                         default:
4325                                 g_warning ("return type 0x%02x unknown", sig->ret->type);       
4326                                 g_assert_not_reached ();
4327                         }
4328                 }
4329         } else {
4330                 mono_mb_emit_byte (mb, CEE_STLOC_3);
4331         }
4332
4333         /* 
4334          * Need to call this after converting the result since MONO_VTADDR needs 
4335          * to be adjacent to the call instruction.
4336          */
4337         emit_thread_interrupt_checkpoint (mb);
4338
4339         /* we need to convert byref arguments back and free string arrays */
4340         for (i = 0; i < sig->param_count; i++) {
4341                 MonoType *t = sig->params [i];
4342                 MonoMarshalSpec *spec = mspecs [i + 1];
4343
4344                 argnum = i + sig->hasthis;
4345
4346                 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
4347                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
4348                         continue;
4349                 }
4350
4351                 switch (t->type) {
4352                 case MONO_TYPE_STRING:
4353                         if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4354                                 mono_mb_emit_ldarg (mb, argnum);
4355                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4356                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
4357                                 mono_mb_emit_byte (mb, CEE_STIND_I);            
4358                         } else {
4359                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4360                                 mono_mb_emit_icall (mb, g_free);
4361                         }
4362                         break;
4363                 case MONO_TYPE_CLASS:
4364                 case MONO_TYPE_OBJECT:                  
4365                         if (t->data.klass == mono_defaults.stringbuilder_class) {
4366                                 gboolean need_free;
4367                                 MonoMarshalNative encoding;
4368
4369                                 encoding = mono_marshal_get_ptr_to_stringbuilder_encoding (piinfo, spec, &need_free);
4370
4371                                 g_assert (!t->byref);
4372                                 g_assert (encoding != -1);
4373
4374                                 mono_mb_emit_ldarg (mb, argnum);
4375                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4376
4377                                 mono_mb_emit_icall (mb, conv_to_icall (encoding));
4378
4379                                 if (need_free) {
4380                                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
4381                                         mono_mb_emit_icall (mb, g_free);
4382                                 }
4383                                 break;
4384                         }
4385                         
4386                         if (!(t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)))
4387                                 continue;
4388
4389                         if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4390                                 /* allocate a new object */
4391                                 mono_mb_emit_ldarg (mb, argnum);
4392                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4393                                 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
4394                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
4395                                 mono_mb_emit_byte (mb, CEE_STIND_I);
4396                         }
4397
4398                         /* dst = *argument */
4399                         mono_mb_emit_ldarg (mb, argnum);
4400
4401                         if (t->byref)
4402                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4403
4404                         mono_mb_emit_byte (mb, CEE_STLOC_1);
4405
4406                         mono_mb_emit_byte (mb, CEE_LDLOC_1);
4407                         mono_mb_emit_byte (mb, CEE_BRFALSE);
4408                         pos = mb->pos;
4409                         mono_mb_emit_i4 (mb, 0);
4410
4411                         mono_mb_emit_byte (mb, CEE_LDLOC_1);
4412                         mono_mb_emit_icon (mb, sizeof (MonoObject));
4413                         mono_mb_emit_byte (mb, CEE_ADD);
4414                         mono_mb_emit_byte (mb, CEE_STLOC_1);
4415                         
4416                         /* src = tmp_locals [i] */
4417                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
4418                         mono_mb_emit_byte (mb, CEE_STLOC_0);
4419
4420                         /* emit valuetype conversion code */
4421                         emit_struct_conv (mb, t->data.klass, TRUE);
4422
4423                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4424                         break;
4425                 case MONO_TYPE_VALUETYPE:
4426                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
4427                         break;
4428                 case MONO_TYPE_SZARRAY:
4429                         klass = mono_class_from_mono_type (t);
4430
4431                         if (klass->element_class == mono_defaults.string_class) {
4432                                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
4433                                 g_assert (tmp_locals [i]);
4434
4435                                 mono_mb_emit_ldarg (mb, argnum);
4436                                 if (t->byref)
4437                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
4438                                 mono_mb_emit_byte (mb, CEE_BRFALSE);
4439                                 pos = mb->pos;
4440                                 mono_mb_emit_i4 (mb, 0);
4441
4442                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4443
4444                                 switch (encoding) {
4445                                 case MONO_NATIVE_LPWSTR:
4446                                         /* 
4447                                          * The array elements point to the managed string data so 
4448                                          * they don't need to be freed.
4449                                          */
4450                                         mono_mb_emit_icall (mb, g_free);
4451                                         break;
4452                                 default:
4453                                         mono_mb_emit_ldarg (mb, argnum);
4454                                         if (t->byref)
4455                                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4456                                         mono_mb_emit_byte (mb, CEE_LDLEN);                              
4457                                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_ARRAY));
4458                                         break;                                  
4459                                 }
4460
4461                                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
4462                         }
4463
4464                         if (t->byref)
4465                                 /* 
4466                                  * FIXME: Need to convert data back but we don't know the
4467                                  * size of the array.
4468                                  */
4469                                 continue;
4470
4471                         /* Character arrays are implicitly marshalled as [Out] */
4472                         if ((klass->element_class == mono_defaults.char_class) || (klass->element_class == mono_defaults.stringbuilder_class) || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
4473                                 /* FIXME: Optimize blittable case */
4474                                 MonoClass *eklass;
4475                                 guint32 label1, label2, label3;
4476                                 int index_var, src_ptr, esize;
4477
4478                                 eklass = klass->element_class;
4479                                 if (eklass == mono_defaults.stringbuilder_class)
4480                                         esize = sizeof (gpointer);
4481                                 else
4482                                         esize = mono_class_native_size (eklass, NULL);
4483                                 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4484
4485                                 /* Check null */
4486                                 mono_mb_emit_ldarg (mb, argnum);
4487                                 mono_mb_emit_byte (mb, CEE_BRFALSE);
4488                                 label1 = mb->pos;
4489                                 mono_mb_emit_i4 (mb, 0);
4490
4491                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
4492                                 mono_mb_emit_stloc (mb, src_ptr);
4493
4494                                 /* Emit marshalling loop */
4495                                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
4496                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4497                                 mono_mb_emit_stloc (mb, index_var);
4498                                 label2 = mb->pos;
4499                                 mono_mb_emit_ldloc (mb, index_var);
4500                                 mono_mb_emit_ldarg (mb, argnum);
4501                                 mono_mb_emit_byte (mb, CEE_LDLEN);
4502                                 mono_mb_emit_byte (mb, CEE_BGE);
4503                                 label3 = mb->pos;
4504                                 mono_mb_emit_i4 (mb, 0);
4505
4506                                 /* Emit marshalling code */
4507
4508                                 if (eklass == mono_defaults.stringbuilder_class) {
4509                                         gboolean need_free;
4510                                         MonoMarshalNative encoding = mono_marshal_get_ptr_to_stringbuilder_encoding (piinfo, spec, &need_free);
4511
4512                                         g_assert (encoding != -1);
4513
4514                                         /* dest */
4515                                         mono_mb_emit_ldarg (mb, argnum);
4516                                         mono_mb_emit_ldloc (mb, index_var);
4517                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4518
4519                                         /* src */
4520                                         mono_mb_emit_ldloc (mb, src_ptr);
4521                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
4522
4523                                         mono_mb_emit_icall (mb, conv_to_icall (encoding));
4524
4525                                         if (need_free) {
4526                                                 /* src */
4527                                                 mono_mb_emit_ldloc (mb, src_ptr);
4528                                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
4529
4530                                                 mono_mb_emit_icall (mb, g_free);
4531                                         }
4532                                 }
4533                                 else {
4534                                         /* set the src_ptr */
4535                                         mono_mb_emit_ldloc (mb, src_ptr);
4536                                         mono_mb_emit_byte (mb, CEE_STLOC_0);
4537
4538                                         /* set dst_ptr */
4539                                         mono_mb_emit_ldarg (mb, argnum);
4540                                         mono_mb_emit_ldloc (mb, index_var);
4541                                         mono_mb_emit_byte (mb, CEE_LDELEMA);
4542                                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
4543                                         mono_mb_emit_byte (mb, CEE_STLOC_1);
4544
4545                                         /* emit valuetype conversion code */
4546                                         emit_struct_conv (mb, eklass, TRUE);
4547                                 }
4548
4549                                 mono_mb_emit_add_to_local (mb, index_var, 1);
4550                                 mono_mb_emit_add_to_local (mb, src_ptr, esize);
4551
4552                                 mono_mb_emit_byte (mb, CEE_BR);
4553                                 mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
4554
4555                                 mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
4556                                 mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
4557                         }
4558                         break;
4559                 case MONO_TYPE_BOOLEAN:
4560                         if (!t->byref)
4561                                 continue;
4562                         mono_mb_emit_ldarg (mb, argnum);
4563                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
4564                         if (mspecs [i + 1] != NULL && mspecs [i + 1]->native == MONO_NATIVE_VARIANTBOOL)
4565                                 mono_mb_emit_byte (mb, CEE_NEG);
4566                         mono_mb_emit_byte (mb, CEE_STIND_I1);
4567                 }
4568         }
4569
4570         if (!MONO_TYPE_IS_VOID(sig->ret))
4571                 mono_mb_emit_byte (mb, CEE_LDLOC_3);
4572
4573         mono_mb_emit_byte (mb, CEE_RET);
4574
4575         csig = mono_metadata_signature_dup (sig);
4576         csig->pinvoke = 0;
4577         res = mono_mb_create_and_cache (cache, method,
4578                                                                         mb, csig, csig->param_count + 16);
4579         mono_mb_free (mb);
4580
4581         for (i = sig->param_count; i >= 0; i--)
4582                 g_free (mspecs [i]);
4583         g_free (mspecs);
4584
4585         /* 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)); */
4586
4587         return res;
4588 }
4589
4590 void
4591 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
4592
4593 static MonoReflectionType *
4594 type_from_handle (MonoType *handle)
4595 {
4596         MonoDomain *domain = mono_domain_get (); 
4597         MonoClass *klass = mono_class_from_mono_type (handle);
4598
4599         MONO_ARCH_SAVE_REGS;
4600
4601         mono_class_init (klass);
4602         return mono_type_get_object (domain, handle);
4603 }
4604
4605 /*
4606  * mono_marshal_get_isinst:
4607  * @klass: the type of the field
4608  *
4609  * This method generates a function which can be used to check if an object is
4610  * an instance of the given type, icluding the case where the object is a proxy.
4611  * The generated function has the following signature:
4612  * MonoObject* __isinst_wrapper_ (MonoObject *obj)
4613  */
4614 MonoMethod *
4615 mono_marshal_get_isinst (MonoClass *klass)
4616 {
4617         static MonoMethodSignature *isint_sig = NULL;
4618         static GHashTable *isinst_hash = NULL; 
4619         MonoMethod *res;
4620         int pos_was_ok, pos_failed, pos_end, pos_end2;
4621         char *name;
4622         MonoMethodBuilder *mb;
4623
4624         EnterCriticalSection (&marshal_mutex);
4625         if (!isinst_hash) 
4626                 isinst_hash = g_hash_table_new (NULL, NULL);
4627         
4628         res = g_hash_table_lookup (isinst_hash, klass);
4629         LeaveCriticalSection (&marshal_mutex);
4630         if (res)
4631                 return res;
4632
4633         if (!isint_sig) {
4634                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4635                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
4636                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
4637                 isint_sig->pinvoke = 0;
4638         }
4639         
4640         name = g_strdup_printf ("__isinst_wrapper_%s", klass->name); 
4641         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
4642         g_free (name);
4643         
4644         mb->method->save_lmf = 1;
4645
4646         /* check if the object is a proxy that needs special cast */
4647         mono_mb_emit_ldarg (mb, 0);
4648         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4649         mono_mb_emit_byte (mb, CEE_MONO_CISINST);
4650         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4651
4652         /* The result of MONO_ISINST can be:
4653                 0) the type check succeeded
4654                 1) the type check did not succeed
4655                 2) a CanCastTo call is needed */
4656         
4657         mono_mb_emit_byte (mb, CEE_DUP);
4658         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
4659
4660         mono_mb_emit_byte (mb, CEE_LDC_I4_2);
4661         pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
4662         
4663         /* get the real proxy from the transparent proxy*/
4664
4665         mono_mb_emit_ldarg (mb, 0);
4666         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
4667         pos_end = mono_mb_emit_branch (mb, CEE_BR);
4668         
4669         /* fail */
4670         
4671         mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
4672         mono_mb_emit_byte (mb, CEE_LDNULL);
4673         pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
4674         
4675         /* success */
4676         
4677         mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
4678         mono_mb_emit_byte (mb, CEE_POP);
4679         mono_mb_emit_ldarg (mb, 0);
4680         
4681         /* the end */
4682         
4683         mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
4684         mono_mb_patch_addr (mb, pos_end2, mb->pos - (pos_end2 + 4));
4685         mono_mb_emit_byte (mb, CEE_RET);
4686
4687         res = mono_mb_create_and_cache (isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
4688         mono_mb_free (mb);
4689
4690         return res;
4691 }
4692
4693 /*
4694  * mono_marshal_get_castclass:
4695  * @klass: the type of the field
4696  *
4697  * This method generates a function which can be used to cast an object to
4698  * an instance of the given type, icluding the case where the object is a proxy.
4699  * The generated function has the following signature:
4700  * MonoObject* __castclass_wrapper_ (MonoObject *obj)
4701  */
4702 MonoMethod *
4703 mono_marshal_get_castclass (MonoClass *klass)
4704 {
4705         static MonoMethodSignature *castclass_sig = NULL;
4706         static GHashTable *castclass_hash = NULL; 
4707         MonoMethod *res;
4708         int pos_was_ok, pos_was_ok2;
4709         char *name;
4710         MonoMethodBuilder *mb;
4711
4712         EnterCriticalSection (&marshal_mutex);
4713         if (!castclass_hash) 
4714                 castclass_hash = g_hash_table_new (NULL, NULL);
4715         
4716         res = g_hash_table_lookup (castclass_hash, klass);
4717         LeaveCriticalSection (&marshal_mutex);
4718         if (res)
4719                 return res;
4720
4721         if (!castclass_sig) {
4722                 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4723                 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
4724                 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
4725                 castclass_sig->pinvoke = 0;
4726         }
4727         
4728         name = g_strdup_printf ("__castclass_wrapper_%s", klass->name); 
4729         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
4730         g_free (name);
4731         
4732         mb->method->save_lmf = 1;
4733
4734         /* check if the object is a proxy that needs special cast */
4735         mono_mb_emit_ldarg (mb, 0);
4736         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4737         mono_mb_emit_byte (mb, CEE_MONO_CCASTCLASS);
4738         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
4739
4740         /* The result of MONO_ISINST can be:
4741                 0) the cast is valid
4742                 1) cast of unknown proxy type
4743                 or an exception if the cast is is invalid
4744         */
4745         
4746         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
4747
4748         /* get the real proxy from the transparent proxy*/
4749
4750         mono_mb_emit_ldarg (mb, 0);
4751         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
4752         pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
4753         
4754         /* fail */
4755         mono_mb_emit_exception (mb, "InvalidCastException", NULL);
4756         
4757         /* success */
4758         mono_mb_patch_addr (mb, pos_was_ok, mb->pos - (pos_was_ok + 4));
4759         mono_mb_patch_addr (mb, pos_was_ok2, mb->pos - (pos_was_ok2 + 4));
4760         mono_mb_emit_ldarg (mb, 0);
4761         
4762         /* the end */
4763         mono_mb_emit_byte (mb, CEE_RET);
4764
4765         res = mono_mb_create_and_cache (castclass_hash, klass, mb, castclass_sig, castclass_sig->param_count + 16);
4766         mono_mb_free (mb);
4767
4768         return res;
4769 }
4770
4771 MonoMethod *
4772 mono_marshal_get_proxy_cancast (MonoClass *klass)
4773 {
4774         static MonoMethodSignature *from_handle_sig = NULL;
4775         static MonoMethodSignature *upgrade_proxy_sig = NULL;
4776         static MonoMethodSignature *isint_sig = NULL;
4777         static GHashTable *proxy_isinst_hash = NULL; 
4778         MonoMethod *res;
4779         int pos_failed, pos_end;
4780         char *name;
4781         MonoMethod *can_cast_to;
4782         MonoMethodDesc *desc;
4783         MonoMethodBuilder *mb;
4784
4785         EnterCriticalSection (&marshal_mutex);
4786         if (!proxy_isinst_hash) 
4787                 proxy_isinst_hash = g_hash_table_new (NULL, NULL);
4788         
4789         res = g_hash_table_lookup (proxy_isinst_hash, klass);
4790         LeaveCriticalSection (&marshal_mutex);
4791         if (res)
4792                 return res;
4793
4794         if (!isint_sig) {
4795                 upgrade_proxy_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
4796                 upgrade_proxy_sig->params [0] = &mono_defaults.object_class->byval_arg;
4797                 upgrade_proxy_sig->params [1] = &mono_defaults.object_class->byval_arg;
4798                 upgrade_proxy_sig->ret = &mono_defaults.void_class->byval_arg;
4799                 upgrade_proxy_sig->pinvoke = 1;
4800
4801                 from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4802                 from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
4803                 from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
4804         
4805                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
4806                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
4807                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
4808                 isint_sig->pinvoke = 0;
4809         }
4810         
4811         name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name); 
4812         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
4813         g_free (name);
4814         
4815         mb->method->save_lmf = 1;
4816
4817         /* get the real proxy from the transparent proxy*/
4818         mono_mb_emit_ldarg (mb, 0);
4819         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
4820         mono_mb_emit_byte (mb, CEE_LDIND_I);
4821         
4822         /* get the refletion type from the type handle */
4823         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4824         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
4825         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &klass->byval_arg));
4826         mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
4827         
4828         mono_mb_emit_ldarg (mb, 0);
4829         
4830         /* make the call to CanCastTo (type, ob) */
4831         desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
4832         can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
4833         g_assert (can_cast_to);
4834         mono_method_desc_free (desc);
4835         mono_mb_emit_byte (mb, CEE_CALLVIRT);
4836         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, can_cast_to));
4837
4838         
4839         pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
4840
4841         /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
4842         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4843         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
4844         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &klass->byval_arg));
4845         mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
4846         mono_mb_emit_ldarg (mb, 0);
4847         
4848         mono_mb_emit_native_call (mb, upgrade_proxy_sig, mono_upgrade_remote_class_wrapper);
4849         emit_thread_interrupt_checkpoint (mb);
4850         
4851         mono_mb_emit_ldarg (mb, 0);
4852         pos_end = mono_mb_emit_branch (mb, CEE_BR);
4853         
4854         /* fail */
4855         
4856         mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
4857         mono_mb_emit_byte (mb, CEE_LDNULL);
4858         
4859         /* the end */
4860         
4861         mono_mb_patch_addr (mb, pos_end, mb->pos - (pos_end + 4));
4862         mono_mb_emit_byte (mb, CEE_RET);
4863
4864         res = mono_mb_create_and_cache (proxy_isinst_hash, klass, mb, isint_sig, isint_sig->param_count + 16);
4865         mono_mb_free (mb);
4866
4867         return res;
4868 }
4869
4870 void
4871 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
4872 {
4873         MonoClass *klass;
4874         klass = mono_class_from_mono_type (rtype->type);
4875         mono_upgrade_remote_class (((MonoObject*)tproxy)->vtable->domain, tproxy->remote_class, klass);
4876         ((MonoObject*)tproxy)->vtable = tproxy->remote_class->vtable;
4877 }
4878
4879 /**
4880  * mono_marshal_get_struct_to_ptr:
4881  * @klass:
4882  *
4883  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
4884  */
4885 MonoMethod *
4886 mono_marshal_get_struct_to_ptr (MonoClass *klass)
4887 {
4888         MonoMethodBuilder *mb;
4889         static MonoMethod *stoptr = NULL;
4890         MonoMethod *res;
4891
4892         g_assert (klass != NULL);
4893
4894         if (klass->str_to_ptr)
4895                 return klass->str_to_ptr;
4896
4897         if (!stoptr) 
4898                 stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
4899         g_assert (stoptr);
4900
4901         mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
4902
4903         if (klass->blittable) {
4904                 mono_mb_emit_byte (mb, CEE_LDARG_1);
4905                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4906                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
4907                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
4908                 mono_mb_emit_byte (mb, CEE_PREFIX1);
4909                 mono_mb_emit_byte (mb, CEE_CPBLK);
4910         } else {
4911
4912                 /* allocate local 0 (pointer) src_ptr */
4913                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4914                 /* allocate local 1 (pointer) dst_ptr */
4915                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4916                 /* allocate local 2 (boolean) delete_old */
4917                 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
4918                 mono_mb_emit_byte (mb, CEE_LDARG_2);
4919                 mono_mb_emit_byte (mb, CEE_STLOC_2);
4920
4921                 /* initialize src_ptr to point to the start of object data */
4922                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4923                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
4924                 mono_mb_emit_byte (mb, CEE_STLOC_0);
4925
4926                 /* initialize dst_ptr */
4927                 mono_mb_emit_byte (mb, CEE_LDARG_1);
4928                 mono_mb_emit_byte (mb, CEE_STLOC_1);
4929
4930                 emit_struct_conv (mb, klass, FALSE);
4931         }
4932
4933         mono_mb_emit_byte (mb, CEE_RET);
4934
4935         res = mono_mb_create_method (mb, stoptr->signature, 0);
4936         mono_mb_free (mb);
4937
4938         klass->str_to_ptr = res;
4939         return res;
4940 }
4941
4942 /**
4943  * mono_marshal_get_ptr_to_struct:
4944  * @klass:
4945  *
4946  * generates IL code for PtrToStructure (IntPtr src, object structure)
4947  */
4948 MonoMethod *
4949 mono_marshal_get_ptr_to_struct (MonoClass *klass)
4950 {
4951         MonoMethodBuilder *mb;
4952         static MonoMethod *ptostr = NULL;
4953         MonoMethod *res;
4954
4955         g_assert (klass != NULL);
4956
4957         if (klass->ptr_to_str)
4958                 return klass->ptr_to_str;
4959
4960         if (!ptostr) 
4961                 ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
4962         g_assert (ptostr);
4963
4964         mb = mono_mb_new (klass, ptostr->name, MONO_WRAPPER_UNKNOWN);
4965
4966         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
4967                 mono_mb_emit_byte (mb, CEE_LDARG_1);
4968                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
4969                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4970                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
4971                 mono_mb_emit_byte (mb, CEE_PREFIX1);
4972                 mono_mb_emit_byte (mb, CEE_CPBLK);
4973         } else {
4974
4975                 /* allocate local 0 (pointer) src_ptr */
4976                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4977                 /* allocate local 1 (pointer) dst_ptr */
4978                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4979                 
4980                 /* initialize src_ptr to point to the start of object data */
4981                 mono_mb_emit_byte (mb, CEE_LDARG_0);
4982                 mono_mb_emit_byte (mb, CEE_STLOC_0);
4983
4984                 /* initialize dst_ptr */
4985                 mono_mb_emit_byte (mb, CEE_LDARG_1);
4986                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
4987                 mono_mb_emit_byte (mb, CEE_STLOC_1);
4988
4989                 emit_struct_conv (mb, klass, TRUE);
4990         }
4991
4992         mono_mb_emit_byte (mb, CEE_RET);
4993
4994         res = mono_mb_create_method (mb, ptostr->signature, 0);
4995         mono_mb_free (mb);
4996
4997         klass->ptr_to_str = res;
4998         return res;
4999 }
5000
5001 /*
5002  * generates IL code for the synchronized wrapper: the generated method
5003  * calls METHOD while locking 'this' or the parent type.
5004  */
5005 MonoMethod *
5006 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
5007 {
5008         static MonoMethodSignature *from_handle_sig = NULL;
5009         static MonoMethod *enter_method, *exit_method;
5010         MonoMethodSignature *sig;
5011         MonoExceptionClause *clause;
5012         MonoMethodHeader *header;
5013         MonoMethodBuilder *mb;
5014         MonoMethod *res;
5015         GHashTable *cache;
5016         int i, pos, this_local, ret_local;
5017
5018         g_assert (method);
5019
5020         if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
5021                 return method;
5022
5023         cache = method->klass->image->synchronized_cache;
5024         if ((res = mono_marshal_find_in_cache (cache, method)))
5025                 return res;
5026
5027         sig = method->signature;
5028
5029         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
5030
5031         /* result */
5032         if (!MONO_TYPE_IS_VOID (sig->ret))
5033                 ret_local = mono_mb_add_local (mb, sig->ret);
5034
5035         /* this */
5036         this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5037
5038         clause = g_new0 (MonoExceptionClause, 1);
5039         clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
5040
5041         if (!enter_method) {
5042                 MonoMethodDesc *desc;
5043
5044                 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
5045                 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
5046                 g_assert (enter_method);
5047                 mono_method_desc_free (desc);
5048                 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
5049                 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
5050                 g_assert (exit_method);
5051                 mono_method_desc_free (desc);
5052
5053                 /*
5054                  * GetTypeFromHandle isn't called as a managed method because it has
5055                  * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
5056                  * transformed into something else by the JIT.
5057                  */
5058                 from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
5059                 from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
5060                 from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
5061         }
5062
5063         /* Push this or the type object */
5064         if (method->flags & METHOD_ATTRIBUTE_STATIC) {
5065                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5066                 mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
5067                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, &method->klass->byval_arg));
5068                 mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
5069         }
5070         else
5071                 mono_mb_emit_ldarg (mb, 0);
5072         mono_mb_emit_stloc (mb, this_local);
5073
5074         /* Call Monitor::Enter() */
5075         mono_mb_emit_ldloc (mb, this_local);
5076         mono_mb_emit_managed_call (mb, enter_method, NULL);
5077
5078         clause->try_offset = mb->pos;
5079
5080         /* Call the method */
5081         if (sig->hasthis)
5082                 mono_mb_emit_ldarg (mb, 0);
5083         for (i = 0; i < sig->param_count; i++)
5084                 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
5085         mono_mb_emit_managed_call (mb, method, method->signature);
5086         if (!MONO_TYPE_IS_VOID (sig->ret))
5087                 mono_mb_emit_stloc (mb, ret_local);
5088
5089         mono_mb_emit_byte (mb, CEE_LEAVE);
5090         pos = mb->pos;
5091         mono_mb_emit_i4 (mb, 0);
5092
5093         clause->try_len = mb->pos - clause->try_offset;
5094         clause->handler_offset = mb->pos;
5095
5096         /* Call Monitor::Exit() */
5097         mono_mb_emit_ldloc (mb, this_local);
5098 /*      mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */
5099         mono_mb_emit_managed_call (mb, exit_method, NULL);
5100         mono_mb_emit_byte (mb, CEE_ENDFINALLY);
5101
5102         clause->handler_len = mb->pos - clause->handler_offset;
5103
5104         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
5105         if (!MONO_TYPE_IS_VOID (sig->ret))
5106                 mono_mb_emit_ldloc (mb, ret_local);
5107         mono_mb_emit_byte (mb, CEE_RET);
5108
5109         res = mono_mb_create_and_cache (cache, method,
5110                                                                         mb, sig, sig->param_count + 16);
5111         mono_mb_free (mb);
5112
5113         header = ((MonoMethodNormal *)res)->header;
5114         header->num_clauses = 1;
5115         header->clauses = clause;
5116
5117         return res;     
5118 }
5119
5120 MonoMethod*
5121 mono_marshal_get_stelemref ()
5122 {
5123         static MonoMethod* ret = NULL;
5124         MonoMethodSignature *sig;
5125         MonoMethodBuilder *mb;
5126         
5127         guint32 b1, b2, b3, b4;
5128         guint32 copy_pos;
5129         int aklass, vklass;
5130         
5131         if (ret)
5132                 return ret;
5133         
5134         mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
5135         
5136
5137         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5138
5139         /* void stelemref (void* array, int idx, void* value) */
5140         sig->ret = &mono_defaults.void_class->byval_arg;
5141         sig->params [0] = &mono_defaults.int_class->byval_arg;
5142         sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
5143         sig->params [2] = &mono_defaults.int_class->byval_arg;
5144                 
5145         aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5146         vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5147         
5148         /*
5149         the method:
5150         <check ABC>
5151         if (!value)
5152                 goto store;
5153         
5154         aklass = array->vtable->klass->element_class;
5155         vklass = value->vtable->klass;
5156         
5157         if (vklass->idepth < aklass->idepth)
5158                 goto long;
5159         
5160         if (vklass->supertypes [aklass->idepth - 1] != aklass)
5161                 goto long;
5162         
5163         store:
5164                 array [idx] = value;
5165                 return;
5166         
5167         long:
5168                 if (mono_object_isinst (value, aklass))
5169                         goto store;
5170                 
5171                 throw new ArrayTypeMismatchException ();
5172         */
5173         
5174         /* ABC */
5175         mono_mb_emit_ldarg (mb, 0);
5176         mono_mb_emit_ldarg (mb, 1);
5177         mono_mb_emit_byte (mb, CEE_LDELEMA);
5178         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.int_class));
5179         mono_mb_emit_byte (mb, CEE_POP);
5180                 
5181         /* if (!value) goto do_store */
5182         mono_mb_emit_ldarg (mb, 2);
5183         b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5184         
5185         /* aklass = array->vtable->klass->element_class */
5186         mono_mb_emit_ldarg (mb, 0);
5187         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
5188         mono_mb_emit_byte (mb, CEE_LDIND_I);
5189         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
5190         mono_mb_emit_byte (mb, CEE_LDIND_I);
5191         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
5192         mono_mb_emit_byte (mb, CEE_LDIND_I);
5193         mono_mb_emit_stloc (mb, aklass);
5194         
5195         /* vklass = value->vtable->klass */
5196         mono_mb_emit_ldarg (mb, 2);
5197         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
5198         mono_mb_emit_byte (mb, CEE_LDIND_I);
5199         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
5200         mono_mb_emit_byte (mb, CEE_LDIND_I);
5201         mono_mb_emit_stloc (mb, vklass);
5202         
5203         /* if (vklass->idepth < aklass->idepth) goto failue */
5204         mono_mb_emit_ldloc (mb, vklass);
5205         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5206         mono_mb_emit_byte (mb, CEE_LDIND_I4);
5207         
5208         mono_mb_emit_ldloc (mb, aklass);
5209         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5210         mono_mb_emit_byte (mb, CEE_LDIND_I4);
5211         
5212         b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
5213         
5214         /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
5215         mono_mb_emit_ldloc (mb, vklass);
5216         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
5217         mono_mb_emit_byte (mb, CEE_LDIND_I);
5218         
5219         mono_mb_emit_ldloc (mb, aklass);
5220         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
5221         mono_mb_emit_byte (mb, CEE_LDIND_I4);
5222         mono_mb_emit_icon (mb, 1);
5223         mono_mb_emit_byte (mb, CEE_SUB);
5224         mono_mb_emit_icon (mb, sizeof (void*));
5225         mono_mb_emit_byte (mb, CEE_MUL);
5226         mono_mb_emit_byte (mb, CEE_ADD);
5227         mono_mb_emit_byte (mb, CEE_LDIND_I);
5228         
5229         mono_mb_emit_ldloc (mb, aklass);
5230         
5231         b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
5232         
5233         copy_pos = mb->pos;
5234         /* do_store */
5235         mono_mb_patch_addr (mb, b1, mb->pos - (b1 + 4));
5236         mono_mb_emit_ldarg (mb, 0);
5237         mono_mb_emit_ldarg (mb, 1);
5238         mono_mb_emit_ldarg (mb, 2);
5239         mono_mb_emit_byte (mb, CEE_STELEM_I);
5240         
5241         mono_mb_emit_byte (mb, CEE_RET);
5242         
5243         /* the hard way */
5244         mono_mb_patch_addr (mb, b2, mb->pos - (b2 + 4));
5245         mono_mb_patch_addr (mb, b3, mb->pos - (b3 + 4));
5246         
5247         mono_mb_emit_ldarg (mb, 2);
5248         mono_mb_emit_ldloc (mb, aklass);
5249         mono_mb_emit_icall (mb, mono_object_isinst);
5250         
5251         b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
5252         mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
5253         mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
5254         
5255         mono_mb_emit_byte (mb, CEE_RET);
5256         ret = mono_mb_create_method (mb, sig, 4);
5257         return ret;
5258 }
5259
5260 /* FIXME: on win32 we should probably use GlobalAlloc(). */
5261 void*
5262 mono_marshal_alloc (gpointer size) 
5263 {
5264         gpointer res;
5265
5266         MONO_ARCH_SAVE_REGS;
5267
5268         if ((gulong)size == 0)
5269                 /* This returns a valid pointer for size 0 on MS.NET */
5270                 size = (gpointer)4;
5271
5272         res = g_try_malloc ((gulong)size);
5273         if (!res)
5274                 mono_gc_out_of_memory ((gulong)size);
5275
5276         return res;
5277 }
5278
5279 void
5280 mono_marshal_free (gpointer ptr) 
5281 {
5282         MONO_ARCH_SAVE_REGS;
5283
5284         g_free (ptr);
5285 }
5286
5287 void
5288 mono_marshal_free_array (gpointer *ptr, int size) 
5289 {
5290         int i;
5291
5292         if (!ptr)
5293                 return;
5294
5295         for (i = 0; i < size; i++)
5296                 if (ptr [i])
5297                         g_free (ptr [i]);
5298 }
5299
5300 void *
5301 mono_marshal_realloc (gpointer ptr, gpointer size) 
5302 {
5303         MONO_ARCH_SAVE_REGS;
5304
5305         return g_try_realloc (ptr, (gulong)size);
5306 }
5307
5308 void *
5309 mono_marshal_string_array (MonoArray *array)
5310 {
5311         char **result;
5312         int i, len;
5313
5314         if (!array)
5315                 return NULL;
5316
5317         len = mono_array_length (array);
5318
5319         result = g_malloc (sizeof (char *) * (len + 1));
5320         for (i = 0; i < len; ++i) {
5321                 MonoString *s = (MonoString *)mono_array_get (array, gpointer, i);
5322                 result [i] = s ? mono_string_to_utf8 (s): NULL;
5323         }
5324         /* null terminate the array */
5325         result [i] = NULL;
5326
5327         return result;
5328 }
5329
5330 void *
5331 mono_marshal_string_array_to_unicode (MonoArray *array)
5332 {
5333         gunichar2 **result;
5334         int i, len;
5335
5336         if (!array)
5337                 return NULL;
5338
5339         len = mono_array_length (array);
5340
5341         result = g_malloc (sizeof (gunichar2 *) * (len + 1));
5342         for (i = 0; i < len; ++i) {
5343                 MonoString *s = (MonoString *)mono_array_get (array, gpointer, i);
5344                 result [i] = s ? mono_string_chars (s) : NULL;
5345         }
5346         /* null terminate the array */
5347         result [i] = NULL;
5348
5349         return result;
5350 }
5351
5352 /**
5353  * mono_marshal_set_last_error:
5354  *
5355  * This function is invoked to set the last error value from a P/Invoke call
5356  * which has SetLastError set.
5357  */
5358 void
5359 mono_marshal_set_last_error (void)
5360 {
5361 #ifdef WIN32
5362         TlsSetValue (last_error_tls_id, (gpointer)GetLastError ());
5363 #else
5364         TlsSetValue (last_error_tls_id, (gpointer)errno);
5365 #endif
5366 }
5367
5368 void
5369 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
5370                                                                     gpointer dest, gint32 length)
5371 {
5372         int element_size;
5373         void *source_addr;
5374
5375         MONO_ARCH_SAVE_REGS;
5376
5377         MONO_CHECK_ARG_NULL (src);
5378         MONO_CHECK_ARG_NULL (dest);
5379
5380         g_assert (src->obj.vtable->klass->rank == 1);
5381         g_assert (start_index >= 0);
5382         g_assert (length >= 0);
5383         g_assert (start_index + length <= mono_array_length (src));
5384
5385         element_size = mono_array_element_size (src->obj.vtable->klass);
5386           
5387         source_addr = mono_array_addr_with_size (src, element_size, start_index);
5388
5389         memcpy (dest, source_addr, length * element_size);
5390 }
5391
5392 void
5393 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
5394                                                                       MonoArray *dest, gint32 length)
5395 {
5396         int element_size;
5397         void *dest_addr;
5398
5399         MONO_ARCH_SAVE_REGS;
5400
5401         MONO_CHECK_ARG_NULL (src);
5402         MONO_CHECK_ARG_NULL (dest);
5403
5404         g_assert (dest->obj.vtable->klass->rank == 1);
5405         g_assert (start_index >= 0);
5406         g_assert (length >= 0);
5407         g_assert (start_index + length <= mono_array_length (dest));
5408
5409         element_size = mono_array_element_size (dest->obj.vtable->klass);
5410           
5411         dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
5412
5413         memcpy (dest_addr, src, length * element_size);
5414 }
5415
5416 #if NO_UNALIGNED_ACCESS
5417 #define RETURN_UNALIGNED(type, addr) \
5418         { \
5419                 type val; \
5420                 memcpy(&val, p + offset, sizeof(val)); \
5421                 return val; \
5422         }
5423 #define WRITE_UNALIGNED(type, addr, val) \
5424         memcpy(addr, &val, sizeof(type))
5425 #else
5426 #define RETURN_UNALIGNED(type, addr) \
5427         return *(type*)(p + offset);
5428 #define WRITE_UNALIGNED(type, addr, val) \
5429         (*(type *)(addr) = (val))
5430 #endif
5431
5432 gpointer
5433 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
5434 {
5435         char *p = ptr;
5436
5437         MONO_ARCH_SAVE_REGS;
5438
5439         RETURN_UNALIGNED(gpointer, p + offset);
5440 }
5441
5442 unsigned char
5443 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
5444 {
5445         char *p = ptr;
5446
5447         MONO_ARCH_SAVE_REGS;
5448
5449         return *(unsigned char*)(p + offset);
5450 }
5451
5452 gint16
5453 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
5454 {
5455         char *p = ptr;
5456
5457         MONO_ARCH_SAVE_REGS;
5458
5459         RETURN_UNALIGNED(gint16, p + offset);
5460 }
5461
5462 gint32
5463 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
5464 {
5465         char *p = ptr;
5466
5467         MONO_ARCH_SAVE_REGS;
5468
5469         RETURN_UNALIGNED(gint32, p + offset);
5470 }
5471
5472 gint64
5473 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
5474 {
5475         char *p = ptr;
5476
5477         MONO_ARCH_SAVE_REGS;
5478
5479         RETURN_UNALIGNED(gint64, p + offset);
5480 }
5481
5482 void
5483 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
5484 {
5485         char *p = ptr;
5486
5487         MONO_ARCH_SAVE_REGS;
5488
5489         *(unsigned char*)(p + offset) = val;
5490 }
5491
5492 void
5493 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
5494 {
5495         char *p = ptr;
5496
5497         MONO_ARCH_SAVE_REGS;
5498
5499         WRITE_UNALIGNED(gpointer, p + offset, val);
5500 }
5501
5502 void
5503 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
5504 {
5505         char *p = ptr;
5506
5507         MONO_ARCH_SAVE_REGS;
5508
5509         WRITE_UNALIGNED(gint16, p + offset, val);
5510 }
5511
5512 void
5513 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
5514 {
5515         char *p = ptr;
5516
5517         MONO_ARCH_SAVE_REGS;
5518
5519         WRITE_UNALIGNED(gint32, p + offset, val);
5520 }
5521
5522 void
5523 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
5524 {
5525         char *p = ptr;
5526
5527         MONO_ARCH_SAVE_REGS;
5528
5529         WRITE_UNALIGNED(gint64, p + offset, val);
5530 }
5531
5532 MonoString *
5533 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
5534 {
5535         MONO_ARCH_SAVE_REGS;
5536
5537         if (ptr == NULL)
5538                 return mono_string_new (mono_domain_get (), "");
5539         else
5540                 return mono_string_new (mono_domain_get (), ptr);
5541 }
5542
5543 MonoString *
5544 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
5545 {
5546         MONO_ARCH_SAVE_REGS;
5547
5548         if (ptr == NULL)
5549                 return mono_string_new (mono_domain_get (), "");
5550         else
5551                 return mono_string_new_len (mono_domain_get (), ptr, len);
5552 }
5553
5554 MonoString *
5555 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
5556 {
5557         MonoDomain *domain = mono_domain_get (); 
5558         int len = 0;
5559         guint16 *t = ptr;
5560
5561         MONO_ARCH_SAVE_REGS;
5562
5563         if (ptr == NULL)
5564                 return mono_string_new (mono_domain_get (), "");
5565
5566         while (*t++)
5567                 len++;
5568
5569         return mono_string_new_utf16 (domain, ptr, len);
5570 }
5571
5572 MonoString *
5573 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
5574 {
5575         MonoDomain *domain = mono_domain_get (); 
5576
5577         MONO_ARCH_SAVE_REGS;
5578
5579         if (ptr == NULL)
5580                 return mono_string_new (mono_domain_get (), "");
5581         else
5582                 return mono_string_new_utf16 (domain, ptr, len);
5583 }
5584
5585 MonoString *
5586 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
5587 {
5588         MONO_ARCH_SAVE_REGS;
5589
5590         g_warning ("PtrToStringBSTR not implemented");
5591         g_assert_not_reached ();
5592
5593         return NULL;
5594 }
5595
5596 guint32 
5597 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
5598 {
5599         MONO_ARCH_SAVE_REGS;
5600
5601         return ((guint32)TlsGetValue (last_error_tls_id));
5602 }
5603
5604 guint32 
5605 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
5606 {
5607         MonoClass *klass;
5608         MonoType *type;
5609         guint32 layout;
5610
5611         MONO_ARCH_SAVE_REGS;
5612
5613         MONO_CHECK_ARG_NULL (rtype);
5614
5615         type = rtype->type;
5616         klass = mono_class_from_mono_type (type);
5617         layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
5618
5619         if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5620                 gchar *msg;
5621                 MonoException *exc;
5622
5623                 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
5624                 exc = mono_get_exception_argument ("t", msg);
5625                 g_free (msg);
5626                 mono_raise_exception (exc);
5627         }
5628
5629
5630         return mono_class_native_size (klass, NULL);
5631 }
5632
5633 void
5634 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
5635 {
5636         MonoMethod *method;
5637         gpointer pa [3];
5638
5639         MONO_ARCH_SAVE_REGS;
5640
5641         MONO_CHECK_ARG_NULL (obj);
5642         MONO_CHECK_ARG_NULL (dst);
5643
5644         method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
5645
5646         pa [0] = obj;
5647         pa [1] = &dst;
5648         pa [2] = &delete_old;
5649
5650         mono_runtime_invoke (method, NULL, pa, NULL);
5651 }
5652
5653 void
5654 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
5655 {
5656         MonoMethod *method;
5657         gpointer pa [2];
5658
5659         MONO_ARCH_SAVE_REGS;
5660
5661         MONO_CHECK_ARG_NULL (src);
5662         MONO_CHECK_ARG_NULL (dst);
5663
5664         method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
5665
5666         pa [0] = &src;
5667         pa [1] = dst;
5668
5669         mono_runtime_invoke (method, NULL, pa, NULL);
5670 }
5671
5672 MonoObject *
5673 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
5674 {
5675         MonoDomain *domain = mono_domain_get (); 
5676         MonoObject *res;
5677
5678         MONO_ARCH_SAVE_REGS;
5679
5680         MONO_CHECK_ARG_NULL (src);
5681         MONO_CHECK_ARG_NULL (type);
5682
5683         res = mono_object_new (domain, mono_class_from_mono_type (type->type));
5684
5685         ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res);
5686
5687         return res;
5688 }
5689
5690 int
5691 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
5692 {
5693         MonoMarshalType *info;
5694         MonoClass *klass;
5695         char *fname;
5696         int i, match_index = -1;
5697         
5698         MONO_ARCH_SAVE_REGS;
5699
5700         MONO_CHECK_ARG_NULL (type);
5701         MONO_CHECK_ARG_NULL (field_name);
5702
5703         fname = mono_string_to_utf8 (field_name);
5704         klass = mono_class_from_mono_type (type->type);
5705
5706         while(klass && match_index == -1) {
5707                 for (i = 0; i < klass->field.count; ++i) {
5708                         if (*fname == *klass->fields [i].name && strcmp (fname, klass->fields [i].name) == 0) {
5709                                 match_index = i;
5710                                 break;
5711                         }
5712                 }
5713
5714                 if(match_index == -1)
5715                         klass = klass->parent;
5716         }
5717
5718         g_free (fname);
5719
5720         if(match_index == -1) {
5721                MonoException* exc;
5722                gchar *tmp;
5723
5724                /* Get back original class instance */
5725                klass = mono_class_from_mono_type (type->type);
5726
5727                tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
5728                exc = mono_get_exception_argument ("fieldName", tmp);
5729                g_free (tmp);
5730  
5731                mono_raise_exception ((MonoException*)exc);
5732        }
5733
5734        info = mono_marshal_load_type_info (klass);     
5735        return info->fields [match_index].offset;
5736 }
5737
5738 gpointer
5739 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
5740 {
5741         MONO_ARCH_SAVE_REGS;
5742
5743         return mono_string_to_utf8 (string);
5744 }
5745
5746 gpointer
5747 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
5748 {
5749         MONO_ARCH_SAVE_REGS;
5750
5751         if (string == NULL)
5752                 return NULL;
5753         else
5754                 return g_memdup (mono_string_chars (string), mono_string_length (string)*2);
5755 }
5756
5757 static void
5758 mono_struct_delete_old (MonoClass *klass, char *ptr)
5759 {
5760         MonoMarshalType *info;
5761         int i;
5762
5763         info = mono_marshal_load_type_info (klass);
5764
5765         for (i = 0; i < info->num_fields; i++) {
5766                 MonoMarshalNative ntype;
5767                 MonoMarshalConv conv;
5768                 MonoType *ftype = info->fields [i].field->type;
5769                 char *cpos;
5770
5771                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
5772                         continue;
5773
5774                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, 
5775                                                 klass->unicode, &conv);
5776                         
5777                 cpos = ptr + info->fields [i].offset;
5778
5779                 switch (conv) {
5780                 case MONO_MARSHAL_CONV_NONE:
5781                         if (MONO_TYPE_ISSTRUCT (ftype)) {
5782                                 mono_struct_delete_old (ftype->data.klass, cpos);
5783                                 continue;
5784                         }
5785                         break;
5786                 case MONO_MARSHAL_CONV_STR_LPWSTR:
5787                 case MONO_MARSHAL_CONV_STR_LPSTR:
5788                 case MONO_MARSHAL_CONV_STR_LPTSTR:
5789                 case MONO_MARSHAL_CONV_STR_BSTR:
5790                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
5791                 case MONO_MARSHAL_CONV_STR_TBSTR:
5792                         g_free (*(gpointer *)cpos);
5793                         break;
5794                 default:
5795                         continue;
5796                 }
5797         }
5798 }
5799
5800 void
5801 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
5802 {
5803         MonoClass *klass;
5804
5805         MONO_ARCH_SAVE_REGS;
5806
5807         MONO_CHECK_ARG_NULL (src);
5808         MONO_CHECK_ARG_NULL (type);
5809
5810         klass = mono_class_from_mono_type (type->type);
5811
5812         mono_struct_delete_old (klass, (char *)src);
5813 }
5814
5815 void*
5816 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
5817 {
5818         /* FIXME: Call AllocCoTaskMem under windows */
5819         MONO_ARCH_SAVE_REGS;
5820
5821         return g_try_malloc ((gulong)size);
5822 }
5823
5824 void
5825 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
5826 {
5827         /* FIXME: Call FreeCoTaskMem under windows */
5828         MONO_ARCH_SAVE_REGS;
5829
5830         g_free (ptr);
5831 }
5832
5833 void*
5834 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
5835 {
5836         return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
5837 }
5838
5839 MonoMarshalType *
5840 mono_marshal_load_type_info (MonoClass* klass)
5841 {
5842         int i, j, count = 0, native_size = 0, min_align = 1;
5843         MonoMarshalType *info;
5844         guint32 layout;
5845
5846         g_assert (klass != NULL);
5847
5848         if (klass->marshal_info)
5849                 return klass->marshal_info;
5850
5851         if (!klass->inited)
5852                 mono_class_init (klass);
5853         
5854         for (i = 0; i < klass->field.count; ++i) {
5855                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
5856                         continue;
5857                 if (mono_field_is_deleted (&klass->fields [i]))
5858                         continue;
5859                 count++;
5860         }
5861
5862         layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
5863
5864         klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
5865         info->num_fields = count;
5866         
5867         /* Try to find a size for this type in metadata */
5868         mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
5869
5870         if (klass->parent) {
5871                 int parent_size = mono_class_native_size (klass->parent, NULL);
5872
5873                 /* Add parent size to real size */
5874                 native_size += parent_size;
5875                 info->native_size = parent_size;
5876         }
5877  
5878         for (j = i = 0; i < klass->field.count; ++i) {
5879                 int size, align;
5880                 
5881                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
5882                         continue;
5883
5884                 if (mono_field_is_deleted (&klass->fields [i]))
5885                         continue;
5886                 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
5887                         mono_metadata_field_info (klass->image, klass->field.first + i, 
5888                                                   NULL, NULL, &info->fields [j].mspec);
5889
5890                 info->fields [j].field = &klass->fields [i];
5891
5892                 if ((klass->field.count == 1) && (klass->instance_size == sizeof (MonoObject)) &&
5893                         (strcmp (klass->fields [i].name, "$PRIVATE$") == 0)) {
5894                         /* This field is a hack inserted by MCS to empty structures */
5895                         continue;
5896                 }
5897
5898                 switch (layout) {
5899                 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
5900                 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
5901                         size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec, 
5902                                                        &align, TRUE, klass->unicode);
5903                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
5904                         min_align = MAX (align, min_align);
5905                         info->fields [j].offset = info->native_size;
5906                         info->fields [j].offset += align - 1;
5907                         info->fields [j].offset &= ~(align - 1);
5908                         info->native_size = info->fields [j].offset + size;
5909                         break;
5910                 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
5911                         size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec, 
5912                                                        &align, TRUE, klass->unicode);
5913                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
5914                         min_align = MAX (align, min_align);
5915                         info->fields [j].offset = klass->fields [i].offset - sizeof (MonoObject);
5916                         info->native_size = MAX (info->native_size, info->fields [j].offset + size);
5917                         break;
5918                 }       
5919                 j++;
5920         }
5921
5922         if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
5923                 info->native_size = MAX (native_size, info->native_size);
5924         }
5925
5926         if (info->native_size & (min_align - 1)) {
5927                 info->native_size += min_align - 1;
5928                 info->native_size &= ~(min_align - 1);
5929         }
5930
5931         /* Update the class's blittable info, if the layouts don't match */
5932         if (info->native_size != mono_class_value_size (klass, NULL))
5933                 klass->blittable = FALSE;
5934
5935         /* If this is an array type, ensure that we have element info */
5936         if (klass->element_class) {
5937                 mono_marshal_load_type_info (klass->element_class);
5938         }
5939
5940         return klass->marshal_info;
5941 }
5942
5943 /**
5944  * mono_class_native_size:
5945  * @klass: a class 
5946  * 
5947  * Returns: the native size of an object instance (when marshaled 
5948  * to unmanaged code) 
5949  */
5950 gint32
5951 mono_class_native_size (MonoClass *klass, guint32 *align)
5952 {
5953         
5954         if (!klass->marshal_info)
5955                 mono_marshal_load_type_info (klass);
5956
5957         if (align)
5958                 *align = klass->min_align;
5959
5960         return klass->marshal_info->native_size;
5961 }
5962
5963 /*
5964  * mono_type_native_stack_size:
5965  * @t: the type to return the size it uses on the stack
5966  *
5967  * Returns: the number of bytes required to hold an instance of this
5968  * type on the native stack
5969  */
5970 int
5971 mono_type_native_stack_size (MonoType *t, gint *align)
5972 {
5973         int tmp;
5974
5975         g_assert (t != NULL);
5976
5977         if (!align)
5978                 align = &tmp;
5979
5980         if (t->byref) {
5981                 *align = 4;
5982                 return 4;
5983         }
5984
5985         switch (t->type){
5986         case MONO_TYPE_BOOLEAN:
5987         case MONO_TYPE_CHAR:
5988         case MONO_TYPE_I1:
5989         case MONO_TYPE_U1:
5990         case MONO_TYPE_I2:
5991         case MONO_TYPE_U2:
5992         case MONO_TYPE_I4:
5993         case MONO_TYPE_U4:
5994         case MONO_TYPE_I:
5995         case MONO_TYPE_U:
5996         case MONO_TYPE_STRING:
5997         case MONO_TYPE_OBJECT:
5998         case MONO_TYPE_CLASS:
5999         case MONO_TYPE_SZARRAY:
6000         case MONO_TYPE_PTR:
6001         case MONO_TYPE_FNPTR:
6002         case MONO_TYPE_ARRAY:
6003         case MONO_TYPE_TYPEDBYREF:
6004                 *align = 4;
6005                 return 4;
6006         case MONO_TYPE_R4:
6007                 *align = 4;
6008                 return 4;
6009         case MONO_TYPE_I8:
6010         case MONO_TYPE_U8:
6011         case MONO_TYPE_R8:
6012                 *align = 4;
6013                 return 8;
6014         case MONO_TYPE_VALUETYPE: {
6015                 guint32 size;
6016
6017                 if (t->data.klass->enumtype)
6018                         return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
6019                 else {
6020                         size = mono_class_native_size (t->data.klass, align);
6021                         *align = *align + 3;
6022                         *align &= ~3;
6023                         
6024                         size +=  3;
6025                         size &= ~3;
6026
6027                         return size;
6028                 }
6029         }
6030         default:
6031                 g_error ("type 0x%02x unknown", t->type);
6032         }
6033         return 0;
6034 }
6035
6036 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
6037    the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
6038    but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
6039 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
6040
6041 gint32
6042 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align, 
6043                         gboolean as_field, gboolean unicode)
6044 {
6045         MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
6046         MonoClass *klass;
6047
6048         switch (native_type) {
6049         case MONO_NATIVE_BOOLEAN:
6050                 *align = 4;
6051                 return 4;
6052         case MONO_NATIVE_I1:
6053         case MONO_NATIVE_U1:
6054                 *align = 1;
6055                 return 1;
6056         case MONO_NATIVE_I2:
6057         case MONO_NATIVE_U2:
6058         case MONO_NATIVE_VARIANTBOOL:
6059                 *align = 2;
6060                 return 2;
6061         case MONO_NATIVE_I4:
6062         case MONO_NATIVE_U4:
6063         case MONO_NATIVE_ERROR:
6064                 *align = 4;
6065                 return 4;
6066         case MONO_NATIVE_I8:
6067         case MONO_NATIVE_U8:
6068                 *align = ALIGNMENT(guint64);
6069                 return 8;
6070         case MONO_NATIVE_R4:
6071                 *align = 4;
6072                 return 4;
6073         case MONO_NATIVE_R8:
6074                 *align = ALIGNMENT(double);
6075                 return 8;
6076         case MONO_NATIVE_INT:
6077         case MONO_NATIVE_UINT:
6078         case MONO_NATIVE_LPSTR:
6079         case MONO_NATIVE_LPWSTR:
6080         case MONO_NATIVE_LPTSTR:
6081         case MONO_NATIVE_BSTR:
6082         case MONO_NATIVE_ANSIBSTR:
6083         case MONO_NATIVE_TBSTR:
6084         case MONO_NATIVE_LPARRAY:
6085         case MONO_NATIVE_SAFEARRAY:
6086         case MONO_NATIVE_IUNKNOWN:
6087         case MONO_NATIVE_IDISPATCH:
6088         case MONO_NATIVE_INTERFACE:
6089         case MONO_NATIVE_ASANY:
6090         case MONO_NATIVE_FUNC:
6091         case MONO_NATIVE_LPSTRUCT:
6092                 *align = ALIGNMENT(gpointer);
6093                 return sizeof (gpointer);
6094         case MONO_NATIVE_STRUCT: 
6095                 klass = mono_class_from_mono_type (type);
6096                 return mono_class_native_size (klass, align);
6097         case MONO_NATIVE_BYVALTSTR: {
6098                 int esize = unicode ? 2: 1;
6099                 g_assert (mspec);
6100                 *align = esize;
6101                 return mspec->data.array_data.num_elem * esize;
6102         }
6103         case MONO_NATIVE_BYVALARRAY: {
6104                 int esize;
6105                 klass = mono_class_from_mono_type (type);
6106                 esize = mono_class_native_size (klass->element_class, align);
6107                 g_assert (mspec);
6108                 return mspec->data.array_data.num_elem * esize;
6109         }
6110         case MONO_NATIVE_CUSTOM:
6111                 g_assert_not_reached ();
6112                 break;
6113         case MONO_NATIVE_CURRENCY:
6114         case MONO_NATIVE_VBBYREFSTR:
6115         default:
6116                 g_error ("native type %02x not implemented", native_type); 
6117                 break;
6118         }
6119         g_assert_not_reached ();
6120         return 0;
6121 }
6122
6123 gpointer
6124 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding)
6125 {
6126         MonoType *t;
6127         MonoClass *klass;
6128
6129         if (o == NULL)
6130                 return NULL;
6131
6132         t = &o->vtable->klass->byval_arg;
6133         switch (t->type) {
6134         case MONO_TYPE_I4:
6135         case MONO_TYPE_U4:
6136         case MONO_TYPE_PTR:
6137         case MONO_TYPE_I1:
6138         case MONO_TYPE_U1:
6139         case MONO_TYPE_BOOLEAN:
6140         case MONO_TYPE_I2:
6141         case MONO_TYPE_U2:
6142         case MONO_TYPE_CHAR:
6143         case MONO_TYPE_I8:
6144         case MONO_TYPE_U8:
6145         case MONO_TYPE_R4:
6146         case MONO_TYPE_R8:
6147                 return mono_object_unbox (o);
6148                 break;
6149         case MONO_TYPE_STRING:
6150                 switch (string_encoding) {
6151                 case MONO_NATIVE_LPWSTR:
6152                         return mono_string_to_utf16 ((MonoString*)o);
6153                         break;
6154                 case MONO_NATIVE_LPSTR:
6155                         return mono_string_to_utf8 ((MonoString*)o);
6156                         break;
6157                 default:
6158                         g_warning ("marshaling conversion %d not implemented", string_encoding);
6159                         g_assert_not_reached ();
6160                 }
6161                 break;
6162         case MONO_TYPE_CLASS:
6163         case MONO_TYPE_VALUETYPE: {
6164                 MonoMethod *method;
6165                 gpointer pa [3];
6166                 gpointer res;
6167                 MonoBoolean delete_old = FALSE;
6168
6169                 klass = t->data.klass;
6170
6171                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
6172                         break;
6173
6174                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6175                         klass->blittable || klass->enumtype)
6176                         return mono_object_unbox (o);
6177
6178                 res = g_malloc0 (mono_class_native_size (klass, NULL));
6179
6180                 method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
6181
6182                 pa [0] = o;
6183                 pa [1] = &res;
6184                 pa [2] = &delete_old;
6185
6186                 mono_runtime_invoke (method, NULL, pa, NULL);
6187
6188                 return res;
6189         }
6190         }
6191
6192         mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
6193
6194         return NULL;
6195 }
6196
6197 void
6198 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding)
6199 {
6200         MonoType *t;
6201         MonoClass *klass;
6202
6203         /* FIXME: Free embedded data as well */
6204
6205         if (o == NULL)
6206                 return;
6207
6208         t = &o->vtable->klass->byval_arg;
6209         switch (t->type) {
6210         case MONO_TYPE_STRING:
6211                 switch (string_encoding) {
6212                 case MONO_NATIVE_LPWSTR:
6213                         g_free (ptr);
6214                         break;
6215                 case MONO_NATIVE_LPSTR:
6216                         g_free (ptr);
6217                         break;
6218                 default:
6219                         g_warning ("marshaling conversion %d not implemented", string_encoding);
6220                         g_assert_not_reached ();
6221                 }
6222                 break;
6223         case MONO_TYPE_CLASS:
6224         case MONO_TYPE_VALUETYPE: {
6225                 klass = t->data.klass;
6226
6227                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6228                         klass->blittable || klass->enumtype)
6229                         break;
6230
6231                 g_free (ptr);
6232                 break;
6233         }
6234         default:
6235                 break;
6236         }
6237 }