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