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