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