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