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