2002-07-15 Dietmar Maurer <dietmar@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
20 //#define DEBUG_RUNTIME_CODE
21
22 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
23         a = i,
24
25 enum {
26 #include "mono/cil/opcode.def"
27         LAST = 0xff
28 };
29 #undef OPDEF
30
31 struct _MonoMethodBuilder {
32         MonoMethod *method;
33         GList *locals_list;
34         int locals;
35         guint32 code_size, pos;
36         unsigned char *code;
37 };
38
39 static char*
40 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
41 {
42         return g_strdup (" ");
43 }
44
45 static MonoDisHelper marshal_dh = {
46         "\n",
47         NULL,
48         "IL_%04x",
49         indenter, 
50         NULL,
51         NULL
52 };
53
54 gpointer
55 mono_delegate_to_ftnptr (MonoDelegate *delegate)
56 {
57         MonoMethod *method, *invoke, *wrapper;
58         MonoMethodSignature *sig;
59         MonoClass *klass;
60
61         if (!delegate)
62                 return NULL;
63
64         if (delegate->delegate_trampoline)
65                 return delegate->delegate_trampoline;
66
67         klass = ((MonoObject *)delegate)->vtable->klass;
68         g_assert (klass->delegate);
69         
70         method = delegate->method_info->method;
71         sig = method->signature;
72         
73         invoke = mono_get_delegate_invoke (klass);
74         wrapper = mono_marshal_get_managed_wrapper (invoke, (MonoObject *)delegate);
75
76         delegate->delegate_trampoline =  mono_compile_method (wrapper);
77
78         return delegate->delegate_trampoline;
79 }
80
81 gpointer
82 mono_array_to_savearray (MonoArray *array)
83 {
84         if (!array)
85                 return NULL;
86
87         g_assert_not_reached ();
88         return NULL;
89 }
90
91 gpointer
92 mono_array_to_lparray (MonoArray *array)
93 {
94         if (!array)
95                 return NULL;
96
97         g_assert_not_reached ();
98         return NULL;
99 }
100
101 gpointer
102 mono_string_to_ansibstr (MonoString *string_obj)
103 {
104         g_error ("implement me");
105         return NULL;
106 }
107
108 gpointer
109 mono_string_to_bstr (MonoString *string_obj)
110 {
111         g_error ("implement me");
112         return NULL;
113 }
114
115 void
116 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
117 {
118         char *s;
119         int len;
120
121         g_assert (dst != NULL);
122         g_assert (size > 0);
123
124         if (!src) {
125                 memset (dst, 0, size);
126                 return;
127         }
128
129         s = mono_string_to_utf8 (src);
130         len = MIN (size, strlen (s));
131         memcpy (dst, s, len);
132         g_free (s);
133
134         *((char *)dst + size - 1) = 0;
135 }
136
137 void
138 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
139 {
140         int len;
141
142         g_assert (dst != NULL);
143         g_assert (size > 1);
144
145         if (!src) {
146                 memset (dst, 0, size);
147                 return;
148         }
149
150         len = MIN (size, (mono_string_length (src) * 2));
151         memcpy (dst, mono_string_chars (src), len);
152
153         *((char *)dst + size - 1) = 0;
154         *((char *)dst + size - 2) = 0;
155 }
156
157
158 static MonoMethod *
159 mono_find_method_by_name (MonoClass *klass, const char *name, int param_count)
160 {
161         MonoMethod *res = NULL;
162         int i;
163
164         for (i = 0; i < klass->method.count; ++i) {
165                 if ((klass->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
166                     klass->methods [i]->name[0] == name [0] && 
167                     !strcmp (name, klass->methods [i]->name) &&
168                     klass->methods [i]->signature->param_count == param_count) {
169                         res = klass->methods [i];
170                         break;
171                 }
172         }
173         return res;
174 }
175
176 void
177 mono_mb_free (MonoMethodBuilder *mb)
178 {
179         g_list_free (mb->locals_list);
180         g_free (mb);
181 }
182
183 MonoMethodBuilder *
184 mono_mb_new (MonoClass *klass, const char *name)
185 {
186         MonoMethodBuilder *mb;
187         MonoMethod *m;
188
189         g_assert (klass != NULL);
190         g_assert (name != NULL);
191
192         mb = g_new0 (MonoMethodBuilder, 1);
193
194         mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
195
196         m->klass = klass;
197         m->name = g_strdup (name);
198         m->inline_info = 1;
199         m->inline_count = -1;
200         m->wrapper_type = MONO_WRAPPER_UNKNOWN;
201
202         mb->code_size = 256;
203         mb->code = g_malloc (mb->code_size);
204         
205         return mb;
206 }
207
208 int
209 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
210 {
211         int res = mb->locals;
212
213         g_assert (mb != NULL);
214         g_assert (type != NULL);
215
216         mb->locals_list = g_list_append (mb->locals_list, type);
217         mb->locals++;
218
219         return res;
220 }
221
222 MonoMethod *
223 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
224 {
225         MonoMethodHeader *header;
226         GList *l;
227         int i;
228
229         g_assert (mb != NULL);
230
231         ((MonoMethodNormal *)mb->method)->header = header = (MonoMethodHeader *) 
232                 g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
233
234         if (max_stack < 8)
235                 max_stack = 8;
236
237         header->max_stack = max_stack;
238
239         for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
240                 header->locals [i] = (MonoType *)l->data;
241         }
242
243         mb->method->signature = signature;
244         header->code = mb->code;
245         header->code_size = mb->pos;
246         header->num_locals = mb->locals;
247
248 #ifdef DEBUG_RUNTIME_CODE
249         printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (mb->method, TRUE));
250         printf ("%s\n", mono_disasm_code (&marshal_dh, mb->method, mb->code, mb->code + mb->pos));
251 #endif
252
253         return mb->method;
254 }
255
256 guint32
257 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
258 {
259         MonoMethodWrapper *mw;
260
261         g_assert (mb != NULL);
262
263         mw = (MonoMethodWrapper *)mb->method;
264
265         mw->data = g_list_append (mw->data, data);
266
267         return g_list_length (mw->data);
268 }
269
270 void
271 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
272 {
273         *((gint32 *)(&mb->code [pos])) = value;
274 }
275
276 void
277 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
278 {
279         if (mb->pos >= mb->code_size) {
280                 mb->code_size += 64;
281                 mb->code = g_realloc (mb->code, mb->code_size);
282         }
283
284         mb->code [mb->pos++] = op;
285 }
286
287 void
288 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
289 {
290         if ((mb->pos + 4) >= mb->code_size) {
291                 mb->code_size += 64;
292                 mb->code = g_realloc (mb->code, mb->code_size);
293         }
294
295         *((gint32 *)(&mb->code [mb->pos])) = data;
296         mb->pos += 4;
297 }
298
299 void
300 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
301 {
302         if ((mb->pos + 2) >= mb->code_size) {
303                 mb->code_size += 64;
304                 mb->code = g_realloc (mb->code, mb->code_size);
305         }
306
307         *((gint16 *)(&mb->code [mb->pos])) = data;
308         mb->pos += 2;
309 }
310
311 void
312 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
313 {
314         if (argnum < 4) {
315                 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
316         } else if (argnum < 256) {
317                 mono_mb_emit_byte (mb, CEE_LDARG_S);
318                 mono_mb_emit_byte (mb, argnum);
319         } else {
320                 mono_mb_emit_byte (mb, CEE_PREFIX1);
321                 mono_mb_emit_byte (mb, CEE_LDARG);
322                 mono_mb_emit_i4 (mb, argnum);
323         }
324 }
325
326 void
327 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
328 {
329         if (argnum < 256) {
330                 mono_mb_emit_byte (mb, CEE_LDARGA_S);
331                 mono_mb_emit_byte (mb, argnum);
332         } else {
333                 mono_mb_emit_byte (mb, CEE_PREFIX1);
334                 mono_mb_emit_byte (mb, CEE_LDARGA);
335                 mono_mb_emit_i4 (mb, argnum);
336         }
337 }
338
339 void
340 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
341 {
342         if (num < 4) {
343                 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
344         } else if (num < 256) {
345                 mono_mb_emit_byte (mb, CEE_LDLOC_S);
346                 mono_mb_emit_byte (mb, num);
347         } else {
348                 mono_mb_emit_byte (mb, CEE_PREFIX1);
349                 mono_mb_emit_byte (mb, CEE_LDLOC);
350                 mono_mb_emit_i4 (mb, num);
351         }
352 }
353
354 void
355 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
356 {
357         if (num < 4) {
358                 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
359         } else if (num < 256) {
360                 mono_mb_emit_byte (mb, CEE_STLOC_S);
361                 mono_mb_emit_byte (mb, num);
362         } else {
363                 mono_mb_emit_byte (mb, CEE_PREFIX1);
364                 mono_mb_emit_byte (mb, CEE_STLOC);
365                 mono_mb_emit_i4 (mb, num);
366         }
367 }
368
369 void
370 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
371 {
372         if (value >= -1 && value < 8) {
373                 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
374         } else if (value >= -128 && value <= 127) {
375                 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
376                 mono_mb_emit_byte (mb, value);
377         } else {
378                 mono_mb_emit_byte (mb, CEE_LDC_I4);
379                 mono_mb_emit_i4 (mb, value);
380         }
381 }
382
383 void
384 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
385 {
386         if (!opt_sig)
387                 opt_sig = method->signature;
388         mono_mb_emit_byte (mb, CEE_PREFIX1);
389         mono_mb_emit_byte (mb, CEE_LDFTN);
390         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
391         mono_mb_emit_byte (mb, CEE_CALLI);
392         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, opt_sig));
393 }
394
395 void
396 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
397 {
398         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
399         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
400         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func));
401         mono_mb_emit_byte (mb, CEE_CALLI);
402         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
403 }
404
405 void
406 mono_mb_emit_exception (MonoMethodBuilder *mb)
407 {
408         mono_mb_emit_byte (mb, CEE_LDNULL);
409         mono_mb_emit_byte (mb, CEE_THROW);
410         
411 }
412
413 void
414 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
415 {
416         mono_mb_emit_ldloc (mb, local); 
417         mono_mb_emit_icon (mb, incr);
418         mono_mb_emit_byte (mb, CEE_ADD);
419         mono_mb_emit_stloc (mb, local); 
420 }
421
422 static void
423 emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
424 {
425         /* fixme: dont know what do do here - docs say 
426            this does not work for value types  */
427
428         g_warning ("not implemented");
429         g_assert_not_reached ();
430 }
431
432 static void
433 emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
434 {
435         switch (conv) {
436         case MONO_MARSHAL_CONV_BOOL_I4:
437                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
438                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
439                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
440                 mono_mb_emit_byte (mb, CEE_STIND_I4);
441                 break;
442         case MONO_MARSHAL_CONV_STR_LPWSTR:
443         case MONO_MARSHAL_CONV_STR_LPSTR:
444         case MONO_MARSHAL_CONV_STR_LPTSTR:
445         case MONO_MARSHAL_CONV_STR_BSTR:
446         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
447         case MONO_MARSHAL_CONV_STR_TBSTR:
448         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
449         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
450                 /* free space if ARG_2 == true */
451                 mono_mb_emit_byte (mb, CEE_LDARG_2);
452                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
453                 mono_mb_emit_byte (mb, 4);
454                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
455                 mono_mb_emit_byte (mb, CEE_LDIND_I);
456                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
457                 mono_mb_emit_byte (mb, CEE_MONO_FREE);
458                 
459                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
460                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
461                 mono_mb_emit_byte (mb, CEE_LDIND_I);
462                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
463                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
464                 mono_mb_emit_byte (mb, conv);
465                 mono_mb_emit_byte (mb, CEE_STIND_I);
466                 break;
467         case MONO_MARSHAL_CONV_STR_BYVALSTR: 
468         case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
469                 if (!usize)
470                         break;
471
472                 mono_mb_emit_byte (mb, CEE_LDLOC_1); /* dst */
473                 mono_mb_emit_byte (mb, CEE_LDLOC_0);    
474                 mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */
475                 mono_mb_emit_icon (mb, usize);
476                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
477                 mono_mb_emit_byte (mb, CEE_MONO_PROC3);
478                 mono_mb_emit_byte (mb, conv);
479                 break;
480         }
481         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
482                 if (!usize) 
483                         break;
484
485                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
486                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
487                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
488                 mono_mb_emit_byte (mb, 15);
489
490                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
491                 mono_mb_emit_byte (mb, CEE_LDLOC_0);    
492                 mono_mb_emit_byte (mb, CEE_LDIND_I);    
493                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
494                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
495                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
496                 mono_mb_emit_byte (mb, CEE_ADD);
497                 mono_mb_emit_icon (mb, usize);
498                 mono_mb_emit_byte (mb, CEE_PREFIX1);
499                 mono_mb_emit_byte (mb, CEE_CPBLK);                      
500                 break;
501         }
502         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
503         default:
504                 g_error ("marshalling conversion %d not implemented", conv);
505         }
506 }
507
508 static void
509 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
510 {
511         MonoMarshalType *info;
512         int i;
513
514         info = mono_marshal_load_type_info (klass);
515
516         for (i = 0; i < info->num_fields; i++) {
517                 MonoMarshalNative ntype;
518                 MonoMarshalConv conv;
519                 MonoType *ftype = info->fields [i].field->type;
520                 int msize = 0;
521                 int usize = 0;
522                 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
523
524                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
525                         continue;
526
527                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
528                         
529                 if (last_field) {
530                         msize = klass->instance_size - info->fields [i].field->offset;
531                         usize = info->native_size - info->fields [i].offset;
532                 } else {
533                         msize = klass->fields [i + 1].offset - info->fields [i].field->offset;
534                         usize = info->fields [i + 1].offset - info->fields [i].offset;
535                 }
536                 g_assert (msize > 0 && usize > 0);
537
538                 switch (conv) {
539                 case MONO_MARSHAL_CONV_NONE:
540
541                         if (ftype->byref || ftype->type == MONO_TYPE_I ||
542                             ftype->type == MONO_TYPE_U) {
543                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
544                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
545                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
546                                 mono_mb_emit_byte (mb, CEE_STIND_I);
547                                 break;
548                         }
549
550                         switch (ftype->type) {
551                         case MONO_TYPE_I4:
552                         case MONO_TYPE_U4:
553                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
554                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
555                                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
556                                 mono_mb_emit_byte (mb, CEE_STIND_I4);
557                                 break;
558                         case MONO_TYPE_I1:
559                         case MONO_TYPE_U1:
560                         case MONO_TYPE_BOOLEAN:
561                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
562                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
563                                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
564                                 mono_mb_emit_byte (mb, CEE_STIND_I1);
565                                 break;
566                         case MONO_TYPE_I2:
567                         case MONO_TYPE_U2:
568                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
569                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
570                                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
571                                 mono_mb_emit_byte (mb, CEE_STIND_I2);
572                                 break;
573                         case MONO_TYPE_I8:
574                         case MONO_TYPE_U8:
575                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
576                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
577                                 mono_mb_emit_byte (mb, CEE_LDIND_I8);
578                                 mono_mb_emit_byte (mb, CEE_STIND_I8);
579                                 break;
580                         case MONO_TYPE_R4:
581                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
582                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
583                                 mono_mb_emit_byte (mb, CEE_LDIND_R4);
584                                 mono_mb_emit_byte (mb, CEE_STIND_R4);
585                                 break;
586                         case MONO_TYPE_R8:
587                                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
588                                 mono_mb_emit_byte (mb, CEE_LDLOC_0);
589                                 mono_mb_emit_byte (mb, CEE_LDIND_R8);
590                                 mono_mb_emit_byte (mb, CEE_STIND_R8);
591                                 break;
592                         case MONO_TYPE_VALUETYPE:
593                                 emit_struct_conv (mb, ftype->data.klass, to_object);
594                                 break;
595                         default:
596                                 g_error ("marshalling type %02x not implemented", ftype->type);
597                         }
598                         break;
599
600                 default:
601                         if (to_object) 
602                                 emit_ptr_to_str_conv (mb, conv, usize, msize);
603                         else
604                                 emit_str_to_ptr_conv (mb, conv, usize, msize);  
605                 }
606
607                 if (!last_field) {
608                         mono_mb_emit_add_to_local (mb, 0, msize);
609                         mono_mb_emit_add_to_local (mb, 1, usize);
610                 }               
611         }
612 }
613
614 static MonoObject *
615 delegate_test (MonoDelegate *delegate, gpointer *params)
616 {
617         g_assert_not_reached ();
618         return NULL;
619 }
620
621 MonoMethod *
622 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
623 {
624         MonoMethodSignature *sig;
625         static MonoMethodSignature *csig = NULL;
626         MonoMethodBuilder *mb;
627         MonoMethod *res;
628         MonoType *ret_type;
629         GHashTable *cache;
630         int i;
631
632         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
633                   !strcmp (method->name, "BeginInvoke"));
634
635         sig = method->signature;
636
637         cache = method->klass->image->delegate_begin_invoke_cache;
638         if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
639                 return res;
640
641         if (sig->ret->byref)
642                 ret_type = &mono_defaults.int_class->byval_arg;
643         else if (sig->ret->type == MONO_TYPE_VALUETYPE && sig->ret->data.klass->enumtype)
644                 ret_type = sig->ret->data.klass->enum_basetype;
645         else 
646                 ret_type = sig->ret;
647
648         if (!csig) {
649                 int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
650                 csig = g_malloc0 (sigsize);
651
652                 /* MonoObject *begin_invoke (MonoDelegate *delegate, gpointer params[]) */
653                 csig->param_count = 2;
654                 csig->ret = &mono_defaults.object_class->byval_arg;
655                 csig->params [0] = &mono_defaults.object_class->byval_arg;
656                 csig->params [1] = &mono_defaults.int_class->byval_arg;
657         }
658
659         mb = mono_mb_new (method->klass, method->name);
660         mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_BEGIN_INVOKE;
661
662         /* allocate local 0 (pointer) *params[] */
663         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
664         /* allocate local 1 (pointer) tmo */
665         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
666
667         /* alloate space on stack to store an array of pointers to the arguments */
668         mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
669         mono_mb_emit_byte (mb, CEE_PREFIX1);
670         mono_mb_emit_byte (mb, CEE_LOCALLOC);
671         mono_mb_emit_byte (mb, CEE_STLOC_0);
672
673         /* tmp = params */
674         mono_mb_emit_byte (mb, CEE_LDLOC_0);
675         mono_mb_emit_byte (mb, CEE_STLOC_1);
676
677         for (i = 0; i < sig->param_count; i++) {
678
679                 mono_mb_emit_byte (mb, CEE_LDLOC_1);
680                 mono_mb_emit_ldarg_addr (mb, i);
681                 mono_mb_emit_byte (mb, CEE_STIND_I);
682                 /* tmp = tmp + sizeof (gpointer) */
683                 if (i < (sig->param_count - 1))
684                         mono_mb_emit_add_to_local (mb, 1, sizeof (gpointer));
685         }
686
687         mono_mb_emit_ldarg (mb, 0);
688         mono_mb_emit_byte (mb, CEE_LDLOC_0);
689         mono_mb_emit_native_call (mb, csig, delegate_test);
690
691         /* unbox the result if necessary */
692
693         switch (ret_type->type) {
694         case MONO_TYPE_STRING:
695         case MONO_TYPE_CLASS: 
696         case MONO_TYPE_OBJECT: 
697         case MONO_TYPE_ARRAY: 
698         case MONO_TYPE_SZARRAY: 
699         case MONO_TYPE_VOID:
700                 /* nothing to do */
701                 break;
702         case MONO_TYPE_U1:
703         case MONO_TYPE_I1:
704         case MONO_TYPE_BOOLEAN:
705         case MONO_TYPE_U2:
706         case MONO_TYPE_I2:
707         case MONO_TYPE_CHAR:
708         case MONO_TYPE_U:
709         case MONO_TYPE_I:
710         case MONO_TYPE_U4:
711         case MONO_TYPE_I4:
712         case MONO_TYPE_U8:
713         case MONO_TYPE_I8:
714         case MONO_TYPE_R4:
715         case MONO_TYPE_R8:
716         case MONO_TYPE_VALUETYPE:
717                 mono_mb_emit_byte (mb, CEE_UNBOX);
718                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (ret_type)));
719                 break;
720         default:
721                 g_warning ("type 0x%x not handled", ret_type->type);
722                 g_assert_not_reached ();
723         }
724
725         mono_mb_emit_byte (mb, CEE_RET);
726
727         res = mono_mb_create_method (mb, sig, 0);
728         mono_mb_free (mb);
729         g_hash_table_insert (cache, sig, res);
730         return res;
731 }
732
733 /*
734  * the returned method invokes all methods in a multicast delegate 
735  */
736 MonoMethod *
737 mono_marshal_get_delegate_invoke (MonoMethod *method)
738 {
739         MonoMethodSignature *sig, *static_sig;
740         int i, sigsize;
741         MonoMethodBuilder *mb;
742         MonoMethod *res;
743         GHashTable *cache;
744         int pos [3];
745
746         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
747                   !strcmp (method->name, "Invoke"));
748                 
749         sig = method->signature;
750
751         cache = method->klass->image->delegate_invoke_cache;
752         if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
753                 return res;
754
755         sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
756         static_sig = g_memdup (sig, sigsize);
757         static_sig->hasthis = 0;
758
759         mb = mono_mb_new (method->klass, method->name);
760         mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_INVOKE;
761
762         /* allocate local 0 (object) prev */
763         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
764         /* allocate local 1 (object) target */
765         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
766         /* allocate local 2 (pointer) mptr */
767         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
768
769         /* allocate local 3 to store the return value */
770         if (sig->ret->type != MONO_TYPE_VOID)
771                 mono_mb_add_local (mb, sig->ret);
772
773         g_assert (sig->hasthis);
774
775         /* prev = addr of delegate */
776         mono_mb_emit_ldarg (mb, 0);
777         mono_mb_emit_stloc (mb, 0);
778
779         /* loop */
780         pos [0] = mb->pos;
781         /* target = delegate->target */
782         mono_mb_emit_ldloc (mb, 0);
783         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
784         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
785         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, target));
786         mono_mb_emit_byte (mb, CEE_ADD);
787         mono_mb_emit_byte (mb, CEE_LDIND_I);
788         mono_mb_emit_stloc (mb, 1);
789
790         /* mptr = delegate->method_ptr */
791         mono_mb_emit_ldloc (mb, 0);
792         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
793         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
794         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
795         mono_mb_emit_byte (mb, CEE_ADD);
796         mono_mb_emit_byte (mb, CEE_LDIND_I);
797         mono_mb_emit_stloc (mb, 2);
798
799         /* target == null ? */
800         mono_mb_emit_ldloc (mb, 1);
801         mono_mb_emit_byte (mb, CEE_BRTRUE); 
802         pos [1] = mb->pos;
803         mono_mb_emit_i4 (mb, 0);
804
805         /* emit static method call */
806
807         for (i = 0; i < sig->param_count; i++)
808                 mono_mb_emit_ldarg (mb, i + 1);
809
810         mono_mb_emit_ldloc (mb, 2);
811         mono_mb_emit_byte (mb, CEE_CALLI);
812         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
813
814         if (sig->ret->type != MONO_TYPE_VOID)
815                 mono_mb_emit_stloc (mb, 3);
816
817         mono_mb_emit_byte (mb, CEE_BR);
818         pos [2] = mb->pos;
819         mono_mb_emit_i4 (mb, 0);
820    
821         /* target != null, emit non static method call */
822
823         mono_mb_patch_addr (mb, pos [1], mb->pos - (pos [1] + 4));
824         mono_mb_emit_ldloc (mb, 1);
825
826         for (i = 0; i < sig->param_count; i++)
827                 mono_mb_emit_ldarg (mb, i + 1);
828         
829         mono_mb_emit_ldloc (mb, 2);
830         mono_mb_emit_byte (mb, CEE_CALLI);
831         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
832
833         if (sig->ret->type != MONO_TYPE_VOID)
834                 mono_mb_emit_stloc (mb, 3);
835
836         mono_mb_patch_addr (mb, pos [2], mb->pos - (pos [2] + 4));
837
838         /* prev = delegate->prev */
839         mono_mb_emit_ldloc (mb, 0);
840         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
841         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
842         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
843         mono_mb_emit_byte (mb, CEE_ADD);
844         mono_mb_emit_byte (mb, CEE_LDIND_I);
845         mono_mb_emit_stloc (mb, 0);
846
847         /* if prev != null goto loop */
848         mono_mb_emit_ldloc (mb, 0);
849         mono_mb_emit_byte (mb, CEE_BRTRUE);
850         mono_mb_emit_i4 (mb, pos [0] - (mb->pos + 4));
851
852         if (sig->ret->type != MONO_TYPE_VOID)
853                 mono_mb_emit_ldloc (mb, 3);
854
855         mono_mb_emit_byte (mb, CEE_RET);
856
857         res = mono_mb_create_method (mb, sig, 0);
858         mono_mb_free (mb);
859
860         g_hash_table_insert (cache, sig, res);
861
862         return res;     
863 }
864
865 /*
866  * generates IL code for the runtime invoke function 
867  * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc)
868  *
869  * we also catch exceptions if exc != null
870  */
871 MonoMethod *
872 mono_marshal_get_runtime_invoke (MonoMethod *method)
873 {
874         MonoMethodSignature *sig, *csig;
875         MonoExceptionClause *clause;
876         MonoMethodHeader *header;
877         MonoMethodBuilder *mb;
878         MonoMethod *res;
879         GHashTable *cache;
880         static MonoString *string_dummy = NULL;
881         int i, pos, sigsize;
882
883         g_assert (method);
884
885         cache = method->klass->image->runtime_invoke_cache;
886         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
887                 return res;
888         
889         /* to make it work with our special string constructors */
890         if (!string_dummy)
891                 string_dummy = mono_string_new_wrapper ("dummy");
892
893         sig = method->signature;
894
895         sigsize = sizeof (MonoMethodSignature) + 3 * sizeof (MonoType *);
896         csig = g_malloc0 (sigsize);
897
898         csig->param_count = 3;
899         csig->ret = &mono_defaults.object_class->byval_arg;
900         csig->params [0] = &mono_defaults.object_class->byval_arg;
901         csig->params [1] = &mono_defaults.int_class->byval_arg;
902         csig->params [2] = &mono_defaults.int_class->byval_arg;
903
904         mb = mono_mb_new (method->klass, method->name);
905         mb->method->wrapper_type = MONO_WRAPPER_RUNTIME_INVOKE;
906
907         /* allocate local 0 (object) tmp */
908         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
909         /* allocate local 1 (object) exc */
910         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
911
912         /* cond set *exc to null */
913         mono_mb_emit_byte (mb, CEE_LDARG_2);
914         mono_mb_emit_byte (mb, CEE_BRFALSE_S);
915         mono_mb_emit_byte (mb, 3);      
916         mono_mb_emit_byte (mb, CEE_LDARG_2);
917         mono_mb_emit_byte (mb, CEE_LDNULL);
918         mono_mb_emit_byte (mb, CEE_STIND_I);
919
920         if (sig->hasthis) {
921                 if (method->string_ctor) {
922                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
923                         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
924                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
925                 } else {
926                         mono_mb_emit_ldarg (mb, 0);
927                 }
928         }
929
930         for (i = 0; i < sig->param_count; i++) {
931                 MonoType *t = sig->params [i];
932                 int type;
933
934                 mono_mb_emit_ldarg (mb, 1);
935                 if (i) {
936                         mono_mb_emit_icon (mb, sizeof (gpointer) * i);
937                         mono_mb_emit_byte (mb, CEE_ADD);
938                 }
939                 mono_mb_emit_byte (mb, CEE_LDIND_I);
940
941                 if (t->byref)
942                         continue;
943
944                 type = sig->params [i]->type;
945 handle_enum:
946                 switch (type) {
947                 case MONO_TYPE_I1:
948                         mono_mb_emit_byte (mb, CEE_LDIND_I1);
949                         break;
950                 case MONO_TYPE_BOOLEAN:
951                 case MONO_TYPE_U1:
952                         mono_mb_emit_byte (mb, CEE_LDIND_U1);
953                         break;
954                 case MONO_TYPE_I2:
955                         mono_mb_emit_byte (mb, CEE_LDIND_I2);
956                         break;
957                 case MONO_TYPE_U2:
958                 case MONO_TYPE_CHAR:
959                         mono_mb_emit_byte (mb, CEE_LDIND_U2);
960                         break;
961 #if SIZEOF_VOID_P == 4
962                 case MONO_TYPE_I:
963 #endif
964                 case MONO_TYPE_I4:
965                         mono_mb_emit_byte (mb, CEE_LDIND_I4);
966                         break;
967 #if SIZEOF_VOID_P == 4
968                 case MONO_TYPE_U:
969 #endif
970                 case MONO_TYPE_U4:
971                         mono_mb_emit_byte (mb, CEE_LDIND_U4);
972                         break;
973                 case MONO_TYPE_R4:
974                         mono_mb_emit_byte (mb, CEE_LDIND_R4);
975                         break;
976                 case MONO_TYPE_R8:
977                         mono_mb_emit_byte (mb, CEE_LDIND_R8);
978                         break;
979 #if SIZEOF_VOID_P == 8
980                 case MONO_TYPE_I:
981                 case MONO_TYPE_U:
982 #endif
983                 case MONO_TYPE_I8:
984                 case MONO_TYPE_U8:
985                         mono_mb_emit_byte (mb, CEE_LDIND_I8);
986                         break;
987                 case MONO_TYPE_STRING:
988                 case MONO_TYPE_CLASS:  
989                 case MONO_TYPE_ARRAY:
990                 case MONO_TYPE_PTR:
991                 case MONO_TYPE_SZARRAY:
992                 case MONO_TYPE_OBJECT:
993                         /* do nothing */
994                         break;
995                 case MONO_TYPE_VALUETYPE:
996                         if (t->data.klass->enumtype) {
997                                 type = t->data.klass->enum_basetype->type;
998                                 goto handle_enum;
999                         }
1000                         g_assert_not_reached ();
1001                         break;
1002                 default:
1003                         g_assert_not_reached ();
1004                 }               
1005         }
1006
1007         if (method->string_ctor) {
1008                 MonoMethodSignature *strsig;
1009
1010                 sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1011                 strsig = g_memdup (sig, sigsize);
1012                 strsig->ret = &mono_defaults.string_class->byval_arg;
1013
1014                 mono_mb_emit_managed_call (mb, method, strsig);         
1015         } else 
1016                 mono_mb_emit_managed_call (mb, method, NULL);
1017
1018         switch (sig->ret->type) {
1019         case MONO_TYPE_VOID:
1020                 if (!method->string_ctor)
1021                         mono_mb_emit_byte (mb, CEE_LDNULL);
1022                 break;
1023         case MONO_TYPE_I1:
1024         case MONO_TYPE_U1:
1025         case MONO_TYPE_I2:
1026         case MONO_TYPE_U2:
1027         case MONO_TYPE_I4:
1028         case MONO_TYPE_U4:
1029         case MONO_TYPE_I:
1030         case MONO_TYPE_U:
1031         case MONO_TYPE_R4:
1032         case MONO_TYPE_R8:
1033         case MONO_TYPE_I8:
1034         case MONO_TYPE_U8:
1035         case MONO_TYPE_VALUETYPE:
1036                 /* box value types */
1037                 mono_mb_emit_byte (mb, CEE_BOX);
1038                 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret)));
1039                 break;
1040         case MONO_TYPE_STRING:
1041         case MONO_TYPE_CLASS:  
1042         case MONO_TYPE_ARRAY:
1043         case MONO_TYPE_SZARRAY:
1044         case MONO_TYPE_OBJECT:
1045                 /* nothing to do */
1046                 break;
1047         case MONO_TYPE_PTR:
1048         default:
1049                 g_assert_not_reached ();
1050         }
1051
1052         mono_mb_emit_stloc (mb, 0);
1053                 
1054         mono_mb_emit_byte (mb, CEE_LEAVE);
1055         pos = mb->pos;
1056         mono_mb_emit_i4 (mb, 0);
1057
1058         /* fixme: use a filter clause and only catch exceptions
1059          * when exc != null. With RETHROW we get wrong stack 
1060          * traces. */
1061         clause = g_new0 (MonoExceptionClause, 1);
1062         clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
1063         clause->try_offset = 0;
1064         clause->try_len = mb->pos;
1065         clause->handler_offset = mb->pos;
1066
1067         /* handler code */
1068
1069         /* store exception */
1070         mono_mb_emit_stloc (mb, 1);
1071         
1072         mono_mb_emit_byte (mb, CEE_LDARG_2);
1073         mono_mb_emit_byte (mb, CEE_BRTRUE_S);
1074         mono_mb_emit_byte (mb, 2);
1075         mono_mb_emit_byte (mb, CEE_PREFIX1);
1076         mono_mb_emit_byte (mb, CEE_RETHROW);
1077         
1078         mono_mb_emit_byte (mb, CEE_LDARG_2);
1079         mono_mb_emit_ldloc (mb, 1);
1080         mono_mb_emit_byte (mb, CEE_STIND_I);
1081
1082         mono_mb_emit_byte (mb, CEE_LEAVE);
1083         mono_mb_emit_i4 (mb, 0);
1084
1085         clause->handler_len = mb->pos - clause->handler_offset;
1086
1087         /* return result */
1088         mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
1089         mono_mb_emit_ldloc (mb, 0);
1090         mono_mb_emit_byte (mb, CEE_RET);
1091         
1092         res = mono_mb_create_method (mb, csig, 0);
1093         mono_mb_free (mb);
1094
1095         header = ((MonoMethodNormal *)res)->header;
1096         header->num_clauses = 1;
1097         header->clauses = clause;
1098
1099         g_hash_table_insert (cache, method, res);
1100
1101         return res;     
1102 }
1103
1104 /*
1105  * generates IL code to call managed methods from unmanaged code 
1106  */
1107 MonoMethod *
1108 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
1109 {
1110         MonoMethodSignature *sig, *csig;
1111         MonoMethodBuilder *mb;
1112         MonoMethod *res;
1113         GHashTable *cache;
1114         int i, sigsize;
1115
1116         g_assert (method != NULL);
1117
1118         cache = method->klass->image->managed_wrapper_cache;
1119         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
1120                 return res;
1121
1122         sig = method->signature;
1123
1124         mb = mono_mb_new (method->klass, method->name);
1125         mb->method->wrapper_type = MONO_WRAPPER_NATIVE_TO_MANAGED;
1126
1127         /* we copy the signature, so that we can modify it */
1128         sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1129         csig = g_memdup (sig, sigsize);
1130         csig->hasthis = 0;
1131
1132         /* fixme: howto handle this ? */
1133         if (sig->hasthis) {
1134
1135                 if (this) {
1136                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1137                         mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
1138                         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, this));
1139
1140
1141                 } else {
1142                         /* fixme: */
1143                         g_assert_not_reached ();
1144                 }
1145         } 
1146
1147         for (i = 0; i < sig->param_count; i++) {
1148                 MonoType *t = sig->params [i];
1149                 
1150                 switch (t->type) {
1151                 case MONO_TYPE_I1:
1152                 case MONO_TYPE_U1:
1153                 case MONO_TYPE_I2:
1154                 case MONO_TYPE_U2:
1155                 case MONO_TYPE_I4:
1156                 case MONO_TYPE_U4:
1157                 case MONO_TYPE_I:
1158                 case MONO_TYPE_U:
1159                 case MONO_TYPE_PTR:
1160                 case MONO_TYPE_R4:
1161                 case MONO_TYPE_R8:
1162                 case MONO_TYPE_I8:
1163                 case MONO_TYPE_U8:
1164                         mono_mb_emit_ldarg (mb, i);
1165                         break;
1166                 case MONO_TYPE_STRING:
1167                         csig->params [i] = &mono_defaults.int_class->byval_arg;
1168                         mono_mb_emit_ldarg (mb, i);
1169                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1170                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
1171                         mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
1172                         break;  
1173                 case MONO_TYPE_CLASS:  
1174                 case MONO_TYPE_ARRAY:
1175                 case MONO_TYPE_SZARRAY:
1176                 case MONO_TYPE_OBJECT:
1177                         /* fixme: conversions ? */
1178                         mono_mb_emit_ldarg (mb, i);
1179                         break;
1180                 default:
1181                         g_warning ("type 0x%02x unknown", t->type);     
1182                         g_assert_not_reached ();
1183                 }
1184         }
1185
1186         mono_mb_emit_managed_call (mb, method, NULL);
1187         
1188         /* fixme: add return type conversions */
1189
1190         mono_mb_emit_byte (mb, CEE_RET);
1191
1192         res = mono_mb_create_method (mb, csig, 0);
1193         mono_mb_free (mb);
1194
1195         g_hash_table_insert (cache, method, res);
1196
1197         return res;
1198 }
1199
1200 /*
1201  * generates IL code for the pinvoke wrapper (the generated method
1202  * call the unamnage code in method->addr)
1203  */
1204 MonoMethod *
1205 mono_marshal_get_native_wrapper (MonoMethod *method)
1206 {
1207         MonoMethodSignature *sig, *csig;
1208         MonoMethodBuilder *mb;
1209         MonoMethod *res;
1210         GHashTable *cache;
1211         MonoClass *klass;
1212         gboolean pinvoke = FALSE;
1213         int i, argnum, *tmp_locals;
1214         int type, sigsize;
1215
1216         g_assert (method != NULL);
1217
1218         cache = method->klass->image->native_wrapper_cache;
1219         if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
1220                 return res;
1221
1222         sig = method->signature;
1223
1224         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
1225             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
1226                 pinvoke = TRUE;
1227
1228         mb = mono_mb_new (method->klass, method->name);
1229         mb->method->wrapper_type = MONO_WRAPPER_MANAGED_TO_NATIVE;
1230
1231         mb->method->save_lmf = 1;
1232
1233         if (pinvoke && !method->addr)
1234                 mono_lookup_pinvoke_call (method);
1235
1236         if (!method->addr) {
1237                 mono_mb_emit_exception (mb);
1238                 res = mono_mb_create_method (mb, sig, 0);
1239                 mono_mb_free (mb);
1240                 g_hash_table_insert (cache, method, res);
1241                 return res;
1242         }
1243
1244         /* we copy the signature, so that we can modify it */
1245         sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
1246         csig = g_memdup (sig, sigsize);
1247
1248         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
1249
1250                 if (method->string_ctor)
1251                         csig->ret = &mono_defaults.string_class->byval_arg;
1252
1253                 if (sig->hasthis)
1254                         mono_mb_emit_byte (mb, CEE_LDARG_0);
1255
1256                 for (i = 0; i < sig->param_count; i++)
1257                         mono_mb_emit_ldarg (mb, i + sig->hasthis);
1258
1259                 g_assert (method->addr);
1260                 mono_mb_emit_native_call (mb, csig, method->addr);
1261
1262                 mono_mb_emit_byte (mb, CEE_RET);
1263
1264                 res = mono_mb_create_method (mb, csig, 0);
1265                 mono_mb_free (mb);
1266                 g_hash_table_insert (cache, method, res);
1267                 return res;
1268         }
1269
1270         g_assert (pinvoke);
1271
1272         /* we allocate local for use with emit_struct_conv() */
1273         /* allocate local 0 (pointer) src_ptr */
1274         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1275         /* allocate local 1 (pointer) dst_ptr */
1276         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1277         /* allocate local 2 (pointer) as tmp/scratch storage */
1278         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1279
1280         if (sig->ret->type != MONO_TYPE_VOID) {
1281                 /* allocate local 3 to store the return value */
1282                 mono_mb_add_local (mb, sig->ret);
1283         }
1284
1285         /* we first do all conversions */
1286         tmp_locals = alloca (sizeof (int) * sig->param_count);
1287         for (i = 0; i < sig->param_count; i ++) {
1288                 MonoType *t = sig->params [i];
1289
1290                 argnum = i + sig->hasthis;
1291
1292                 /* allocate one tmp/scratch storage for each parameter */
1293                 tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1294
1295                 switch (t->type) {
1296                 case MONO_TYPE_VALUETYPE:
1297                         klass = sig->params [i]->data.klass;
1298                         if (klass->enumtype)
1299                                 break;
1300                         
1301                         /* store the address of the source into local variable 0 */
1302                         mono_mb_emit_byte (mb, CEE_LDARGA);
1303                         mono_mb_emit_i2 (mb, argnum);
1304                         mono_mb_emit_byte (mb, CEE_STLOC_0);
1305                         
1306                         /* allocate space for the native struct and
1307                          * store the address into local variable 1 (dest) */
1308                         mono_mb_emit_icon (mb, mono_class_native_size (klass));
1309                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
1310                         mono_mb_emit_stloc (mb, tmp_locals [i]);
1311                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
1312                         mono_mb_emit_byte (mb, CEE_STLOC_1);
1313
1314                         /* emit valuetype convnversion code code */
1315                         emit_struct_conv (mb, sig->params [i]->data.klass, FALSE);
1316
1317                         break;
1318                 case MONO_TYPE_STRING:
1319                         /* fixme: load the address instead */
1320                         mono_mb_emit_ldarg (mb, argnum);
1321                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1322                         mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
1323                         mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
1324                         mono_mb_emit_stloc (mb, tmp_locals [i]);
1325                         break;
1326                 case MONO_TYPE_CLASS:
1327                 case MONO_TYPE_OBJECT:
1328                         if (t->data.klass->delegate) {
1329                                 mono_mb_emit_ldarg (mb, argnum);
1330                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1331                                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
1332                                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_DEL_FTN);
1333                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
1334                         } else {
1335                                 mono_mb_emit_ldarg (mb, argnum);
1336                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1337                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1338                                 /* fixme: convert to what ? */
1339                                 mono_mb_emit_stloc (mb, tmp_locals [i]);
1340                         }
1341                         break;
1342                 }
1343         }
1344
1345         /* push all arguments */
1346
1347         if (sig->hasthis)
1348                 mono_mb_emit_byte (mb, CEE_LDARG_0);
1349
1350         for (i = 0; i < sig->param_count; i++) {
1351                 MonoType *t = sig->params [i];
1352                 
1353                 argnum = i + sig->hasthis;
1354
1355                 if (t->byref) {
1356                         mono_mb_emit_ldarg (mb, argnum);
1357                         continue;
1358                 }
1359
1360                 switch (t->type) {
1361                 case MONO_TYPE_BOOLEAN:
1362                         mono_mb_emit_ldarg (mb, argnum);
1363                         break;
1364                 case MONO_TYPE_I1:
1365                 case MONO_TYPE_U1:
1366                 case MONO_TYPE_I2:
1367                 case MONO_TYPE_U2:
1368                 case MONO_TYPE_I4:
1369                 case MONO_TYPE_U4:
1370                 case MONO_TYPE_I:
1371                 case MONO_TYPE_U:
1372                 case MONO_TYPE_PTR:
1373                 case MONO_TYPE_R4:
1374                 case MONO_TYPE_R8:
1375                 case MONO_TYPE_I8:
1376                 case MONO_TYPE_U8:
1377                         mono_mb_emit_ldarg (mb, argnum);
1378                         break;
1379                 case MONO_TYPE_VALUETYPE:
1380                         klass = sig->params [i]->data.klass;
1381                         if (klass->enumtype) {
1382                                 mono_mb_emit_ldarg (mb, argnum);
1383                                 break;
1384                         }                       
1385                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
1386                         //mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1387                         //mono_mb_emit_byte (mb, CEE_MONO_LDOBJ);
1388                         //mono_mb_emit_i4 (mb, mono_klass_native_size (klass));
1389
1390                         break;
1391                 case MONO_TYPE_STRING:
1392                         /* fixme: load the address instead */
1393                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
1394                         break;
1395                 case MONO_TYPE_CLASS:
1396                 case MONO_TYPE_OBJECT:
1397                         mono_mb_emit_ldloc (mb, tmp_locals [i]);
1398                         break;
1399                 case MONO_TYPE_CHAR:
1400                 case MONO_TYPE_ARRAY:
1401                 case MONO_TYPE_SZARRAY:
1402                 case MONO_TYPE_TYPEDBYREF:
1403                 case MONO_TYPE_FNPTR:
1404                 default:
1405                         g_warning ("type 0x%02x unknown", t->type);     
1406                         g_assert_not_reached ();
1407                 }
1408         }                       
1409
1410         /* call the native method */
1411         mono_mb_emit_native_call (mb, csig, method->addr);
1412
1413         type = sig->ret->type;
1414 handle_enum:
1415         switch (type) {
1416         case MONO_TYPE_VOID:
1417         case MONO_TYPE_I1:
1418         case MONO_TYPE_U1:
1419         case MONO_TYPE_I2:
1420         case MONO_TYPE_U2:
1421         case MONO_TYPE_I4:
1422         case MONO_TYPE_U4:
1423         case MONO_TYPE_I:
1424         case MONO_TYPE_U:
1425         case MONO_TYPE_PTR:
1426         case MONO_TYPE_R4:
1427         case MONO_TYPE_R8:
1428         case MONO_TYPE_I8:
1429         case MONO_TYPE_U8:
1430                 /* no conversions necessary */
1431                 break;
1432         case MONO_TYPE_BOOLEAN:
1433                 /* maybe we need to make sure that it fits within 8 bits */
1434                 break;
1435         case MONO_TYPE_VALUETYPE:
1436                 if (sig->ret->data.klass->enumtype) {
1437                         type = sig->ret->data.klass->enum_basetype->type;
1438                         goto handle_enum;
1439                 } else {
1440                         g_warning ("generic valutype %s not handled", sig->ret->data.klass->name);
1441                         g_assert_not_reached ();
1442                 }
1443                 break;
1444         case MONO_TYPE_STRING:
1445                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1446                 mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
1447                 mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
1448                 break;
1449         case MONO_TYPE_ARRAY:
1450         case MONO_TYPE_SZARRAY:
1451         case MONO_TYPE_CLASS:
1452         case MONO_TYPE_OBJECT:
1453                 /* fixme: we need conversions here */
1454                 break;
1455         case MONO_TYPE_CHAR:
1456         case MONO_TYPE_TYPEDBYREF:
1457         case MONO_TYPE_FNPTR:
1458         default:
1459                 g_warning ("return type 0x%02x unknown", sig->ret->type);       
1460                 g_assert_not_reached ();
1461         }
1462
1463         mono_mb_emit_byte (mb, CEE_RET);
1464
1465         res = mono_mb_create_method (mb, sig, 0);
1466         mono_mb_free (mb);
1467
1468         g_hash_table_insert (cache, method, res);
1469
1470         return res;
1471 }
1472
1473 /*
1474  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
1475  */
1476 MonoMethod *
1477 mono_marshal_get_struct_to_ptr (MonoClass *klass)
1478 {
1479         MonoMethodBuilder *mb;
1480         static MonoMethod *stoptr = NULL;
1481         MonoMethod *res;
1482
1483         g_assert (klass != NULL);
1484
1485         if (klass->str_to_ptr)
1486                 return klass->str_to_ptr;
1487
1488         if (!stoptr) 
1489                 stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
1490         g_assert (stoptr);
1491
1492         mb = mono_mb_new (stoptr->klass, stoptr->name);
1493
1494         /* allocate local 0 (pointer) src_ptr */
1495         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1496         /* allocate local 1 (pointer) dst_ptr */
1497         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1498         /* allocate local 2 (pointer) as tmp/scratch storage */
1499         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1500
1501         /* initialize src_ptr to point to the start of object data */
1502         mono_mb_emit_byte (mb, CEE_LDARG_0);
1503         mono_mb_emit_icon (mb, sizeof (MonoObject));
1504         mono_mb_emit_byte (mb, CEE_ADD);
1505         mono_mb_emit_byte (mb, CEE_STLOC_0);
1506
1507         /* initialize dst_ptr */
1508         mono_mb_emit_byte (mb, CEE_LDARG_1);
1509         mono_mb_emit_byte (mb, CEE_STLOC_1);
1510
1511         emit_struct_conv (mb, klass, FALSE);
1512
1513         mono_mb_emit_byte (mb, CEE_RET);
1514
1515         res = mono_mb_create_method (mb, stoptr->signature, 0);
1516         mono_mb_free (mb);
1517
1518         klass->str_to_ptr = res;
1519         return res;
1520 }
1521
1522 /*
1523  * generates IL code for PtrToStructure (IntPtr src, object structure)
1524  */
1525 MonoMethod *
1526 mono_marshal_get_ptr_to_struct (MonoClass *klass)
1527 {
1528         MonoMethodBuilder *mb;
1529         static MonoMethod *ptostr = NULL;
1530         MonoMethod *res;
1531
1532         g_assert (klass != NULL);
1533
1534         if (klass->ptr_to_str)
1535                 return klass->ptr_to_str;
1536
1537         if (!ptostr) 
1538                 ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
1539         g_assert (ptostr);
1540
1541         mb = mono_mb_new (ptostr->klass, ptostr->name);
1542
1543         /* allocate local 0 (pointer) src_ptr */
1544         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1545         /* allocate local 1 (pointer) dst_ptr */
1546         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1547         /* allocate local 2 (pointer) as tmp/scratch storage */
1548         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1549
1550         /* initialize src_ptr to point to the start of object data */
1551         mono_mb_emit_byte (mb, CEE_LDARG_0);
1552         mono_mb_emit_byte (mb, CEE_STLOC_0);
1553
1554         /* initialize dst_ptr */
1555         mono_mb_emit_byte (mb, CEE_LDARG_1);
1556         mono_mb_emit_icon (mb, sizeof (MonoObject));
1557         mono_mb_emit_byte (mb, CEE_ADD);
1558         mono_mb_emit_byte (mb, CEE_STLOC_1);
1559
1560         emit_struct_conv (mb, klass, TRUE);
1561
1562         mono_mb_emit_byte (mb, CEE_RET);
1563
1564         res = mono_mb_create_method (mb, ptostr->signature, 0);
1565         mono_mb_free (mb);
1566
1567         klass->ptr_to_str = res;
1568         return res;
1569 }
1570
1571 /* FIXME: on win32 we should probably use GlobalAlloc(). */
1572 void*
1573 mono_marshal_alloc (gpointer size) {
1574         return g_try_malloc ((gulong)size);
1575 }
1576
1577 void
1578 mono_marshal_free (gpointer ptr) {
1579         g_free (ptr);
1580 }
1581
1582 void*
1583 mono_marshal_realloc (gpointer ptr, gpointer size) {
1584         return g_try_realloc (ptr, (gulong)size);
1585 }
1586
1587 void*
1588 mono_marshal_string_array (MonoArray *array)
1589 {
1590         char **result;
1591         int i, len;
1592
1593         if (!array)
1594                 return NULL;
1595
1596         len = mono_array_length (array);
1597
1598         result = g_malloc (sizeof (char*) * len);
1599         for (i = 0; i < len; ++i) {
1600                 MonoString *s = (MonoString*)mono_array_get (array, gpointer, i);
1601                 result [i] = s ? mono_string_to_utf8 (s): NULL;
1602         }
1603         return result;
1604 }
1605
1606 void
1607 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
1608                                                                     gpointer dest, gint32 length)
1609 {
1610         int element_size;
1611         void *source_addr;
1612
1613         MONO_CHECK_ARG_NULL (src);
1614         MONO_CHECK_ARG_NULL (dest);
1615
1616         g_assert (src->obj.vtable->klass->rank == 1);
1617         g_assert (start_index >= 0 && start_index < mono_array_length (src));
1618         g_assert (start_index + length <= mono_array_length (src));
1619
1620         element_size = mono_array_element_size (src->obj.vtable->klass);
1621           
1622         source_addr = mono_array_addr_with_size (src, element_size, start_index);
1623
1624         memcpy (dest, source_addr, length * element_size);
1625 }
1626
1627 void
1628 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
1629                                                                       MonoArray *dest, gint32 length)
1630 {
1631         int element_size;
1632         void *dest_addr;
1633
1634         MONO_CHECK_ARG_NULL (src);
1635         MONO_CHECK_ARG_NULL (dest);
1636
1637         g_assert (dest->obj.vtable->klass->rank == 1);
1638         g_assert (start_index >= 0 && start_index < mono_array_length (dest));
1639         g_assert (start_index + length <= mono_array_length (dest));
1640
1641         element_size = mono_array_element_size (dest->obj.vtable->klass);
1642           
1643         dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
1644
1645         memcpy (dest_addr, src, length * element_size);
1646 }
1647
1648 gpointer
1649 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
1650 {
1651         char *p = ptr;
1652         return *(gpointer*)(p + offset);
1653 }
1654
1655 unsigned char
1656 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
1657 {
1658         char *p = ptr;
1659         return *(unsigned char*)(p + offset);
1660 }
1661
1662 gint16
1663 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
1664 {
1665         char *p = ptr;
1666         return *(gint16*)(p + offset);
1667 }
1668
1669 gint32
1670 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
1671 {
1672         char *p = ptr;
1673         return *(gint32*)(p + offset);
1674 }
1675
1676 gint64
1677 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
1678 {
1679         char *p = ptr;
1680         return *(gint64*)(p + offset);
1681 }
1682
1683 void
1684 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
1685 {
1686         char *p = ptr;
1687         *(unsigned char*)(p + offset) = val;
1688 }
1689
1690 void
1691 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
1692 {
1693         char *p = ptr;
1694         *(gpointer*)(p + offset) = val;
1695 }
1696
1697 void
1698 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
1699 {
1700         char *p = ptr;
1701         *(gint16*)(p + offset) = val;
1702 }
1703
1704 void
1705 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
1706 {
1707         char *p = ptr;
1708         *(gint32*)(p + offset) = val;
1709 }
1710
1711 void
1712 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
1713 {
1714         char *p = ptr;
1715         *(gint64*)(p + offset) = val;
1716 }
1717
1718 MonoString*
1719 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAuto (gpointer ptr)
1720 {
1721         MonoDomain *domain = mono_domain_get (); 
1722
1723         return mono_string_new (domain, (char *)ptr);
1724 }
1725
1726 guint32 
1727 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
1728 {
1729         return (GetLastError ());
1730 }
1731
1732 guint32 
1733 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
1734 {
1735         MonoClass *klass;
1736
1737         MONO_CHECK_ARG_NULL (rtype);
1738
1739         klass = mono_class_from_mono_type (rtype->type);
1740
1741         return mono_class_native_size (klass);
1742 }
1743
1744 void
1745 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
1746 {
1747         MonoMethod *method;
1748         gpointer pa [3];
1749
1750         MONO_CHECK_ARG_NULL (obj);
1751         MONO_CHECK_ARG_NULL (dst);
1752
1753         method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
1754
1755         pa [0] = obj;
1756         pa [1] = &dst;
1757         pa [2] = &delete_old;
1758
1759         mono_runtime_invoke (method, NULL, pa, NULL);
1760 }
1761
1762 void
1763 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
1764 {
1765         MonoMethod *method;
1766         gpointer pa [2];
1767
1768         MONO_CHECK_ARG_NULL (src);
1769         MONO_CHECK_ARG_NULL (dst);
1770
1771         method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
1772
1773         pa [0] = &src;
1774         pa [1] = dst;
1775
1776         mono_runtime_invoke (method, NULL, pa, NULL);
1777 }