2002-08-16 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / metadata / marshal.c
1 /*
2  * marshal.c: Routines for marshaling complex types in P/Invoke methods.
3  * 
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.  http://www.ximian.com
8  *
9  */
10
11 #include "config.h"
12 #include "object.h"
13 #include "loader.h"
14 #include "metadata/marshal.h"
15 #include "metadata/tabledefs.h"
16 #include "metadata/exception.h"
17 #include "metadata/appdomain.h"
18 #include "mono/metadata/debug-helpers.h"
19 #include "mono/metadata/threadpool.h"
20 #include <string.h>
21
22 //#define DEBUG_RUNTIME_CODE
23
24 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
25         a = i,
26
27 enum {
28 #include "mono/cil/opcode.def"
29         LAST = 0xff
30 };
31 #undef OPDEF
32
33 struct _MonoMethodBuilder {
34         MonoMethod *method;
35         GList *locals_list;
36         int locals;
37         guint32 code_size, pos;
38         unsigned char *code;
39 };
40
41 static void
42 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
43
44 #ifdef DEBUG_RUNTIME_CODE
45 static char*
46 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
47 {
48         return g_strdup (" ");
49 }
50
51 static MonoDisHelper marshal_dh = {
52         "\n",
53         NULL,
54         "IL_%04x",
55         indenter, 
56         NULL,
57         NULL
58 };
59 #endif 
60
61 gpointer
62 mono_delegate_to_ftnptr (MonoDelegate *delegate)
63 {
64         MonoMethod *method, *wrapper;
65         MonoClass *klass;
66
67         if (!delegate)
68                 return NULL;
69
70         if (delegate->delegate_trampoline)
71                 return delegate->delegate_trampoline;
72
73         klass = ((MonoObject *)delegate)->vtable->klass;
74         g_assert (klass->delegate);
75         
76         method = delegate->method_info->method;
77         wrapper = mono_marshal_get_managed_wrapper (method, delegate->target);
78
79         delegate->delegate_trampoline =  mono_compile_method (wrapper);
80
81         return delegate->delegate_trampoline;
82 }
83
84 gpointer
85 mono_array_to_savearray (MonoArray *array)
86 {
87         if (!array)
88                 return NULL;
89
90         g_assert_not_reached ();
91         return NULL;
92 }
93
94 gpointer
95 mono_array_to_lparray (MonoArray *array)
96 {
97         if (!array)
98                 return NULL;
99
100         /* fixme: maybe we need to make a copy */
101         return array->vector;
102 }
103
104 void
105 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
106 {
107         GError *error = NULL;
108         guint16 *ut;
109         glong items_written;
110         int l;
111
112         if (!sb || !text)
113                 return;
114
115         l = strlen (text);
116
117         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
118
119         if (items_written > sb->capacity)
120                 items_written = sb->capacity;
121         
122         if (!error) {
123                 memcpy (sb->chars->vector, ut, items_written * 2);
124                 sb->length = items_written;
125         } else 
126                 g_error_free (error);
127
128         g_free (ut);
129 }
130
131 gpointer
132 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
133 {
134         char *res;
135
136         if (!sb)
137                 return NULL;
138
139         res = g_malloc (sb->capacity + 1);
140
141         /* fixme: copy the content of the string builder? */
142         res [0] = 0;
143
144         return res;
145 }
146
147 gpointer
148 mono_string_to_ansibstr (MonoString *string_obj)
149 {
150         g_error ("implement me");
151         return NULL;
152 }
153
154 gpointer
155 mono_string_to_bstr (MonoString *string_obj)
156 {
157         g_error ("implement me");
158         return NULL;
159 }
160
161 void
162 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
163 {
164         char *s;
165         int len;
166
167         g_assert (dst != NULL);
168         g_assert (size > 0);
169
170         if (!src) {
171                 memset (dst, 0, size);
172                 return;
173         }
174
175         s = mono_string_to_utf8 (src);
176         len = MIN (size, strlen (s));
177         memcpy (dst, s, len);
178         g_free (s);
179
180         *((char *)dst + size - 1) = 0;
181 }
182
183 void
184 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
185 {
186         int len;
187
188         g_assert (dst != NULL);
189         g_assert (size > 1);
190
191         if (!src) {
192                 memset (dst, 0, size);
193                 return;
194         }
195
196         len = MIN (size, (mono_string_length (src) * 2));
197         memcpy (dst, mono_string_chars (src), len);
198
199         *((char *)dst + size - 1) = 0;
200         *((char *)dst + size - 2) = 0;
201 }
202
203
204 static MonoMethod *
205 mono_find_method_by_name (MonoClass *klass, const char *name, int param_count)
206 {
207         MonoMethod *res = NULL;
208         int i;
209
210         for (i = 0; i < klass->method.count; ++i) {
211                 if ((klass->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
212                     klass->methods [i]->name[0] == name [0] && 
213                     !strcmp (name, klass->methods [i]->name) &&
214                     klass->methods [i]->signature->param_count == param_count) {
215                         res = klass->methods [i];
216                         break;
217                 }
218         }
219         return res;
220 }
221
222 void
223 mono_mb_free (MonoMethodBuilder *mb)
224 {
225         g_list_free (mb->locals_list);
226         g_free (mb);
227 }
228
229 MonoMethodBuilder *
230 mono_mb_new (MonoClass *klass, const char *name)
231 {
232         MonoMethodBuilder *mb;
233         MonoMethod *m;
234
235         g_assert (klass != NULL);
236         g_assert (name != NULL);
237
238         mb = g_new0 (MonoMethodBuilder, 1);
239
240         mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
241
242         m->klass = klass;
243         m->name = g_strdup (name);
244         m->inline_info = 1;
245         m->inline_count = -1;
246         m->wrapper_type = MONO_WRAPPER_UNKNOWN;
247
248         mb->code_size = 256;
249         mb->code = g_malloc (mb->code_size);
250         
251         return mb;
252 }
253
254 int
255 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
256 {
257         int res = mb->locals;
258
259         g_assert (mb != NULL);
260         g_assert (type != NULL);
261
262         mb->locals_list = g_list_append (mb->locals_list, type);
263         mb->locals++;
264
265         return res;
266 }
267
268 MonoMethod *
269 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
270 {
271         MonoMethodHeader *header;
272         GList *l;
273         int i;
274
275         g_assert (mb != NULL);
276
277         ((MonoMethodNormal *)mb->method)->header = header = (MonoMethodHeader *) 
278                 g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
279
280         if (max_stack < 8)
281                 max_stack = 8;
282
283         header->max_stack = max_stack;
284
285         for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
286                 header->locals [i] = (MonoType *)l->data;
287         }
288
289         mb->method->signature = signature;
290         header->code = mb->code;
291         header->code_size = mb->pos;
292         header->num_locals = mb->locals;
293
294 #ifdef DEBUG_RUNTIME_CODE
295         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (mb->method, TRUE));
296         printf ("%s\n", mono_disasm_code (&marshal_dh, mb->method, mb->code, mb->code + mb->pos));
297 #endif
298
299         return mb->method;
300 }
301
302 guint32
303 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
304 {
305         MonoMethodWrapper *mw;
306
307         g_assert (mb != NULL);
308
309         mw = (MonoMethodWrapper *)mb->method;
310
311         mw->data = g_list_append (mw->data, data);
312
313         return GUINT32_TO_LE (g_list_length (mw->data));
314 }
315
316 void
317 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
318 {
319         *((gint32 *)(&mb->code [pos])) = value;
320 }
321
322 void
323 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
324 {
325         *((gint8 *)(&mb->code [pos])) = value;
326 }
327
328 void
329 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
330 {
331         if (mb->pos >= mb->code_size) {
332                 mb->code_size += 64;
333                 mb->code = g_realloc (mb->code, mb->code_size);
334         }
335
336         mb->code [mb->pos++] = op;
337 }
338
339 void
340 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
341 {
342         if ((mb->pos + 4) >= mb->code_size) {
343                 mb->code_size += 64;
344                 mb->code = g_realloc (mb->code, mb->code_size);
345         }
346
347         *((gint32 *)(&mb->code [mb->pos])) = data;
348         mb->pos += 4;
349 }
350
351 void
352 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
353 {
354         if ((mb->pos + 2) >= mb->code_size) {
355                 mb->code_size += 64;
356                 mb->code = g_realloc (mb->code, mb->code_size);
357         }
358
359         *((gint16 *)(&mb->code [mb->pos])) = data;
360         mb->pos += 2;
361 }
362
363 void
364 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
365 {
366         if (argnum < 4) {
367                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
368         } else if (argnum < 256) {
369                 mono_mb_emit_byte (mb, CEE_LDARG_S);
370                 mono_mb_emit_byte (mb, argnum);
371         } else {
372                 mono_mb_emit_byte (mb, CEE_PREFIX1);
373                 mono_mb_emit_byte (mb, CEE_LDARG);
374                 mono_mb_emit_i4 (mb, argnum);
375         }
376 }
377
378 void
379 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
380 {
381         if (argnum < 256) {
382                 mono_mb_emit_byte (mb, CEE_LDARGA_S);
383                 mono_mb_emit_byte (mb, argnum);
384         } else {
385                 mono_mb_emit_byte (mb, CEE_PREFIX1);
386                 mono_mb_emit_byte (mb, CEE_LDARGA);
387                 mono_mb_emit_i4 (mb, argnum);
388         }
389 }
390
391 void
392 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
393 {
394         if (locnum < 256) {
395                 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
396                 mono_mb_emit_byte (mb, locnum);
397         } else {
398                 mono_mb_emit_byte (mb, CEE_PREFIX1);
399                 mono_mb_emit_byte (mb, CEE_LDLOCA);
400                 mono_mb_emit_i4 (mb, locnum);
401         }
402 }
403
404 void
405 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
406 {
407         if (num < 4) {
408                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
409         } else if (num < 256) {
410                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
411                 mono_mb_emit_byte (mb, num);
412         } else {
413                 mono_mb_emit_byte (mb, CEE_PREFIX1);
414                 mono_mb_emit_byte (mb, CEE_LDLOC);
415                 mono_mb_emit_i4 (mb, num);
416         }
417 }
418
419 void
420 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
421 {
422         if (num < 4) {
423                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
424         } else if (num < 256) {
425                 mono_mb_emit_byte (mb, CEE_STLOC_S);
426                 mono_mb_emit_byte (mb, num);
427         } else {
428                 mono_mb_emit_byte (mb, CEE_PREFIX1);
429                 mono_mb_emit_byte (mb, CEE_STLOC);
430                 mono_mb_emit_i4 (mb, num);
431         }
432 }
433
434 void
435 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
436 {
437         if (value >= -1 && value < 8) {
438                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
439         } else if (value >= -128 && value <= 127) {
440                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
441                 mono_mb_emit_byte (mb, value);
442         } else {
443                 mono_mb_emit_byte (mb, CEE_LDC_I4);
444                 mono_mb_emit_i4 (mb, value);
445         }
446 }
447
448 void
449 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
450 {
451         if (!opt_sig)
452                 opt_sig = method->signature;
453         mono_mb_emit_byte (mb, CEE_PREFIX1);
454         mono_mb_emit_byte (mb, CEE_LDFTN);
455         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
456         mono_mb_emit_byte (mb, CEE_CALLI);
457         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, opt_sig));
458 }
459
460 void
461 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
462 {
463         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
464         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
465         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
466         mono_mb_emit_byte (mb, CEE_CALLI);
467         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
468 }
469
470 void
471 mono_mb_emit_exception (MonoMethodBuilder *mb)
472 {
473         /* fixme: we need a better way to throw exception,
474          * supporting several exception types and messages */
475         mono_mb_emit_byte (mb, CEE_LDNULL);
476         mono_mb_emit_byte (mb, CEE_THROW);
477         
478 }
479
480 void
481 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
482 {
483         mono_mb_emit_ldloc (mb, local); 
484         mono_mb_emit_icon (mb, incr);
485         mono_mb_emit_byte (mb, CEE_ADD);
486         mono_mb_emit_stloc (mb, local); 
487 }
488
489 static void
490 emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, 
491                       int usize, int msize)
492 {
493         switch (conv) {
494         case MONO_MARSHAL_CONV_BOOL_I4:
495                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
496                 mono_mb_emit_byte (mb, CEE_LDIND_I);
497                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
498                 mono_mb_emit_byte (mb, 5);
499                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
500                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
501                 mono_mb_emit_byte (mb, CEE_STIND_I1);
502                 mono_mb_emit_byte (mb, CEE_BR_S);
503                 mono_mb_emit_byte (mb, 3);
504                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
505                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
506                 mono_mb_emit_byte (mb, CEE_STIND_I1);
507                 break;
508         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
509                 MonoClass *eclass;
510                 int esize;
511
512                 if (type->type == MONO_TYPE_ARRAY)
513                         eclass = mono_class_from_mono_type (type->data.array->type);
514                 else if (type->type == MONO_TYPE_SZARRAY) {
515                         eclass = mono_class_from_mono_type (type->data.type);
516                 } else {
517                         g_assert_not_reached ();
518                 }
519
520                 if (eclass->valuetype)
521                         esize = mono_class_instance_size (eclass) - sizeof (MonoObject);
522                 else
523                         esize = sizeof (gpointer);
524
525                 /* create a new array */
526                 /* fixme: this only works for SZARRAYS */
527                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
528                 mono_mb_emit_icon (mb, msize / esize);
529                 mono_mb_emit_byte (mb, CEE_NEWARR);     
530                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass));
531                 mono_mb_emit_byte (mb, CEE_STIND_I);
532
533                 /* copy the elements */
534                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
535                 mono_mb_emit_byte (mb, CEE_LDIND_I);
536                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
537                 mono_mb_emit_byte (mb, CEE_ADD);
538                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
539                 mono_mb_emit_icon (mb, usize);
540                 mono_mb_emit_byte (mb, CEE_PREFIX1);
541                 mono_mb_emit_byte (mb, CEE_CPBLK);                      
542
543                 break;
544         }
545         case MONO_MARSHAL_CONV_STR_BYVALSTR: 
546                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
547                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
548                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
549                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
550                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
551                 mono_mb_emit_byte (mb, CEE_STIND_I);            
552                 break;
553         case MONO_MARSHAL_CONV_STR_LPTSTR:
554         case MONO_MARSHAL_CONV_STR_LPSTR:
555                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
556                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
557                 mono_mb_emit_byte (mb, CEE_LDIND_I);
558                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
559                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
560                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
561                 mono_mb_emit_byte (mb, CEE_STIND_I);            
562                 break;
563         case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
564                 MonoClass *klass = mono_class_from_mono_type (type);
565                 int src_var, dst_var;
566
567                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
568                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
569                 
570                 /* *dst = new object */
571                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
572                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
573                 mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
574                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
575                 mono_mb_emit_byte (mb, CEE_STIND_I);
576         
577                 /* save the old src pointer */
578                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
579                 mono_mb_emit_stloc (mb, src_var);
580                 /* save the old dst pointer */
581                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
582                 mono_mb_emit_stloc (mb, dst_var);
583
584                 /* dst = pointer to newly created object data */
585                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
586                 mono_mb_emit_byte (mb, CEE_LDIND_I);
587                 mono_mb_emit_icon (mb, sizeof (MonoObject));
588                 mono_mb_emit_byte (mb, CEE_ADD);
589                 mono_mb_emit_byte (mb, CEE_STLOC_1); 
590
591                 emit_struct_conv (mb, klass, TRUE);
592                 
593                 /* restore the old src pointer */
594                 mono_mb_emit_ldloc (mb, src_var);
595                 mono_mb_emit_byte (mb, CEE_STLOC_0);
596                 /* restore the old dst pointer */
597                 mono_mb_emit_ldloc (mb, dst_var);
598                 mono_mb_emit_byte (mb, CEE_STLOC_1);
599                 break;
600         }
601         case MONO_MARSHAL_CONV_STR_LPWSTR:
602         case MONO_MARSHAL_CONV_STR_BSTR:
603         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
604         case MONO_MARSHAL_CONV_STR_TBSTR:
605         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
606         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
607         case MONO_MARSHAL_CONV_STR_BYVALWSTR: 
608         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
609         default:
610                 g_warning ("marshaling conversion %d not implemented", conv);
611                 g_assert_not_reached ();
612         }
613 }
614
615 static void
616 emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, int usize, int msize)
617 {
618         int pos;
619
620         switch (conv) {
621         case MONO_MARSHAL_CONV_BOOL_I4:
622                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
623                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
624                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
625                 mono_mb_emit_byte (mb, CEE_STIND_I4);
626                 break;
627         case MONO_MARSHAL_CONV_STR_LPWSTR:
628         case MONO_MARSHAL_CONV_STR_LPSTR:
629         case MONO_MARSHAL_CONV_STR_LPTSTR:
630         case MONO_MARSHAL_CONV_STR_BSTR:
631         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
632         case MONO_MARSHAL_CONV_STR_TBSTR:
633                 /* free space if free == true */
634                 mono_mb_emit_byte (mb, CEE_LDLOC_2);
635                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
636                 mono_mb_emit_byte (mb, 4);
637                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
638                 mono_mb_emit_byte (mb, CEE_LDIND_I);
639                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
640                 mono_mb_emit_byte (mb, CEE_MONO_FREE);
641
642                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
643                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
644                 mono_mb_emit_byte (mb, CEE_LDIND_I);
645                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
646                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
647                 mono_mb_emit_byte (mb, conv);
648                 mono_mb_emit_byte (mb, CEE_STIND_I);    
649                 break;
650         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
651         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
652                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
653                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
654                 mono_mb_emit_byte (mb, CEE_LDIND_I);
655                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
656                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
657                 mono_mb_emit_byte (mb, conv);
658                 mono_mb_emit_byte (mb, CEE_STIND_I);    
659                 break;
660         case MONO_MARSHAL_CONV_STR_BYVALSTR: 
661         case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
662                 if (!usize)
663                         break;
664
665                 mono_mb_emit_byte (mb, CEE_LDLOC_1); /* dst */
666                 mono_mb_emit_byte (mb, CEE_LDLOC_0);    
667                 mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */
668                 mono_mb_emit_icon (mb, usize);
669                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
670                 mono_mb_emit_byte (mb, CEE_MONO_PROC3);
671                 mono_mb_emit_byte (mb, conv);
672                 break;
673         }
674         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
675                 if (!usize) 
676                         break;
677
678                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
679                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
680                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
681                 pos = mb->pos;
682                 mono_mb_emit_byte (mb, 0);
683
684                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
685                 mono_mb_emit_byte (mb, CEE_LDLOC_0);    
686                 mono_mb_emit_byte (mb, CEE_LDIND_I);    
687                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
688                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
689                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
690                 mono_mb_emit_byte (mb, CEE_ADD);
691                 mono_mb_emit_icon (mb, usize);
692                 mono_mb_emit_byte (mb, CEE_PREFIX1);
693                 mono_mb_emit_byte (mb, CEE_CPBLK);                      
694                 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
695                 break;
696         }
697         case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
698                 int src_var, dst_var;
699
700                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
701                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
702                 
703                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
704                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
705                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
706                 pos = mb->pos;
707                 mono_mb_emit_byte (mb, 0);
708                 
709                 /* save the old src pointer */
710                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
711                 mono_mb_emit_stloc (mb, src_var);
712                 /* save the old dst pointer */
713                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
714                 mono_mb_emit_stloc (mb, dst_var);
715
716                 /* src = pointer to object data */
717                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
718                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
719                 mono_mb_emit_icon (mb, sizeof (MonoObject));
720                 mono_mb_emit_byte (mb, CEE_ADD);
721                 mono_mb_emit_byte (mb, CEE_STLOC_0); 
722
723                 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
724                 
725                 /* restore the old src pointer */
726                 mono_mb_emit_ldloc (mb, src_var);
727                 mono_mb_emit_byte (mb, CEE_STLOC_0);
728                 /* restore the old dst pointer */
729                 mono_mb_emit_ldloc (mb, dst_var);
730                 mono_mb_emit_byte (mb, CEE_STLOC_1);
731
732                 mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
733                 break;
734         }
735         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
736         default:
737                 g_warning ("marshalling conversion %d not implemented", conv);
738                 g_assert_not_reached ();
739         }
740 }
741
742 static void
743 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
744 {
745         MonoMarshalType *info;
746         int i;
747
748         info = mono_marshal_load_type_info (klass);
749
750         for (i = 0; i < info->num_fields; i++) {
751                 MonoMarshalNative ntype;
752                 MonoMarshalConv conv;
753                 MonoType *ftype = info->fields [i].field->type;
754                 int msize = 0;
755                 int usize = 0;
756                 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
757
758                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
759                         continue;
760
761                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
762                         
763                 if (last_field) {
764                         msize = klass->instance_size - info->fields [i].field->offset;
765                         usize = info->native_size - info->fields [i].offset;
766                 } else {
767                         msize = klass->fields [i + 1].offset - info->fields [i].field->offset;
768                         usize = info->fields [i + 1].offset - info->fields [i].offset;
769                 }
770                 g_assert (msize > 0 && usize > 0);
771
772                 switch (conv) {
773                 case MONO_MARSHAL_CONV_NONE: {
774                         int t;
775
776                         if (ftype->byref || ftype->type == MONO_TYPE_I ||
777                             ftype->type == MONO_TYPE_U) {
778                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
779                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
780                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
781                                 mono_mb_emit_byte (mb, CEE_STIND_I);
782                                 break;
783                         }
784
785                         t = ftype->type;
786                 handle_enum:
787                         switch (t) {
788                         case MONO_TYPE_I4:
789                         case MONO_TYPE_U4:
790                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
791                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
792                                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
793                                 mono_mb_emit_byte (mb, CEE_STIND_I4);
794                                 break;
795                         case MONO_TYPE_I1:
796                         case MONO_TYPE_U1:
797                         case MONO_TYPE_BOOLEAN:
798                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
799                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
800                                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
801                                 mono_mb_emit_byte (mb, CEE_STIND_I1);
802                                 break;
803                         case MONO_TYPE_I2:
804                         case MONO_TYPE_U2:
805                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
806                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
807                                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
808                                 mono_mb_emit_byte (mb, CEE_STIND_I2);
809                                 break;
810                         case MONO_TYPE_I8:
811                         case MONO_TYPE_U8:
812                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
813                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
814                                 mono_mb_emit_byte (mb, CEE_LDIND_I8);
815                                 mono_mb_emit_byte (mb, CEE_STIND_I8);
816                                 break;
817                         case MONO_TYPE_R4:
818                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
819                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
820                                 mono_mb_emit_byte (mb, CEE_LDIND_R4);
821                                 mono_mb_emit_byte (mb, CEE_STIND_R4);
822                                 break;
823                         case MONO_TYPE_R8:
824                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
825                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
826                                 mono_mb_emit_byte (mb, CEE_LDIND_R8);
827                                 mono_mb_emit_byte (mb, CEE_STIND_R8);
828                                 break;
829                         case MONO_TYPE_VALUETYPE:
830                                 if (ftype->data.klass->enumtype) {
831                                         t = ftype->data.klass->enum_basetype->type;
832                                         goto handle_enum;
833                                 }
834                                 emit_struct_conv (mb, ftype->data.klass, to_object);
835                                 continue;
836                         default:
837                                 g_warning ("marshaling type %02x not implemented", ftype->type);
838                                 g_assert_not_reached ();
839                         }
840                         break;
841                 }
842                 default:
843                         if (to_object) 
844                                 emit_ptr_to_str_conv (mb, ftype, conv, usize, msize);
845                         else
846                                 emit_str_to_ptr_conv (mb, ftype, conv, usize, msize);   
847                 }
848                 
849                 if (to_object) {
850                         mono_mb_emit_add_to_local (mb, 0, usize);
851                         mono_mb_emit_add_to_local (mb, 1, msize);
852                 } else {
853                         mono_mb_emit_add_to_local (mb, 0, msize);
854                         mono_mb_emit_add_to_local (mb, 1, usize);
855                 }                               
856         }
857 }
858
859 static MonoAsyncResult *
860 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
861 {
862         MonoMethodMessage *msg;
863         MonoDelegate *async_callback;
864         MonoObject *state;
865         MonoMethod *im;
866         MonoClass *klass;
867         MonoMethod *method = NULL;
868         int i;
869
870         g_assert (delegate);
871
872         klass = delegate->object.vtable->klass;
873
874         method = mono_get_delegate_invoke (klass);
875         for (i = 0; i < klass->method.count; ++i) {
876                 if (klass->methods [i]->name[0] == 'B' && 
877                     !strcmp ("BeginInvoke", klass->methods [i]->name)) {
878                         method = klass->methods [i];
879                         break;
880                 }
881         }
882
883         g_assert (method != NULL);
884
885         im = mono_get_delegate_invoke (method->klass);
886         
887         msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
888
889         return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
890 }
891
892 static int
893 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
894 {
895         int i, params_var, tmp_var;
896
897         /* allocate local (pointer) *params[] */
898         params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
899         /* allocate local (pointer) tmp */
900         tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
901
902         /* alloate space on stack to store an array of pointers to the arguments */
903         mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
904         mono_mb_emit_byte (mb, CEE_PREFIX1);
905         mono_mb_emit_byte (mb, CEE_LOCALLOC);
906         mono_mb_emit_stloc (mb, params_var);
907
908         /* tmp = params */
909         mono_mb_emit_ldloc (mb, params_var);
910         mono_mb_emit_stloc (mb, tmp_var);
911
912         if (save_this && sig->hasthis) {
913                 mono_mb_emit_ldloc (mb, tmp_var);
914                 mono_mb_emit_ldarg_addr (mb, 0);
915                 mono_mb_emit_byte (mb, CEE_STIND_I);
916                 /* tmp = tmp + sizeof (gpointer) */
917                 if (sig->param_count)
918                         mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
919
920         }
921
922         for (i = 0; i < sig->param_count; i++) {
923                 mono_mb_emit_ldloc (mb, tmp_var);
924                 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
925                 mono_mb_emit_byte (mb, CEE_STIND_I);
926                 /* tmp = tmp + sizeof (gpointer) */
927                 if (i < (sig->param_count - 1))
928                         mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
929         }
930
931         return params_var;
932 }
933
934 static char*
935 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
936 {
937         int i;
938         char *result;
939         GString *res = g_string_new ("");
940
941         if (prefix) {
942                 g_string_append (res, prefix);
943                 g_string_append_c (res, '_');
944         }
945
946         mono_type_get_desc (res, sig->ret, FALSE);
947
948         for (i = 0; i < sig->param_count; ++i) {
949                 g_string_append_c (res, '_');
950                 mono_type_get_desc (res, sig->params [i], FALSE);
951         }
952         result = res->str;
953         g_string_free (res, FALSE);
954         return result;
955 }
956
957 MonoMethod *
958 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
959 {
960         MonoMethodSignature *sig;
961         static MonoMethodSignature *csig = NULL;
962         MonoMethodBuilder *mb;
963         MonoMethod *res;
964         GHashTable *cache;
965         int params_var;
966         char *name;
967
968         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
969                   !strcmp (method->name, "BeginInvoke"));
970
971         sig = method->signature;
972
973         cache = method->klass->image->delegate_begin_invoke_cache;
974         if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
975                 return res;
976
977         g_assert (sig->hasthis);
978
979         if (!csig) {
980                 int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
981                 csig = g_malloc0 (sigsize);
982
983                 /* MonoAsyncResult * begin_invoke (MonoDelegate *delegate, gpointer params[]) */
984                 csig->param_count = 2;
985                 csig->ret = &mono_defaults.object_class->byval_arg;
986                 csig->params [0] = &mono_defaults.object_class->byval_arg;
987                 csig->params [1] = &mono_defaults.int_class->byval_arg;
988         }
989
990         name = mono_signature_to_name (sig, "begin_invoke");
991         mb = mono_mb_new (mono_defaults.multicastdelegate_class, name);
992         g_free (name);
993
994         mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_BEGIN_INVOKE;
995         mb->method->save_lmf = 1;
996
997         params_var = mono_mb_emit_save_args (mb, sig, FALSE);
998
999         mono_mb_emit_ldarg (mb, 0);
1000         mono_mb_emit_ldloc (mb, params_var);
1001         mono_mb_emit_native_call (mb, csig, mono_delegate_begin_invoke);
1002         mono_mb_emit_byte (mb, CEE_RET);
1003
1004         res = mono_mb_create_method (mb, sig, sig->param_count + 16);
1005         mono_mb_free (mb);
1006         g_hash_table_insert (cache, sig, res);
1007         return res;
1008 }
1009
1010 static MonoObject *
1011 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
1012 {
1013         MonoDomain *domain = mono_domain_get ();
1014         MonoAsyncResult *ares;
1015         MonoMethod *method = NULL;
1016         MonoMethodSignature *sig;
1017         MonoMethodMessage *msg;
1018         MonoObject *res, *exc;
1019         MonoArray *out_args;
1020         MonoClass *klass;
1021         int i;
1022
1023         g_assert (delegate);
1024
1025         if (!delegate->method_info || !delegate->method_info->method)
1026                 g_assert_not_reached ();
1027
1028         klass = delegate->object.vtable->klass;
1029
1030         for (i = 0; i < klass->method.count; ++i) {
1031                 if (klass->methods [i]->name[0] == 'E' && 
1032                     !strcmp ("EndInvoke", klass->methods [i]->name)) {
1033                         method = klass->methods [i];
1034                         break;
1035                 }
1036         }
1037
1038         g_assert (method != NULL);
1039
1040         sig = method->signature;
1041
1042         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
1043
1044         ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
1045         g_assert (ares);
1046
1047         res = mono_thread_pool_finish (ares, &out_args, &exc);
1048
1049         if (exc) {
1050                 char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
1051                 char  *tmp;
1052                 tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
1053                 g_free (strace);        
1054                 ((MonoException*)exc)->stack_trace = mono_string_new (domain, tmp);
1055                 g_free (tmp);
1056                 mono_raise_exception ((MonoException*)exc);
1057         }
1058
1059         mono_method_return_message_restore (method, params, out_args);
1060         return res;
1061 }
1062
1063 static void
1064 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
1065 {
1066         if (return_type->byref)
1067                 return_type = &mono_defaults.int_class->byval_arg;
1068         else if (return_type->type == MONO_TYPE_VALUETYPE && return_type->data.klass->enumtype)
1069                 return_type = return_type->data.klass->enum_basetype;
1070
1071         switch (return_type->type) {
1072         case MONO_TYPE_VOID:
1073                 g_assert_not_reached ();
1074                 break;
1075         case MONO_TYPE_STRING:
1076         case MONO_TYPE_CLASS: 
1077         case MONO_TYPE_OBJECT: 
1078         case MONO_TYPE_ARRAY: 
1079         case MONO_TYPE_SZARRAY: 
1080                 /* nothing to do */
1081                 break;
1082         case MONO_TYPE_U1:
1083         case MONO_TYPE_BOOLEAN:
1084                 mono_mb_emit_byte (mb, CEE_UNBOX);
1085                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1086                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1087                 break;
1088         case MONO_TYPE_I1:
1089                 mono_mb_emit_byte (mb, CEE_UNBOX);
1090                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1091                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
1092                 break;
1093         case MONO_TYPE_U2:
1094         case MONO_TYPE_CHAR:
1095                 mono_mb_emit_byte (mb, CEE_UNBOX);
1096                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1097                 mono_mb_emit_byte (mb, CEE_LDIND_U2);
1098                 break;
1099         case MONO_TYPE_I2:
1100                 mono_mb_emit_byte (mb, CEE_UNBOX);
1101                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1102                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1103                 break;
1104         case MONO_TYPE_I:
1105         case MONO_TYPE_U:
1106                 mono_mb_emit_byte (mb, CEE_UNBOX);
1107                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1108                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1109                 break;
1110         case MONO_TYPE_I4:
1111                 mono_mb_emit_byte (mb, CEE_UNBOX);
1112                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1113                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1114                 break;
1115         case MONO_TYPE_U4:
1116                 mono_mb_emit_byte (mb, CEE_UNBOX);
1117                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1118                 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1119                 break;
1120         case MONO_TYPE_U8:
1121         case MONO_TYPE_I8:
1122                 mono_mb_emit_byte (mb, CEE_UNBOX);
1123                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1124                 mono_mb_emit_byte (mb, CEE_LDIND_I8);
1125                 break;
1126         case MONO_TYPE_R4:
1127                 mono_mb_emit_byte (mb, CEE_UNBOX);
1128                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1129                 mono_mb_emit_byte (mb, CEE_LDIND_R4);
1130                 break;
1131         case MONO_TYPE_R8:
1132                 mono_mb_emit_byte (mb, CEE_UNBOX);
1133                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
1134                 mono_mb_emit_byte (mb, CEE_LDIND_R8);
1135                 break;
1136         case MONO_TYPE_VALUETYPE: {
1137                 int class;
1138                 mono_mb_emit_byte (mb, CEE_UNBOX);
1139                 class = mono_mb_add_data (mb, mono_class_from_mono_type (return_type));
1140                 mono_mb_emit_i4 (mb, class);
1141                 mono_mb_emit_byte (mb, CEE_LDOBJ);
1142                 mono_mb_emit_i4 (mb, class);
1143                 break;
1144         }
1145         default:
1146                 g_warning ("type 0x%x not handled", return_type->type);
1147                 g_assert_not_reached ();
1148         }
1149
1150         mono_mb_emit_byte (mb, CEE_RET);
1151 }
1152
1153 MonoMethod *
1154 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
1155 {
1156         MonoMethodSignature *sig;
1157         static MonoMethodSignature *csig = NULL;
1158         MonoMethodBuilder *mb;
1159         MonoMethod *res;
1160         GHashTable *cache;
1161         int params_var;
1162         char *name;
1163
1164         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1165                   !strcmp (method->name, "EndInvoke"));
1166
1167         sig = method->signature;
1168
1169         cache = method->klass->image->delegate_end_invoke_cache;
1170         if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
1171                 return res;
1172
1173         g_assert (sig->hasthis);
1174
1175         if (!csig) {
1176                 int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
1177                 csig = g_malloc0 (sigsize);
1178
1179                 /* MonoObject *end_invoke (MonoDelegate *delegate, gpointer params[]) */
1180                 csig->param_count = 2;
1181                 csig->ret = &mono_defaults.object_class->byval_arg;
1182                 csig->params [0] = &mono_defaults.object_class->byval_arg;
1183                 csig->params [1] = &mono_defaults.int_class->byval_arg;
1184         }
1185
1186         name = mono_signature_to_name (sig, "end_invoke");
1187         mb = mono_mb_new (mono_defaults.multicastdelegate_class, name);
1188         g_free (name);
1189
1190         mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_END_INVOKE;
1191         mb->method->save_lmf = 1;
1192
1193         params_var = mono_mb_emit_save_args (mb, sig, FALSE);
1194
1195         mono_mb_emit_ldarg (mb, 0);
1196         mono_mb_emit_ldloc (mb, params_var);
1197         mono_mb_emit_native_call (mb, csig, mono_delegate_end_invoke);
1198
1199         if (sig->ret->type == MONO_TYPE_VOID) {
1200                 mono_mb_emit_byte (mb, CEE_POP);
1201                 mono_mb_emit_byte (mb, CEE_RET);
1202         } else
1203                 mono_mb_emit_restore_result (mb, sig->ret);
1204
1205         res = mono_mb_create_method (mb, sig, sig->param_count + 16);
1206         mono_mb_free (mb);
1207         g_hash_table_insert (cache, sig, res);
1208
1209         return res;
1210 }
1211
1212 static MonoObject *
1213 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
1214 {
1215         MonoMethodMessage *msg;
1216         MonoTransparentProxy *this;
1217         MonoObject *res, *exc;
1218         MonoArray *out_args;
1219
1220         this = *((MonoTransparentProxy **)params [0]);
1221
1222         g_assert (this);
1223         g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
1224         
1225         /* skip the this pointer */
1226         params++;
1227
1228         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
1229
1230         res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
1231
1232         if (exc)
1233                 mono_raise_exception ((MonoException *)exc);
1234
1235         mono_method_return_message_restore (method, params, out_args);
1236
1237         return res;
1238
1239
1240 MonoMethod *
1241 mono_marshal_get_remoting_invoke (MonoMethod *method)
1242 {
1243         MonoMethodSignature *sig;
1244         static MonoMethodSignature *csig = NULL;
1245         MonoMethodBuilder *mb;
1246         MonoMethod *res;
1247         GHashTable *cache;
1248         int params_var;
1249
1250         g_assert (method);
1251
1252         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
1253                 return method;
1254
1255         sig = method->signature;
1256
1257         /* we cant remote methods without this pointer */
1258         if (!sig->hasthis)
1259                 return method;
1260
1261         cache = method->klass->image->remoting_invoke_cache;
1262         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
1263                 return res;
1264
1265         if (!csig) {
1266                 int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
1267                 csig = g_malloc0 (sigsize);
1268
1269                 /* MonoObject *remoting_wrapper (MonoMethod *method, gpointer params[]) */
1270                 csig->param_count = 2;
1271                 csig->ret = &mono_defaults.object_class->byval_arg;
1272                 csig->params [0] = &mono_defaults.int_class->byval_arg;
1273                 csig->params [1] = &mono_defaults.int_class->byval_arg;
1274         }
1275
1276         mb = mono_mb_new (method->klass, method->name);
1277         mb->method->wrapper_type = MONO_WRAPPER_REMOTING_INVOKE;
1278
1279         params_var = mono_mb_emit_save_args (mb, sig, TRUE);
1280
1281         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1282         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1283         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
1284         mono_mb_emit_ldloc (mb, params_var);
1285         mono_mb_emit_native_call (mb, csig, mono_remoting_wrapper);
1286
1287         if (sig->ret->type == MONO_TYPE_VOID)
1288                 mono_mb_emit_byte (mb, CEE_POP);
1289         else
1290                 mono_mb_emit_restore_result (mb, sig->ret);
1291
1292         res = mono_mb_create_method (mb, sig, sig->param_count + 16);
1293         mono_mb_free (mb);
1294         g_hash_table_insert (cache, method, res);
1295         return res;
1296 }
1297
1298 /*
1299  * the returned method invokes all methods in a multicast delegate 
1300  */
1301 MonoMethod *
1302 mono_marshal_get_delegate_invoke (MonoMethod *method)
1303 {
1304         MonoMethodSignature *sig, *static_sig;
1305         int i, sigsize;
1306         MonoMethodBuilder *mb;
1307         MonoMethod *res;
1308         GHashTable *cache;
1309         int pos [3];
1310         char *name;
1311
1312         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
1313                   !strcmp (method->name, "Invoke"));
1314                 
1315         sig = method->signature;
1316
1317         cache = method->klass->image->delegate_invoke_cache;
1318         if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
1319                 return res;
1320
1321         sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1322         static_sig = g_memdup (sig, sigsize);
1323         static_sig->hasthis = 0;
1324
1325         name = mono_signature_to_name (sig, "invoke");
1326         mb = mono_mb_new (mono_defaults.multicastdelegate_class, name);
1327         g_free (name);
1328
1329         mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_INVOKE;
1330
1331         /* allocate local 0 (object) prev */
1332         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1333         /* allocate local 1 (object) target */
1334         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1335         /* allocate local 2 (pointer) mptr */
1336         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1337
1338         /* allocate local 3 to store the return value */
1339         if (sig->ret->type != MONO_TYPE_VOID)
1340                 mono_mb_add_local (mb, sig->ret);
1341
1342         g_assert (sig->hasthis);
1343
1344         /* prev = addr of delegate */
1345         mono_mb_emit_ldarg (mb, 0);
1346         mono_mb_emit_stloc (mb, 0);
1347
1348         /* loop */
1349         pos [0] = mb->pos;
1350         /* target = delegate->target */
1351         mono_mb_emit_ldloc (mb, 0);
1352         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1353         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1354         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, target));
1355         mono_mb_emit_byte (mb, CEE_ADD);
1356         mono_mb_emit_byte (mb, CEE_LDIND_I);
1357         mono_mb_emit_stloc (mb, 1);
1358
1359         /* mptr = delegate->method_ptr */
1360         mono_mb_emit_ldloc (mb, 0);
1361         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1362         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1363         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
1364         mono_mb_emit_byte (mb, CEE_ADD);
1365         mono_mb_emit_byte (mb, CEE_LDIND_I);
1366         mono_mb_emit_stloc (mb, 2);
1367
1368         /* target == null ? */
1369         mono_mb_emit_ldloc (mb, 1);
1370         mono_mb_emit_byte (mb, CEE_BRTRUE); 
1371         pos [1] = mb->pos;
1372         mono_mb_emit_i4 (mb, 0);
1373
1374         /* emit static method call */
1375
1376         for (i = 0; i < sig->param_count; i++)
1377                 mono_mb_emit_ldarg (mb, i + 1);
1378
1379         mono_mb_emit_ldloc (mb, 2);
1380         mono_mb_emit_byte (mb, CEE_CALLI);
1381         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
1382
1383         if (sig->ret->type != MONO_TYPE_VOID)
1384                 mono_mb_emit_stloc (mb, 3);
1385
1386         mono_mb_emit_byte (mb, CEE_BR);
1387         pos [2] = mb->pos;
1388         mono_mb_emit_i4 (mb, 0);
1389    
1390         /* target != null, emit non static method call */
1391
1392         mono_mb_patch_addr (mb, pos [1], mb->pos - (pos [1] + 4));
1393         mono_mb_emit_ldloc (mb, 1);
1394
1395         for (i = 0; i < sig->param_count; i++)
1396                 mono_mb_emit_ldarg (mb, i + 1);
1397         
1398         mono_mb_emit_ldloc (mb, 2);
1399         mono_mb_emit_byte (mb, CEE_CALLI);
1400         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
1401
1402         if (sig->ret->type != MONO_TYPE_VOID)
1403                 mono_mb_emit_stloc (mb, 3);
1404
1405         mono_mb_patch_addr (mb, pos [2], mb->pos - (pos [2] + 4));
1406
1407         /* prev = delegate->prev */
1408         mono_mb_emit_ldloc (mb, 0);
1409         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1410         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1411         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
1412         mono_mb_emit_byte (mb, CEE_ADD);
1413         mono_mb_emit_byte (mb, CEE_LDIND_I);
1414         mono_mb_emit_stloc (mb, 0);
1415
1416         /* if prev != null goto loop */
1417         mono_mb_emit_ldloc (mb, 0);
1418         mono_mb_emit_byte (mb, CEE_BRTRUE);
1419         mono_mb_emit_i4 (mb, pos [0] - (mb->pos + 4));
1420
1421         if (sig->ret->type != MONO_TYPE_VOID)
1422                 mono_mb_emit_ldloc (mb, 3);
1423
1424         mono_mb_emit_byte (mb, CEE_RET);
1425
1426         res = mono_mb_create_method (mb, sig, sig->param_count + 16);
1427         mono_mb_free (mb);
1428
1429         g_hash_table_insert (cache, sig, res);
1430
1431         return res;     
1432 }
1433
1434 /*
1435  * generates IL code for the runtime invoke function 
1436  * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc)
1437  *
1438  * we also catch exceptions if exc != null
1439  */
1440 MonoMethod *
1441 mono_marshal_get_runtime_invoke (MonoMethod *method)
1442 {
1443         MonoMethodSignature *sig, *csig;
1444         MonoExceptionClause *clause;
1445         MonoMethodHeader *header;
1446         MonoMethodBuilder *mb;
1447         MonoMethod *res;
1448         GHashTable *cache;
1449         static MonoString *string_dummy = NULL;
1450         int i, pos, sigsize;
1451
1452         g_assert (method);
1453
1454         cache = method->klass->image->runtime_invoke_cache;
1455         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
1456                 return res;
1457         
1458         /* to make it work with our special string constructors */
1459         if (!string_dummy)
1460                 string_dummy = mono_string_new_wrapper ("dummy");
1461
1462         sig = method->signature;
1463
1464         sigsize = sizeof (MonoMethodSignature) + 3 * sizeof (MonoType *);
1465         csig = g_malloc0 (sigsize);
1466
1467         csig->param_count = 3;
1468         csig->ret = &mono_defaults.object_class->byval_arg;
1469         csig->params [0] = &mono_defaults.object_class->byval_arg;
1470         csig->params [1] = &mono_defaults.int_class->byval_arg;
1471         csig->params [2] = &mono_defaults.int_class->byval_arg;
1472
1473         mb = mono_mb_new (method->klass, method->name);
1474         mb->method->wrapper_type = MONO_WRAPPER_RUNTIME_INVOKE;
1475
1476         /* allocate local 0 (object) tmp */
1477         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1478         /* allocate local 1 (object) exc */
1479         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1480
1481         /* cond set *exc to null */
1482         mono_mb_emit_byte (mb, CEE_LDARG_2);
1483         mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1484         mono_mb_emit_byte (mb, 3);      
1485         mono_mb_emit_byte (mb, CEE_LDARG_2);
1486         mono_mb_emit_byte (mb, CEE_LDNULL);
1487         mono_mb_emit_byte (mb, CEE_STIND_I);
1488
1489         if (sig->hasthis) {
1490                 if (method->string_ctor) {
1491                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1492                         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1493                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
1494                 } else {
1495                         mono_mb_emit_ldarg (mb, 0);
1496                         if (method->klass->valuetype) {
1497                                 mono_mb_emit_byte (mb, CEE_UNBOX);
1498                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method->klass));
1499                         } 
1500                 }
1501         }
1502
1503         for (i = 0; i < sig->param_count; i++) {
1504                 MonoType *t = sig->params [i];
1505                 int type;
1506
1507                 mono_mb_emit_ldarg (mb, 1);
1508                 if (i) {
1509                         mono_mb_emit_icon (mb, sizeof (gpointer) * i);
1510                         mono_mb_emit_byte (mb, CEE_ADD);
1511                 }
1512                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1513
1514                 if (t->byref)
1515                         continue;
1516
1517                 type = sig->params [i]->type;
1518 handle_enum:
1519                 switch (type) {
1520                 case MONO_TYPE_I1:
1521                         mono_mb_emit_byte (mb, CEE_LDIND_I1);
1522                         break;
1523                 case MONO_TYPE_BOOLEAN:
1524                 case MONO_TYPE_U1:
1525                         mono_mb_emit_byte (mb, CEE_LDIND_U1);
1526                         break;
1527                 case MONO_TYPE_I2:
1528                         mono_mb_emit_byte (mb, CEE_LDIND_I2);
1529                         break;
1530                 case MONO_TYPE_U2:
1531                 case MONO_TYPE_CHAR:
1532                         mono_mb_emit_byte (mb, CEE_LDIND_U2);
1533                         break;
1534                 case MONO_TYPE_I:
1535                 case MONO_TYPE_U:
1536                         mono_mb_emit_byte (mb, CEE_LDIND_I);
1537                         break;
1538                 case MONO_TYPE_I4:
1539                         mono_mb_emit_byte (mb, CEE_LDIND_I4);
1540                         break;
1541                 case MONO_TYPE_U4:
1542                         mono_mb_emit_byte (mb, CEE_LDIND_U4);
1543                         break;
1544                 case MONO_TYPE_R4:
1545                         mono_mb_emit_byte (mb, CEE_LDIND_R4);
1546                         break;
1547                 case MONO_TYPE_R8:
1548                         mono_mb_emit_byte (mb, CEE_LDIND_R8);
1549                         break;
1550                 case MONO_TYPE_I8:
1551                 case MONO_TYPE_U8:
1552                         mono_mb_emit_byte (mb, CEE_LDIND_I8);
1553                         break;
1554                 case MONO_TYPE_STRING:
1555                 case MONO_TYPE_CLASS:  
1556                 case MONO_TYPE_ARRAY:
1557                 case MONO_TYPE_PTR:
1558                 case MONO_TYPE_SZARRAY:
1559                 case MONO_TYPE_OBJECT:
1560                         /* do nothing */
1561                         break;
1562                 case MONO_TYPE_VALUETYPE:
1563                         if (t->data.klass->enumtype) {
1564                                 type = t->data.klass->enum_basetype->type;
1565                                 goto handle_enum;
1566                         }
1567                         mono_mb_emit_byte (mb, CEE_LDOBJ);
1568                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
1569                         break;
1570                 default:
1571                         g_assert_not_reached ();
1572                 }               
1573         }
1574
1575         if (method->string_ctor) {
1576                 MonoMethodSignature *strsig;
1577
1578                 sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1579                 strsig = g_memdup (sig, sigsize);
1580                 strsig->ret = &mono_defaults.string_class->byval_arg;
1581
1582                 mono_mb_emit_managed_call (mb, method, strsig);         
1583         } else 
1584                 mono_mb_emit_managed_call (mb, method, NULL);
1585
1586         if (sig->ret->byref) {
1587                 /* fixme: */
1588                 g_assert_not_reached ();
1589         }
1590
1591
1592         switch (sig->ret->type) {
1593         case MONO_TYPE_VOID:
1594                 if (!method->string_ctor)
1595                         mono_mb_emit_byte (mb, CEE_LDNULL);
1596                 break;
1597         case MONO_TYPE_I1:
1598         case MONO_TYPE_U1:
1599         case MONO_TYPE_I2:
1600         case MONO_TYPE_U2:
1601         case MONO_TYPE_I4:
1602         case MONO_TYPE_U4:
1603         case MONO_TYPE_I:
1604         case MONO_TYPE_U:
1605         case MONO_TYPE_R4:
1606         case MONO_TYPE_R8:
1607         case MONO_TYPE_I8:
1608         case MONO_TYPE_U8:
1609         case MONO_TYPE_VALUETYPE:
1610                 /* box value types */
1611                 mono_mb_emit_byte (mb, CEE_BOX);
1612                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret)));
1613                 break;
1614         case MONO_TYPE_STRING:
1615         case MONO_TYPE_CLASS:  
1616         case MONO_TYPE_ARRAY:
1617         case MONO_TYPE_SZARRAY:
1618         case MONO_TYPE_OBJECT:
1619                 /* nothing to do */
1620                 break;
1621         case MONO_TYPE_PTR:
1622         default:
1623                 g_assert_not_reached ();
1624         }
1625
1626         mono_mb_emit_stloc (mb, 0);
1627                 
1628         mono_mb_emit_byte (mb, CEE_LEAVE);
1629         pos = mb->pos;
1630         mono_mb_emit_i4 (mb, 0);
1631
1632         clause = g_new0 (MonoExceptionClause, 1);
1633         clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
1634         clause->try_len = mb->pos;
1635
1636         /* filter code */
1637         clause->token_or_filter = mb->pos;
1638         
1639         mono_mb_emit_byte (mb, CEE_POP);
1640         mono_mb_emit_byte (mb, CEE_LDARG_2);
1641         mono_mb_emit_byte (mb, CEE_PREFIX1);
1642         mono_mb_emit_byte (mb, CEE_ENDFILTER);
1643
1644         clause->handler_offset = mb->pos;
1645
1646         /* handler code */
1647         /* store exception */
1648         mono_mb_emit_stloc (mb, 1);
1649         
1650         mono_mb_emit_byte (mb, CEE_LDARG_2);
1651         mono_mb_emit_ldloc (mb, 1);
1652         mono_mb_emit_byte (mb, CEE_STIND_I);
1653
1654         mono_mb_emit_byte (mb, CEE_LEAVE);
1655         mono_mb_emit_i4 (mb, 0);
1656
1657         clause->handler_len = mb->pos - clause->handler_offset;
1658
1659         /* return result */
1660         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
1661         mono_mb_emit_ldloc (mb, 0);
1662         mono_mb_emit_byte (mb, CEE_RET);
1663         
1664         res = mono_mb_create_method (mb, csig, sig->param_count + 16);
1665         mono_mb_free (mb);
1666
1667         header = ((MonoMethodNormal *)res)->header;
1668         header->num_clauses = 1;
1669         header->clauses = clause;
1670
1671         g_hash_table_insert (cache, method, res);
1672
1673         return res;     
1674 }
1675
1676 /*
1677  * generates IL code to call managed methods from unmanaged code 
1678  */
1679 MonoMethod *
1680 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
1681 {
1682         MonoMethodSignature *sig, *csig;
1683         MonoMethodBuilder *mb;
1684         MonoClass *klass;
1685         MonoMethod *res;
1686         GHashTable *cache;
1687         int i, pos, sigsize, *tmp_locals;
1688
1689         g_assert (method != NULL);
1690
1691         cache = method->klass->image->managed_wrapper_cache;
1692         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
1693                 return res;
1694
1695         sig = method->signature;
1696
1697         mb = mono_mb_new (method->klass, method->name);
1698         mb->method->wrapper_type = MONO_WRAPPER_NATIVE_TO_MANAGED;
1699
1700         /* allocate local 0 (pointer) src_ptr */
1701         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1702         /* allocate local 1 (pointer) dst_ptr */
1703         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1704         /* allocate local 2 (boolean) delete_old */
1705         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
1706
1707         mono_mb_emit_byte (mb, CEE_LDNULL);
1708         mono_mb_emit_byte (mb, CEE_STLOC_2);
1709
1710         /* we copy the signature, so that we can modify it */
1711         sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1712         csig = g_memdup (sig, sigsize);
1713         csig->hasthis = 0;
1714         csig->pinvoke = 1;
1715
1716         /* fixme: howto handle this ? */
1717         if (sig->hasthis) {
1718
1719                 if (this) {
1720                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1721                         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1722                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, this));
1723
1724
1725                 } else {
1726                         /* fixme: */
1727                         g_assert_not_reached ();
1728                 }
1729         } 
1730
1731
1732         /* we first do all conversions */
1733         tmp_locals = alloca (sizeof (int) * sig->param_count);
1734         for (i = 0; i < sig->param_count; i ++) {
1735                 MonoType *t = sig->params [i];
1736
1737                 tmp_locals [i] = 0;
1738                 
1739                 switch (t->type) {
1740                 case MONO_TYPE_VALUETYPE:
1741                         
1742                         klass = sig->params [i]->data.klass;
1743                         if (klass->blittable || klass->enumtype)
1744                                 break;
1745
1746                         tmp_locals [i] = mono_mb_add_local (mb, &klass->byval_arg);
1747
1748                         if (t->byref) 
1749                                 mono_mb_emit_ldarg (mb, i);
1750                         else
1751                                 mono_mb_emit_ldarg_addr (mb, i);
1752                         mono_mb_emit_byte (mb, CEE_STLOC_0);
1753
1754                         if (t->byref) {
1755                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
1756                                 mono_mb_emit_byte (mb, CEE_BRFALSE);
1757                                 pos = mb->pos;
1758                                 mono_mb_emit_i4 (mb, 0);
1759                         }                       
1760
1761                         mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
1762                         mono_mb_emit_byte (mb, CEE_STLOC_1);
1763
1764                         /* emit valuetype convnversion code code */
1765                         emit_struct_conv (mb, klass, TRUE);
1766
1767                         if (t->byref)
1768                                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
1769                         break;
1770                 case MONO_TYPE_STRING:
1771                         if (t->byref)
1772                                 continue;
1773
1774                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1775                         csig->params [i] = &mono_defaults.int_class->byval_arg;
1776
1777                         mono_mb_emit_ldarg (mb, i);
1778                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1779                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
1780                         mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
1781                         mono_mb_emit_stloc (mb, tmp_locals [i]);
1782                         break;  
1783                 case MONO_TYPE_ARRAY:
1784                 case MONO_TYPE_SZARRAY:
1785                         if (t->byref)
1786                                 continue;
1787
1788                         klass = mono_class_from_mono_type (t);
1789
1790                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1791                         csig->params [i] = &mono_defaults.int_class->byval_arg;
1792
1793                         g_warning ("array marshaling not implemented");
1794                         g_assert_not_reached ();
1795                         break;
1796                 }
1797         }
1798
1799         for (i = 0; i < sig->param_count; i++) {
1800                 MonoType *t = sig->params [i];
1801
1802                 switch (t->type) {
1803                 case MONO_TYPE_I1:
1804                 case MONO_TYPE_U1:
1805                 case MONO_TYPE_I2:
1806                 case MONO_TYPE_U2:
1807                 case MONO_TYPE_I4:
1808                 case MONO_TYPE_U4:
1809                 case MONO_TYPE_I:
1810                 case MONO_TYPE_U:
1811                 case MONO_TYPE_PTR:
1812                 case MONO_TYPE_R4:
1813                 case MONO_TYPE_R8:
1814                 case MONO_TYPE_I8:
1815                 case MONO_TYPE_U8:
1816                         mono_mb_emit_ldarg (mb, i);
1817                         break;
1818                 case MONO_TYPE_STRING:
1819                         if (t->byref) {
1820                                 mono_mb_emit_ldarg (mb, i);
1821                         } else {
1822                                 g_assert (tmp_locals [i]);
1823                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
1824                         }
1825                         break;  
1826                 case MONO_TYPE_CLASS:  
1827                 case MONO_TYPE_ARRAY:
1828                 case MONO_TYPE_SZARRAY:
1829                 case MONO_TYPE_OBJECT:
1830                         /* fixme: conversions ? */
1831                         mono_mb_emit_ldarg (mb, i);
1832                         break;
1833                 case MONO_TYPE_VALUETYPE:
1834                         klass = sig->params [i]->data.klass;
1835                         if (klass->blittable || klass->enumtype) {
1836                                 mono_mb_emit_ldarg (mb, i);
1837                                 break;
1838                         }
1839
1840                         g_assert (tmp_locals [i]);
1841                         if (t->byref)
1842                                 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
1843                         else
1844                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
1845                         break;
1846                 default:
1847                         g_warning ("type 0x%02x unknown", t->type);     
1848                         g_assert_not_reached ();
1849                 }
1850         }
1851
1852         mono_mb_emit_managed_call (mb, method, NULL);
1853
1854         if (!sig->ret->byref) { 
1855                 switch (sig->ret->type) {
1856                 case MONO_TYPE_VOID:
1857                 case MONO_TYPE_BOOLEAN:
1858                 case MONO_TYPE_I1:
1859                 case MONO_TYPE_U1:
1860                 case MONO_TYPE_I2:
1861                 case MONO_TYPE_U2:
1862                 case MONO_TYPE_I4:
1863                 case MONO_TYPE_U4:
1864                 case MONO_TYPE_I:
1865                 case MONO_TYPE_U:
1866                 case MONO_TYPE_PTR:
1867                 case MONO_TYPE_R4:
1868                 case MONO_TYPE_R8:
1869                 case MONO_TYPE_I8:
1870                 case MONO_TYPE_U8:
1871                         /* do nothing */
1872                         break;
1873                 case MONO_TYPE_STRING:          
1874                         csig->ret = &mono_defaults.int_class->byval_arg;
1875
1876                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1877                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
1878                         mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
1879                         break;
1880                 case MONO_TYPE_VALUETYPE: {
1881                         int tmp;
1882                         klass = sig->ret->data.klass;
1883                         if (klass->blittable || klass->enumtype)
1884                                 break;
1885                         
1886                         /* load pointer to returned value type */
1887                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1888                         mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
1889                         
1890                         /* store the address of the source into local variable 0 */
1891                         mono_mb_emit_byte (mb, CEE_STLOC_0);
1892                         /* allocate space for the native struct and
1893                          * store the address into dst_ptr */
1894                         tmp = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1895                         g_assert (tmp);
1896                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
1897                         mono_mb_emit_byte (mb, CEE_PREFIX1);
1898                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
1899                         mono_mb_emit_byte (mb, CEE_STLOC_1);
1900                         mono_mb_emit_byte (mb, CEE_LDLOC_1);
1901                         mono_mb_emit_stloc (mb, tmp);
1902
1903                         /* emit valuetype conversion code */
1904                         emit_struct_conv (mb, klass, FALSE);
1905                         mono_mb_emit_ldloc (mb, tmp);
1906                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1907                         mono_mb_emit_byte (mb, CEE_MONO_RETOBJ);
1908                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
1909                         break;
1910                 }
1911                 default:
1912                         g_warning ("return type 0x%02x unknown", sig->ret->type);       
1913                         g_assert_not_reached ();
1914                 }
1915         }
1916
1917         mono_mb_emit_byte (mb, CEE_RET);
1918
1919         res = mono_mb_create_method (mb, csig, sig->param_count + 16);
1920         mono_mb_free (mb);
1921
1922         g_hash_table_insert (cache, method, res);
1923
1924         return res;
1925 }
1926
1927 /*
1928  * generates IL code for the pinvoke wrapper (the generated method
1929  * calls the unamnage code in method->addr)
1930  */
1931 MonoMethod *
1932 mono_marshal_get_native_wrapper (MonoMethod *method)
1933 {
1934         MonoMethodSignature *sig, *csig;
1935         MonoMethodBuilder *mb;
1936         MonoMethod *res;
1937         GHashTable *cache;
1938         MonoClass *klass;
1939         gboolean pinvoke = FALSE;
1940         int i, pos, argnum, *tmp_locals;
1941         int type, sigsize;
1942
1943         g_assert (method != NULL);
1944
1945         cache = method->klass->image->native_wrapper_cache;
1946         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
1947                 return res;
1948
1949         sig = method->signature;
1950
1951         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
1952             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1953                 pinvoke = TRUE;
1954
1955         mb = mono_mb_new (method->klass, method->name);
1956         mb->method->wrapper_type = MONO_WRAPPER_MANAGED_TO_NATIVE;
1957
1958         mb->method->save_lmf = 1;
1959
1960         if (pinvoke && !method->addr)
1961                 mono_lookup_pinvoke_call (method);
1962
1963         if (!method->addr) {
1964                 mono_mb_emit_exception (mb);
1965                 res = mono_mb_create_method (mb, sig, sig->param_count + 16);
1966                 mono_mb_free (mb);
1967                 g_hash_table_insert (cache, method, res);
1968                 return res;
1969         }
1970
1971         /* we copy the signature, so that we can modify it */
1972         sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1973         csig = g_memdup (sig, sigsize);
1974
1975         /* internal calls: we simply push all arguments and call the method (no conversions) */
1976         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
1977
1978                 /* hack - string constructors returns a value */
1979                 if (method->string_ctor)
1980                         csig->ret = &mono_defaults.string_class->byval_arg;
1981
1982                 if (sig->hasthis)
1983                         mono_mb_emit_byte (mb, CEE_LDARG_0);
1984
1985                 for (i = 0; i < sig->param_count; i++)
1986                         mono_mb_emit_ldarg (mb, i + sig->hasthis);
1987
1988                 g_assert (method->addr);
1989                 mono_mb_emit_native_call (mb, csig, method->addr);
1990
1991                 mono_mb_emit_byte (mb, CEE_RET);
1992
1993                 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
1994                 mono_mb_free (mb);
1995                 g_hash_table_insert (cache, method, res);
1996                 return res;
1997         }
1998
1999         g_assert (pinvoke);
2000
2001         /* pinvoke: we need to convert the arguments if necessary */
2002
2003         csig->pinvoke = 1;
2004
2005         /* we allocate local for use with emit_struct_conv() */
2006         /* allocate local 0 (pointer) src_ptr */
2007         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2008         /* allocate local 1 (pointer) dst_ptr */
2009         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2010         /* allocate local 2 (boolean) delete_old */
2011         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
2012
2013         /* delete_old = FALSE */
2014         mono_mb_emit_icon (mb, 0);
2015         mono_mb_emit_byte (mb, CEE_STLOC_2);
2016
2017         if (sig->ret->type != MONO_TYPE_VOID) {
2018                 /* allocate local 3 to store the return value */
2019                 mono_mb_add_local (mb, sig->ret);
2020         }
2021
2022         /* we first do all conversions */
2023         tmp_locals = alloca (sizeof (int) * sig->param_count);
2024         for (i = 0; i < sig->param_count; i ++) {
2025                 MonoType *t = sig->params [i];
2026
2027                 argnum = i + sig->hasthis;
2028                 tmp_locals [i] = 0;
2029
2030                 switch (t->type) {
2031                 case MONO_TYPE_VALUETYPE:                       
2032                         klass = t->data.klass;
2033                         if (klass->blittable || klass->enumtype)
2034                                 break;
2035
2036                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2037                         
2038                         /* store the address of the source into local variable 0 */
2039                         if (t->byref)
2040                                 mono_mb_emit_ldarg (mb, argnum);
2041                         else
2042                                 mono_mb_emit_ldarg_addr (mb, argnum);
2043
2044                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2045                         
2046                         if (t->byref) {
2047                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
2048                                 mono_mb_emit_byte (mb, CEE_BRFALSE);
2049                                 pos = mb->pos;
2050                                 mono_mb_emit_i4 (mb, 0);
2051                         }
2052
2053                         /* allocate space for the native struct and
2054                          * store the address into local variable 1 (dest) */
2055                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
2056                         mono_mb_emit_byte (mb, CEE_PREFIX1);
2057                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
2058                         mono_mb_emit_stloc (mb, tmp_locals [i]);
2059                         /* set dst_ptr */
2060                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
2061                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2062
2063                         /* emit valuetype conversion code */
2064                         emit_struct_conv (mb, klass, FALSE);
2065                         
2066                         if (t->byref)
2067                                 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2068                         break;
2069                 case MONO_TYPE_STRING:
2070                         if (t->byref)
2071                                 continue;
2072
2073                         csig->params [argnum] = &mono_defaults.int_class->byval_arg;
2074                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2075
2076                         mono_mb_emit_ldarg (mb, argnum);
2077                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2078                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
2079                         mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
2080                         mono_mb_emit_stloc (mb, tmp_locals [i]);
2081                         break;
2082                 case MONO_TYPE_CLASS:
2083                 case MONO_TYPE_OBJECT:
2084                         if (t->byref)
2085                                 continue;
2086
2087                         csig->params [argnum] = &mono_defaults.int_class->byval_arg;
2088                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2089
2090                         mono_mb_emit_ldarg (mb, argnum);
2091                         mono_mb_emit_byte (mb, CEE_BRFALSE);
2092                         pos = mb->pos;
2093                         mono_mb_emit_i4 (mb, 0);
2094
2095                         if (t->data.klass->delegate) {
2096                                 mono_mb_emit_ldarg (mb, argnum);
2097                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2098                                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
2099                                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_DEL_FTN);
2100                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
2101                         } else if (t->data.klass == mono_defaults.stringbuilder_class) {
2102                                 mono_mb_emit_ldarg (mb, argnum);
2103                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2104                                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
2105                                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_SB_LPSTR);
2106                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
2107                         } else {
2108                                 mono_mb_emit_ldarg (mb, argnum);
2109                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2110                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
2111                                 /* fixme: convert to what ? */
2112                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
2113                         }
2114
2115                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2116                         
2117                         break;
2118                 case MONO_TYPE_ARRAY:
2119                 case MONO_TYPE_SZARRAY:
2120                         if (t->byref)
2121                                 continue;
2122
2123                         klass = mono_class_from_mono_type (t);
2124
2125                         csig->params [argnum] = &mono_defaults.int_class->byval_arg;
2126                         tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2127
2128                         mono_mb_emit_ldarg (mb, argnum);
2129                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2130                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
2131                         if (klass->element_class == mono_defaults.string_class) 
2132                                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY);
2133                         else
2134                                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_ARRAY_LPARRAY);
2135                         mono_mb_emit_stloc (mb, tmp_locals [i]);
2136                         break;
2137                 }
2138         }
2139
2140         /* push all arguments */
2141
2142         if (sig->hasthis)
2143                 mono_mb_emit_byte (mb, CEE_LDARG_0);
2144
2145         for (i = 0; i < sig->param_count; i++) {
2146                 MonoType *t = sig->params [i];
2147                 
2148                 argnum = i + sig->hasthis;
2149
2150                 switch (t->type) {
2151                 case MONO_TYPE_BOOLEAN:
2152                         if (t->byref)
2153                                 g_warning ("byref boolean marshalling not inplemented");
2154                         mono_mb_emit_ldarg (mb, argnum);
2155                         break;
2156                 case MONO_TYPE_I1:
2157                 case MONO_TYPE_U1:
2158                 case MONO_TYPE_I2:
2159                 case MONO_TYPE_U2:
2160                 case MONO_TYPE_I4:
2161                 case MONO_TYPE_U4:
2162                 case MONO_TYPE_I:
2163                 case MONO_TYPE_U:
2164                 case MONO_TYPE_PTR:
2165                 case MONO_TYPE_R4:
2166                 case MONO_TYPE_R8:
2167                 case MONO_TYPE_I8:
2168                 case MONO_TYPE_U8:
2169                         mono_mb_emit_ldarg (mb, argnum);
2170                         break;
2171                 case MONO_TYPE_VALUETYPE:
2172                         klass = sig->params [i]->data.klass;
2173                         if (klass->blittable || klass->enumtype) {
2174                                 mono_mb_emit_ldarg (mb, argnum);
2175                                 break;
2176                         }                       
2177                         g_assert (tmp_locals [i]);
2178                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
2179                         if (!t->byref) {
2180                                 mono_mb_emit_byte (mb, CEE_LDOBJ);
2181                                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
2182                         }
2183                         break;
2184                 case MONO_TYPE_STRING:
2185                         if (t->byref) {
2186                                 mono_mb_emit_ldarg (mb, argnum);
2187                         } else {
2188                                 g_assert (tmp_locals [i]);
2189                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2190                         }
2191                         break;
2192                 case MONO_TYPE_CLASS:
2193                 case MONO_TYPE_OBJECT:
2194                         if (t->byref) {
2195                                 mono_mb_emit_ldarg (mb, argnum);
2196                         } else {
2197                                 g_assert (tmp_locals [i]);
2198                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2199                         }
2200                         break;
2201                 case MONO_TYPE_CHAR:
2202                         /* fixme: dont know how to marshal that. We cant simply
2203                          * convert it to a one byte UTF8 character, because an
2204                          * unicode character may need more that one byte in UTF8 */
2205                         mono_mb_emit_ldarg (mb, argnum);
2206                         break;
2207                 case MONO_TYPE_ARRAY:
2208                 case MONO_TYPE_SZARRAY:
2209                         if (t->byref) {
2210                                 mono_mb_emit_ldarg (mb, argnum);
2211                         } else {
2212                                 g_assert (tmp_locals [i]);
2213                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2214                         }
2215                         break;
2216                 case MONO_TYPE_TYPEDBYREF:
2217                 case MONO_TYPE_FNPTR:
2218                 default:
2219                         g_warning ("type 0x%02x unknown", t->type);     
2220                         g_assert_not_reached ();
2221                 }
2222         }                       
2223
2224         /* call the native method */
2225         mono_mb_emit_native_call (mb, csig, method->addr);
2226
2227         /* return the result */
2228
2229         /* we need to convert byref arguments back and free string arrays */
2230         for (i = 0; i < sig->param_count; i++) {
2231                 MonoType *t = sig->params [i];
2232                 
2233                 argnum = i + sig->hasthis;
2234
2235                 switch (t->type) {
2236                 case MONO_TYPE_CLASS:
2237                 case MONO_TYPE_OBJECT:                  
2238                         if (t->byref)
2239                                 continue;
2240      
2241                         if (t->data.klass == mono_defaults.stringbuilder_class) {
2242                                 mono_mb_emit_ldarg (mb, argnum);
2243                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2244                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2245                                 mono_mb_emit_byte (mb, CEE_MONO_PROC2);
2246                                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_SB);
2247                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2248                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2249                                 mono_mb_emit_byte (mb, CEE_MONO_FREE);
2250                         }
2251                         break;
2252                 case MONO_TYPE_VALUETYPE:
2253                         if (!t->byref)
2254                                 continue;
2255         
2256                         klass = t->data.klass;
2257                         if (klass->blittable || klass->enumtype)
2258                                 break;
2259
2260                         /* dst = argument */
2261                         mono_mb_emit_ldarg (mb, argnum);
2262                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2263
2264                         mono_mb_emit_byte (mb, CEE_LDLOC_1);
2265                         mono_mb_emit_byte (mb, CEE_BRFALSE);
2266                         pos = mb->pos;
2267                         mono_mb_emit_i4 (mb, 0);
2268
2269                         /* src = tmp_locals [i] */
2270                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
2271                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2272
2273                         /* emit valuetype conversion code */
2274                         emit_struct_conv (mb, klass, TRUE);
2275                         
2276                         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
2277                         break;
2278                 case MONO_TYPE_SZARRAY:
2279                         if (t->byref)
2280                                 continue;
2281  
2282                         klass = mono_class_from_mono_type (t);
2283                         
2284                         if (klass->element_class == mono_defaults.string_class) {
2285                                 g_assert (tmp_locals [i]);
2286                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
2287                                 mono_mb_emit_ldarg (mb, argnum);
2288                                 mono_mb_emit_byte (mb, CEE_LDLEN);                              
2289                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2290                                 mono_mb_emit_byte (mb, CEE_MONO_PROC2);
2291                                 mono_mb_emit_byte (mb, MONO_MARSHAL_FREE_ARRAY);
2292                         }
2293
2294                         break;
2295                 }
2296         }
2297
2298         if (!sig->ret->byref) {
2299                 type = sig->ret->type;
2300         handle_enum:
2301                 switch (type) {
2302                 case MONO_TYPE_VOID:
2303                 case MONO_TYPE_I1:
2304                 case MONO_TYPE_U1:
2305                 case MONO_TYPE_I2:
2306                 case MONO_TYPE_U2:
2307                 case MONO_TYPE_I4:
2308                 case MONO_TYPE_U4:
2309                 case MONO_TYPE_I:
2310                 case MONO_TYPE_U:
2311                 case MONO_TYPE_PTR:
2312                 case MONO_TYPE_R4:
2313                 case MONO_TYPE_R8:
2314                 case MONO_TYPE_I8:
2315                 case MONO_TYPE_U8:
2316                 /* no conversions necessary */
2317                         break;
2318                 case MONO_TYPE_BOOLEAN:
2319                         /* maybe we need to make sure that it fits within 8 bits */
2320                         break;
2321                 case MONO_TYPE_VALUETYPE: {
2322                         int tmp;
2323
2324                         klass = sig->ret->data.klass;
2325                         if (klass->enumtype) {
2326                                 type = sig->ret->data.klass->enum_basetype->type;
2327                                 goto handle_enum;
2328                         }
2329
2330                         if (klass->blittable)
2331                                 break;
2332
2333                         tmp = mono_mb_add_local (mb, sig->ret);
2334                         g_assert (tmp);
2335                         /* load pointer to returned value type */
2336                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2337                         mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
2338                         /* store the address of the source into local variable 0 */
2339                         mono_mb_emit_byte (mb, CEE_STLOC_0);
2340                         /* set dst_ptr */
2341                         mono_mb_emit_ldloc_addr (mb, tmp);
2342                         mono_mb_emit_byte (mb, CEE_STLOC_1);
2343
2344                         /* emit valuetype conversion code */
2345                         emit_struct_conv (mb, sig->ret->data.klass, TRUE);
2346
2347                         mono_mb_emit_ldloc (mb, tmp);
2348                         break;
2349                 }
2350                 case MONO_TYPE_STRING:
2351                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2352                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
2353                         mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
2354                         break;
2355                 case MONO_TYPE_ARRAY:
2356                 case MONO_TYPE_SZARRAY:
2357                 case MONO_TYPE_CLASS:
2358                 case MONO_TYPE_OBJECT:
2359                         /* fixme: we need conversions here */
2360                         break;
2361                 case MONO_TYPE_CHAR:
2362                         /* fixme: we need conversions here */
2363                         break;
2364                 case MONO_TYPE_TYPEDBYREF:
2365                 case MONO_TYPE_FNPTR:
2366                 default:
2367                         g_warning ("return type 0x%02x unknown", sig->ret->type);       
2368                         g_assert_not_reached ();
2369                 }
2370         }
2371
2372         mono_mb_emit_byte (mb, CEE_RET);
2373
2374         res = mono_mb_create_method (mb, sig, sig->param_count + 16);
2375         mono_mb_free (mb);
2376
2377         g_hash_table_insert (cache, method, res);
2378
2379         return res;
2380 }
2381
2382 /*
2383  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
2384  */
2385 MonoMethod *
2386 mono_marshal_get_struct_to_ptr (MonoClass *klass)
2387 {
2388         MonoMethodBuilder *mb;
2389         static MonoMethod *stoptr = NULL;
2390         MonoMethod *res;
2391
2392         g_assert (klass != NULL);
2393
2394         if (klass->str_to_ptr)
2395                 return klass->str_to_ptr;
2396
2397         if (!stoptr) 
2398                 stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
2399         g_assert (stoptr);
2400
2401         mb = mono_mb_new (klass, stoptr->name);
2402
2403         if (klass->blittable) {
2404                 mono_mb_emit_byte (mb, CEE_LDARG_1);
2405                 mono_mb_emit_byte (mb, CEE_LDARG_0);
2406                 mono_mb_emit_icon (mb, sizeof (MonoObject));
2407                 mono_mb_emit_byte (mb, CEE_ADD);
2408                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
2409                 mono_mb_emit_byte (mb, CEE_PREFIX1);
2410                 mono_mb_emit_byte (mb, CEE_CPBLK);
2411         } else {
2412
2413                 /* allocate local 0 (pointer) src_ptr */
2414                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2415                 /* allocate local 1 (pointer) dst_ptr */
2416                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2417                 /* allocate local 2 (boolean) delete_old */
2418                 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
2419                 mono_mb_emit_byte (mb, CEE_LDARG_2);
2420                 mono_mb_emit_byte (mb, CEE_STLOC_2);
2421
2422                 /* initialize src_ptr to point to the start of object data */
2423                 mono_mb_emit_byte (mb, CEE_LDARG_0);
2424                 mono_mb_emit_icon (mb, sizeof (MonoObject));
2425                 mono_mb_emit_byte (mb, CEE_ADD);
2426                 mono_mb_emit_byte (mb, CEE_STLOC_0);
2427
2428                 /* initialize dst_ptr */
2429                 mono_mb_emit_byte (mb, CEE_LDARG_1);
2430                 mono_mb_emit_byte (mb, CEE_STLOC_1);
2431
2432                 emit_struct_conv (mb, klass, FALSE);
2433         }
2434
2435         mono_mb_emit_byte (mb, CEE_RET);
2436
2437         res = mono_mb_create_method (mb, stoptr->signature, 0);
2438         mono_mb_free (mb);
2439
2440         klass->str_to_ptr = res;
2441         return res;
2442 }
2443
2444 /*
2445  * generates IL code for PtrToStructure (IntPtr src, object structure)
2446  */
2447 MonoMethod *
2448 mono_marshal_get_ptr_to_struct (MonoClass *klass)
2449 {
2450         MonoMethodBuilder *mb;
2451         static MonoMethod *ptostr = NULL;
2452         MonoMethod *res;
2453
2454         g_assert (klass != NULL);
2455
2456         if (klass->ptr_to_str)
2457                 return klass->ptr_to_str;
2458
2459         if (!ptostr) 
2460                 ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
2461         g_assert (ptostr);
2462
2463         mb = mono_mb_new (klass, ptostr->name);
2464
2465         if (klass->blittable) {
2466                 mono_mb_emit_byte (mb, CEE_LDARG_1);
2467                 mono_mb_emit_icon (mb, sizeof (MonoObject));
2468                 mono_mb_emit_byte (mb, CEE_ADD);
2469                 mono_mb_emit_byte (mb, CEE_LDARG_0);
2470                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
2471                 mono_mb_emit_byte (mb, CEE_PREFIX1);
2472                 mono_mb_emit_byte (mb, CEE_CPBLK);
2473         } else {
2474
2475                 /* allocate local 0 (pointer) src_ptr */
2476                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2477                 /* allocate local 1 (pointer) dst_ptr */
2478                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2479                 
2480                 /* initialize src_ptr to point to the start of object data */
2481                 mono_mb_emit_byte (mb, CEE_LDARG_0);
2482                 mono_mb_emit_byte (mb, CEE_STLOC_0);
2483
2484                 /* initialize dst_ptr */
2485                 mono_mb_emit_byte (mb, CEE_LDARG_1);
2486                 mono_mb_emit_icon (mb, sizeof (MonoObject));
2487                 mono_mb_emit_byte (mb, CEE_ADD);
2488                 mono_mb_emit_byte (mb, CEE_STLOC_1);
2489
2490                 emit_struct_conv (mb, klass, TRUE);
2491         }
2492
2493         mono_mb_emit_byte (mb, CEE_RET);
2494
2495         res = mono_mb_create_method (mb, ptostr->signature, 0);
2496         mono_mb_free (mb);
2497
2498         klass->ptr_to_str = res;
2499         return res;
2500 }
2501
2502 /* FIXME: on win32 we should probably use GlobalAlloc(). */
2503 void*
2504 mono_marshal_alloc (gpointer size) {
2505         return g_try_malloc ((gulong)size);
2506 }
2507
2508 void
2509 mono_marshal_free (gpointer ptr) {
2510         g_free (ptr);
2511 }
2512
2513 void
2514 mono_marshal_free_array (gpointer *ptr, int size) {
2515         int i;
2516
2517         for (i = 0; i < size; i++)
2518                 if (ptr [i])
2519                         g_free (ptr [i]);
2520 }
2521
2522 void *
2523 mono_marshal_realloc (gpointer ptr, gpointer size) {
2524         return g_try_realloc (ptr, (gulong)size);
2525 }
2526
2527 void *
2528 mono_marshal_string_array (MonoArray *array)
2529 {
2530         char **result;
2531         int i, len;
2532
2533         if (!array)
2534                 return NULL;
2535
2536         len = mono_array_length (array);
2537
2538         result = g_malloc (sizeof (char *) * (len + 1));
2539         for (i = 0; i < len; ++i) {
2540                 MonoString *s = (MonoString *)mono_array_get (array, gpointer, i);
2541                 result [i] = s ? mono_string_to_utf8 (s): NULL;
2542         }
2543         /* null terminate the array */
2544         result [i] = NULL;
2545
2546         return result;
2547 }
2548
2549 void
2550 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
2551                                                                     gpointer dest, gint32 length)
2552 {
2553         int element_size;
2554         void *source_addr;
2555
2556         MONO_CHECK_ARG_NULL (src);
2557         MONO_CHECK_ARG_NULL (dest);
2558
2559         g_assert (src->obj.vtable->klass->rank == 1);
2560         g_assert (start_index >= 0 && start_index < mono_array_length (src));
2561         g_assert (start_index + length <= mono_array_length (src));
2562
2563         element_size = mono_array_element_size (src->obj.vtable->klass);
2564           
2565         source_addr = mono_array_addr_with_size (src, element_size, start_index);
2566
2567         memcpy (dest, source_addr, length * element_size);
2568 }
2569
2570 void
2571 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
2572                                                                       MonoArray *dest, gint32 length)
2573 {
2574         int element_size;
2575         void *dest_addr;
2576
2577         MONO_CHECK_ARG_NULL (src);
2578         MONO_CHECK_ARG_NULL (dest);
2579
2580         g_assert (dest->obj.vtable->klass->rank == 1);
2581         g_assert (start_index >= 0 && start_index < mono_array_length (dest));
2582         g_assert (start_index + length <= mono_array_length (dest));
2583
2584         element_size = mono_array_element_size (dest->obj.vtable->klass);
2585           
2586         dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
2587
2588         memcpy (dest_addr, src, length * element_size);
2589 }
2590
2591 gpointer
2592 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
2593 {
2594         char *p = ptr;
2595         return *(gpointer*)(p + offset);
2596 }
2597
2598 unsigned char
2599 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
2600 {
2601         char *p = ptr;
2602         return *(unsigned char*)(p + offset);
2603 }
2604
2605 gint16
2606 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
2607 {
2608         char *p = ptr;
2609         return *(gint16*)(p + offset);
2610 }
2611
2612 gint32
2613 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
2614 {
2615         char *p = ptr;
2616         return *(gint32*)(p + offset);
2617 }
2618
2619 gint64
2620 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
2621 {
2622         char *p = ptr;
2623         return *(gint64*)(p + offset);
2624 }
2625
2626 void
2627 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
2628 {
2629         char *p = ptr;
2630         *(unsigned char*)(p + offset) = val;
2631 }
2632
2633 void
2634 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
2635 {
2636         char *p = ptr;
2637         *(gpointer*)(p + offset) = val;
2638 }
2639
2640 void
2641 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
2642 {
2643         char *p = ptr;
2644         *(gint16*)(p + offset) = val;
2645 }
2646
2647 void
2648 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
2649 {
2650         char *p = ptr;
2651         *(gint32*)(p + offset) = val;
2652 }
2653
2654 void
2655 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
2656 {
2657         char *p = ptr;
2658         *(gint64*)(p + offset) = val;
2659 }
2660
2661 MonoString *
2662 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
2663 {
2664         return mono_string_new (mono_domain_get (), ptr);
2665 }
2666
2667 MonoString *
2668 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
2669 {
2670         return mono_string_new_len (mono_domain_get (), ptr, len);
2671 }
2672
2673 MonoString *
2674 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
2675 {
2676         MonoDomain *domain = mono_domain_get (); 
2677         int len = 0;
2678         guint16 *t = ptr;
2679
2680         while (t++)
2681                 len++;
2682
2683         return mono_string_new_utf16 (domain, ptr, len);
2684 }
2685
2686 MonoString *
2687 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
2688 {
2689         MonoDomain *domain = mono_domain_get (); 
2690
2691         return mono_string_new_utf16 (domain, ptr, len);
2692 }
2693
2694 MonoString *
2695 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
2696 {
2697         g_warning ("PtrToStringBSTR not implemented");
2698         g_assert_not_reached ();
2699
2700         return NULL;
2701 }
2702
2703 guint32 
2704 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
2705 {
2706         return (GetLastError ());
2707 }
2708
2709 guint32 
2710 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
2711 {
2712         MonoClass *klass;
2713
2714         MONO_CHECK_ARG_NULL (rtype);
2715
2716         klass = mono_class_from_mono_type (rtype->type);
2717
2718         return mono_class_native_size (klass, NULL);
2719 }
2720
2721 void
2722 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
2723 {
2724         MonoMethod *method;
2725         gpointer pa [3];
2726
2727         MONO_CHECK_ARG_NULL (obj);
2728         MONO_CHECK_ARG_NULL (dst);
2729
2730         method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
2731
2732         pa [0] = obj;
2733         pa [1] = &dst;
2734         pa [2] = &delete_old;
2735
2736         mono_runtime_invoke (method, NULL, pa, NULL);
2737 }
2738
2739 void
2740 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
2741 {
2742         MonoMethod *method;
2743         gpointer pa [2];
2744
2745         MONO_CHECK_ARG_NULL (src);
2746         MONO_CHECK_ARG_NULL (dst);
2747
2748         method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
2749
2750         pa [0] = &src;
2751         pa [1] = dst;
2752
2753         mono_runtime_invoke (method, NULL, pa, NULL);
2754 }
2755
2756 MonoObject *
2757 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
2758 {
2759         MonoDomain *domain = mono_domain_get (); 
2760         MonoObject *res;
2761
2762         MONO_CHECK_ARG_NULL (src);
2763         MONO_CHECK_ARG_NULL (type);
2764
2765         res = mono_object_new (domain, mono_class_from_mono_type (type->type));
2766
2767         ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res);
2768
2769         return res;
2770 }
2771
2772 int
2773 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
2774 {
2775         MonoMarshalType *info;
2776         MonoClass *klass;
2777         char *fname;
2778         int i;
2779
2780         MONO_CHECK_ARG_NULL (type);
2781         MONO_CHECK_ARG_NULL (field_name);
2782
2783         fname = mono_string_to_utf8 (field_name);
2784         klass = mono_class_from_mono_type (type->type);
2785
2786         info = mono_marshal_load_type_info (klass);     
2787         
2788         for (i = 0; i < klass->field.count; ++i) {
2789                 if (*fname == *klass->fields [i].name && 
2790                     strcmp (fname, klass->fields [i].name) == 0)
2791                         break;
2792         }
2793         g_free (fname);
2794
2795         mono_assert (i < klass->field.count);
2796
2797         return info->fields [i].offset;
2798 }
2799
2800 gpointer
2801 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
2802 {
2803         return mono_string_to_utf8 (string);
2804 }
2805
2806 gpointer
2807 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
2808 {
2809         return g_memdup (mono_string_chars (string), mono_string_length (string)*2);
2810 }
2811
2812 static void
2813 mono_struct_delete_old (MonoClass *klass, char *ptr)
2814 {
2815         MonoMarshalType *info;
2816         int i;
2817
2818         info = mono_marshal_load_type_info (klass);
2819
2820         for (i = 0; i < info->num_fields; i++) {
2821                 MonoMarshalNative ntype;
2822                 MonoMarshalConv conv;
2823                 MonoType *ftype = info->fields [i].field->type;
2824                 char *cpos;
2825
2826                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
2827                         continue;
2828
2829                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, 
2830                                                 klass->unicode, &conv);
2831                         
2832                 cpos = ptr + info->fields [i].offset;
2833
2834                 switch (conv) {
2835                 case MONO_MARSHAL_CONV_NONE:
2836                         if (MONO_TYPE_ISSTRUCT (ftype)) {
2837                                 mono_struct_delete_old (ftype->data.klass, cpos);
2838                                 continue;
2839                         }
2840                         break;
2841                 case MONO_MARSHAL_CONV_STR_LPWSTR:
2842                 case MONO_MARSHAL_CONV_STR_LPSTR:
2843                 case MONO_MARSHAL_CONV_STR_LPTSTR:
2844                 case MONO_MARSHAL_CONV_STR_BSTR:
2845                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
2846                 case MONO_MARSHAL_CONV_STR_TBSTR:
2847                         g_free (*(gpointer *)cpos);
2848                         break;
2849                 default:
2850                         continue;
2851                 }
2852         }
2853 }
2854
2855 void
2856 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
2857 {
2858         MonoClass *klass;
2859
2860         MONO_CHECK_ARG_NULL (src);
2861         MONO_CHECK_ARG_NULL (type);
2862
2863         klass = mono_class_from_mono_type (type->type);
2864
2865         mono_struct_delete_old (klass, (char *)src);
2866 }
2867