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