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