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