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