2009-01-26 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / marshal.c
1 /*
2  * marshal.c: Routines for marshaling complex types in P/Invoke methods.
3  * 
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.  http://www.ximian.com
8  *
9  */
10
11 #include "config.h"
12 #include "object.h"
13 #include "loader.h"
14 #include "cil-coff.h"
15 #include "metadata/marshal.h"
16 #include "metadata/method-builder.h"
17 #include "metadata/tabledefs.h"
18 #include "metadata/exception.h"
19 #include "metadata/appdomain.h"
20 #include "mono/metadata/debug-helpers.h"
21 #include "mono/metadata/threadpool.h"
22 #include "mono/metadata/threads.h"
23 #include "mono/metadata/monitor.h"
24 #include "mono/metadata/metadata-internals.h"
25 #include "mono/metadata/domain-internals.h"
26 #include "mono/metadata/gc-internal.h"
27 #include "mono/metadata/threads-types.h"
28 #include "mono/metadata/string-icalls.h"
29 #include "mono/metadata/attrdefs.h"
30 #include "mono/metadata/gc-internal.h"
31 #include "mono/utils/mono-counters.h"
32 #include <string.h>
33 #include <errno.h>
34
35 /* #define DEBUG_RUNTIME_CODE */
36
37 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
38         a = i,
39
40 typedef enum {
41         MONO_MARSHAL_NONE,                      /* No marshalling needed */
42         MONO_MARSHAL_COPY,                      /* Can be copied by value to the new domain */
43         MONO_MARSHAL_COPY_OUT,          /* out parameter that needs to be copied back to the original instance */
44         MONO_MARSHAL_SERIALIZE          /* Value needs to be serialized into the new domain */
45 } MonoXDomainMarshalType;
46
47 typedef enum {
48         MONO_COM_DEFAULT,
49         MONO_COM_MS
50 } MonoCOMProvider;
51
52 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
53
54 enum {
55 #include "mono/cil/opcode.def"
56         LAST = 0xff
57 };
58 #undef OPDEF
59
60 struct _MonoRemotingMethods {
61         MonoMethod *invoke;
62         MonoMethod *invoke_with_check;
63         MonoMethod *xdomain_invoke;
64         MonoMethod *xdomain_dispatch;
65 };
66
67 typedef struct _MonoRemotingMethods MonoRemotingMethods;
68
69 /* 
70  * This mutex protects the various marshalling related caches in MonoImage
71  * and a few other data structures static to this file.
72  * Note that when this lock is held it is not possible to take other runtime
73  * locks like the loader lock.
74  */
75 #define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
76 #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
77 static CRITICAL_SECTION marshal_mutex;
78
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
81 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
82 static CRITICAL_SECTION cominterop_mutex;
83
84 static guint32 last_error_tls_id;
85
86 static guint32 load_type_info_tls_id;
87
88 static void
89 delegate_hash_table_add (MonoDelegate *d);
90
91 static void
92 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
93
94 static void 
95 mono_struct_delete_old (MonoClass *klass, char *ptr);
96
97 void *
98 mono_marshal_string_to_utf16 (MonoString *s);
99
100 static void *
101 mono_marshal_string_to_utf16_copy (MonoString *s);
102
103 static gpointer
104 mono_string_to_lpstr (MonoString *string_obj);
105
106 static MonoString * 
107 mono_string_from_bstr (gpointer bstr);
108
109 static void 
110 mono_free_bstr (gpointer bstr);
111
112 static MonoStringBuilder *
113 mono_string_utf8_to_builder2 (char *text);
114
115 static void
116 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum);
117
118 static void
119 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *eltype, guint32 elnum);
120
121 static MonoObject *
122 mono_remoting_wrapper (MonoMethod *method, gpointer *params);
123
124 static MonoAsyncResult *
125 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params);
126
127 static MonoObject *
128 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
129
130 static MonoObject *
131 mono_marshal_xdomain_copy_value (MonoObject *val);
132
133 static void
134 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst);
135
136 static gint32
137 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push);
138
139 static gboolean
140 mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image);
141
142 void
143 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
144
145 static MonoReflectionType *
146 type_from_handle (MonoType *handle);
147
148 static void
149 mono_marshal_set_last_error_windows (int error);
150
151 static void
152 mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions);
153
154 static void init_safe_handle (void);
155
156 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
157 static MonoMethod *sh_dangerous_add_ref;
158 static MonoMethod *sh_dangerous_release;
159
160
161 static void
162 init_safe_handle ()
163 {
164         sh_dangerous_add_ref = mono_class_get_method_from_name (
165                 mono_defaults.safehandle_class, "DangerousAddRef", 1);
166         sh_dangerous_release = mono_class_get_method_from_name (
167                 mono_defaults.safehandle_class, "DangerousRelease", 0);
168 }
169
170 static void
171 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
172 {
173         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
174
175         mono_register_jit_icall (func, name, sig, save);
176 }
177
178 static MonoMethodSignature*
179 signature_dup (MonoImage *image, MonoMethodSignature *sig)
180 {
181         MonoMethodSignature *res;
182         int sigsize;
183
184         res = mono_metadata_signature_alloc (image, sig->param_count);
185         sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
186         memcpy (res, sig, sigsize);
187
188         return res;
189 }
190
191 MonoMethodSignature*
192 mono_signature_no_pinvoke (MonoMethod *method)
193 {
194         MonoMethodSignature *sig = mono_method_signature (method);
195         if (sig->pinvoke) {
196                 sig = signature_dup (method->klass->image, sig);
197                 sig->pinvoke = FALSE;
198         }
199         
200         return sig;
201 }
202
203 /* Begin COM Interop related stuff until seperate file */
204
205
206 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
207 #ifdef  PLATFORM_WIN32
208 #define STDCALL __stdcall
209 #else
210 #define STDCALL
211 #endif
212
213 /* Upon creation of a CCW, only allocate a weak handle and set the
214  * reference count to 0. If the unmanaged client code decides to addref and
215  * hold onto the CCW, I then allocate a strong handle. Once the reference count
216  * goes back to 0, convert back to a weak handle.
217  */
218 typedef struct {
219         guint32 ref_count;
220         guint32 gc_handle;
221         GHashTable* vtable_hash;
222 #ifdef  PLATFORM_WIN32
223         gpointer free_marshaler;
224 #endif
225 } MonoCCW;
226
227 /* This type is the actual pointer passed to unmanaged code
228  * to represent a COM interface.
229  */
230 typedef struct {
231         gpointer vtable;
232         MonoCCW* ccw;
233 } MonoCCWInterface;
234
235 #ifndef DISABLE_COM
236
237 /* IUnknown */
238 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
239
240 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
241
242 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
243
244 /* IDispatch */
245 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
246
247 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
248
249 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
250                                                                                          gunichar2** rgszNames, guint32 cNames,
251                                                                                          guint32 lcid, gint32 *rgDispId);
252
253 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
254                                                                    gpointer riid, guint32 lcid,
255                                                                    guint16 wFlags, gpointer pDispParams,
256                                                                    gpointer pVarResult, gpointer pExcepInfo,
257                                                                    guint32 *puArgErr);
258
259 static MonoMethod *
260 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
261
262 static gpointer
263 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
264
265 static MonoObject*
266 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
267
268 /**
269  * cominterop_method_signature:
270  * @method: a method
271  *
272  * Returns: the corresponding unmanaged method signature for a managed COM 
273  * method.
274  */
275 static MonoMethodSignature*
276 cominterop_method_signature (MonoMethod* method)
277 {
278         MonoMethodSignature *res;
279         MonoImage *image = method->klass->image;
280         MonoMethodSignature *sig = mono_method_signature (method);
281         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
282         int sigsize;
283         int i;
284         int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
285
286         if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
287                 param_count++;
288
289         res = mono_metadata_signature_alloc (image, param_count);
290         sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
291         memcpy (res, sig, sigsize);
292
293         // now move args forward one
294         for (i = sig->param_count-1; i >= 0; i--)
295                 res->params[i+1] = sig->params[i];
296
297         // first arg is interface pointer
298         res->params[0] = &mono_defaults.int_class->byval_arg;
299
300         if (preserve_sig) {
301                 res->ret = sig->ret;
302         }
303         else {
304                 // last arg is return type
305                 if (!MONO_TYPE_IS_VOID (sig->ret)) {
306                         res->params[param_count-1] = mono_metadata_type_dup (image->mempool, sig->ret);
307                         res->params[param_count-1]->byref = 1;
308                         res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
309                 }
310
311                 // return type is always int32 (HRESULT)
312                 res->ret = &mono_defaults.int32_class->byval_arg;
313         }
314
315         // no pinvoke
316         res->pinvoke = FALSE;
317
318         // no hasthis
319         res->hasthis = 0;
320
321         // set param_count
322         res->param_count = param_count;
323
324         // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
325 #ifdef PLATFORM_WIN32
326         res->call_convention = MONO_CALL_STDCALL;
327 #else
328         res->call_convention = MONO_CALL_C;
329 #endif
330
331         return res;
332 }
333
334 /**
335  * cominterop_get_function_pointer:
336  * @itf: a pointer to the COM interface
337  * @slot: the vtable slot of the method pointer to return
338  *
339  * Returns: the unmanaged vtable function pointer from the interface
340  */
341 static gpointer
342 cominterop_get_function_pointer (gpointer itf, int slot)
343 {
344         gpointer func;
345         func = *((*(gpointer**)itf)+slot);
346         return func;
347 }
348
349 /**
350  * cominterop_object_is_com_object:
351  * @obj: a pointer to the object
352  *
353  * Returns: a value indicating if the object is a
354  * Runtime Callable Wrapper (RCW) for a COM object
355  */
356 static gboolean
357 cominterop_object_is_rcw (MonoObject *obj)
358 {
359         MonoClass *klass = NULL;
360         MonoRealProxy* real_proxy = NULL;
361         if (!obj)
362                 return FALSE;
363         klass = mono_object_class (obj);
364         if (klass != mono_defaults.transparent_proxy_class)
365                 return FALSE;
366
367         real_proxy = ((MonoTransparentProxy*)obj)->rp;
368         if (!real_proxy)
369                 return FALSE;
370
371         klass = mono_object_class (real_proxy);
372         return (klass && klass == mono_defaults.com_interop_proxy_class);
373 }
374
375 static int
376 cominterop_get_com_slot_begin (MonoClass* klass)
377 {
378         static MonoClass *interface_type_attribute = NULL;
379         MonoCustomAttrInfo *cinfo = NULL;
380         MonoInterfaceTypeAttribute* itf_attr = NULL; 
381
382         if (!interface_type_attribute)
383                 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
384         cinfo = mono_custom_attrs_from_class (klass);
385         if (cinfo) {
386                 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
387                 if (!cinfo->cached)
388                         mono_custom_attrs_free (cinfo);
389         }
390
391         if (itf_attr && itf_attr->intType == 1)
392                 return 3; /* 3 methods in IUnknown*/
393         else
394                 return 7; /* 7 methods in IDispatch*/
395 }
396
397 /**
398  * cominterop_get_method_interface:
399  * @method: method being called
400  *
401  * Returns: the MonoClass* representing the interface on which
402  * the method is defined.
403  */
404 static MonoClass*
405 cominterop_get_method_interface (MonoMethod* method)
406 {
407         MonoClass *ic = method->klass;
408
409         /* if method is on a class, we need to look up interface method exists on */
410         if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
411                 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass);
412                 if (ifaces) {
413                         int i;
414                         for (i = 0; i < ifaces->len; ++i) {
415                                 int offset;
416                                 ic = g_ptr_array_index (ifaces, i);
417                                 offset = mono_class_interface_offset (method->klass, ic);
418                                 if (method->slot >= offset && method->slot < offset + ic->method.count)
419                                         break;
420                                 ic = NULL;
421                         }
422                         g_ptr_array_free (ifaces, TRUE);
423                 }
424         }
425
426         g_assert (ic);
427         g_assert (MONO_CLASS_IS_INTERFACE (ic));
428
429         return ic;
430 }
431
432 /**
433  * cominterop_get_com_slot_for_method:
434  * @method: a method
435  *
436  * Returns: the method's slot in the COM interface vtable
437  */
438 static int
439 cominterop_get_com_slot_for_method (MonoMethod* method)
440 {
441         guint32 slot = method->slot;
442         MonoClass *ic = method->klass;
443
444         /* if method is on a class, we need to look up interface method exists on */
445         if (!MONO_CLASS_IS_INTERFACE(ic)) {
446                 int offset = 0;
447                 ic = cominterop_get_method_interface (method);
448                 offset = mono_class_interface_offset (method->klass, ic);
449                 g_assert(offset >= 0);
450                 slot -= offset;
451         }
452
453         g_assert (ic);
454         g_assert (MONO_CLASS_IS_INTERFACE (ic));
455
456         return slot + cominterop_get_com_slot_begin (ic);
457 }
458
459
460 static void
461 cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid);
462
463 static gboolean
464 cominterop_class_guid (MonoClass* klass, guint8* guid)
465 {
466         static MonoClass *GuidAttribute = NULL;
467         MonoCustomAttrInfo *cinfo;
468
469         /* Handle the GuidAttribute */
470         if (!GuidAttribute)
471                 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
472
473         cinfo = mono_custom_attrs_from_class (klass);   
474         if (cinfo) {
475                 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
476
477                 if (!attr)
478                         return FALSE;
479                 if (!cinfo->cached)
480                         mono_custom_attrs_free (cinfo);
481
482                 cominterop_mono_string_to_guid (attr->guid, guid);
483                 return TRUE;
484         }
485         return FALSE;
486 }
487
488 static gboolean
489 cominterop_com_visible (MonoClass* klass)
490 {
491         static MonoClass *ComVisibleAttribute = NULL;
492         MonoCustomAttrInfo *cinfo;
493
494         /* Handle the ComVisibleAttribute */
495         if (!ComVisibleAttribute)
496                 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
497
498         cinfo = mono_custom_attrs_from_class (klass);   
499         if (cinfo) {
500                 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
501
502                 if (!attr)
503                         return FALSE;
504                 if (!cinfo->cached)
505                         mono_custom_attrs_free (cinfo);
506
507                 if (attr->visible)
508                         return TRUE;
509         }
510         return FALSE;
511 }
512
513 static void cominterop_raise_hr_exception (int hr)
514 {
515         static MonoMethod* throw_exception_for_hr = NULL;
516         MonoException* ex;
517         void* params[1] = {&hr};
518         if (!throw_exception_for_hr)
519                 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
520         ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
521         mono_raise_exception (ex);
522 }
523
524 /**
525  * cominterop_get_interface:
526  * @obj: managed wrapper object containing COM object
527  * @ic: interface type to retrieve for COM object
528  *
529  * Returns: the COM interface requested
530  */
531 static gpointer
532 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
533 {
534         gpointer itf = NULL;
535
536         g_assert (ic);
537         g_assert (MONO_CLASS_IS_INTERFACE (ic));
538
539         mono_cominterop_lock ();
540         if (obj->itf_hash)
541                 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
542         mono_cominterop_unlock ();
543
544         if (!itf) {
545                 guint8 iid [16];
546                 int found = cominterop_class_guid (ic, iid);
547                 int hr;
548                 g_assert(found);
549                 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
550                 if (hr < 0 && throw_exception) {
551                         cominterop_raise_hr_exception (hr);     
552                 }
553
554                 if (hr >= 0 && itf) {
555                         mono_cominterop_lock ();
556                         if (!obj->itf_hash)
557                                 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
558                         g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
559                         mono_cominterop_unlock ();
560                 }
561
562         }
563         if (throw_exception)
564                 g_assert (itf);
565
566         return itf;
567 }
568
569 static int
570 cominterop_get_hresult_for_exception (MonoException* exc)
571 {
572         int hr = 0;
573         return hr;
574 }
575
576 #endif /* DISABLE_COM */
577
578 void
579 mono_marshal_init (void)
580 {
581         static gboolean module_initialized = FALSE;
582
583         if (!module_initialized) {
584                 char* com_provider_env = NULL;
585                 module_initialized = TRUE;
586                 InitializeCriticalSection (&marshal_mutex);
587                 InitializeCriticalSection (&cominterop_mutex);
588                 last_error_tls_id = TlsAlloc ();
589                 load_type_info_tls_id = TlsAlloc ();
590
591                 com_provider_env = getenv ("MONO_COM");
592                 if (com_provider_env && !strcmp(com_provider_env, "MS"))
593                         com_provider = MONO_COM_MS;
594
595                 register_icall (ves_icall_System_Threading_Thread_ResetAbort, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE);
596                 register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
597                 register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
598                 register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
599                 register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
600                 register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
601                 register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
602                 register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
603                 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
604                 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
605                 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
606                 register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
607                 register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
608                 register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
609                 register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
610                 register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
611                 register_icall (mono_byvalarray_to_array, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE);
612                 register_icall (mono_array_to_byvalarray, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE);
613                 register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
614                 register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
615                 register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
616                 register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
617                 register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
618                 register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
619                 register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
620                 register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE);
621                 register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
622                 register_icall (mono_string_utf8_to_builder2, "mono_string_utf8_to_builder2", "object ptr", FALSE);
623                 register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
624                 register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
625                 register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
626                 register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
627                 register_icall (g_free, "g_free", "void ptr", FALSE);
628                 register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
629                 register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
630                 register_icall (mono_remoting_wrapper, "mono_remoting_wrapper", "object ptr ptr", FALSE);
631                 register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
632                 register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
633                 register_icall (mono_marshal_xdomain_copy_value, "mono_marshal_xdomain_copy_value", "object object", FALSE);
634                 register_icall (mono_marshal_xdomain_copy_out_value, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE);
635                 register_icall (mono_marshal_set_domain_by_id, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE);
636                 register_icall (mono_marshal_check_domain_image, "mono_marshal_check_domain_image", "int32 int32 ptr", FALSE);
637                 register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
638                 register_icall (mono_context_get, "mono_context_get", "object", FALSE);
639                 register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
640                 register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE);
641                 register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE);
642                 register_icall (mono_gc_wbarrier_generic_store, "wb_generic", "void ptr object", FALSE);
643 #ifndef DISABLE_COM
644                 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
645                 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
646                 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
647                 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
648                 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
649                 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
650                 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
651 #endif /* DISABLE_COM */
652         }
653 }
654
655 void
656 mono_marshal_cleanup (void)
657 {
658         TlsFree (load_type_info_tls_id);
659         TlsFree (last_error_tls_id);
660         DeleteCriticalSection (&marshal_mutex);
661         DeleteCriticalSection (&cominterop_mutex);
662 }
663
664 MonoClass *byte_array_class;
665 static MonoMethod *method_rs_serialize, *method_rs_deserialize, *method_exc_fixexc, *method_rs_appdomain_target;
666 static MonoMethod *method_set_context, *method_get_context;
667 static MonoMethod *method_set_call_context, *method_needs_context_sink, *method_rs_serialize_exc;
668
669 static void
670 mono_remoting_marshal_init (void)
671 {
672         MonoClass *klass;
673
674         static gboolean module_initialized = FALSE;
675
676         if (!module_initialized) {
677                 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
678                 method_rs_serialize = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
679                 method_rs_deserialize = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
680                 method_rs_serialize_exc = mono_class_get_method_from_name (klass, "SerializeExceptionData", -1);
681         
682                 klass = mono_defaults.real_proxy_class;
683                 method_rs_appdomain_target = mono_class_get_method_from_name (klass, "GetAppDomainTarget", -1);
684         
685                 klass = mono_defaults.exception_class;
686                 method_exc_fixexc = mono_class_get_method_from_name (klass, "FixRemotingException", -1);
687         
688                 klass = mono_defaults.thread_class;
689                 method_get_context = mono_class_get_method_from_name (klass, "get_CurrentContext", -1);
690         
691                 klass = mono_defaults.appdomain_class;
692                 method_set_context = mono_class_get_method_from_name (klass, "InternalSetContext", -1);
693                 byte_array_class = mono_array_class_get (mono_defaults.byte_class, 1);
694         
695                 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Messaging", "CallContext");
696                 method_set_call_context = mono_class_get_method_from_name (klass, "SetCurrentCallContext", -1);
697         
698                 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
699                 method_needs_context_sink = mono_class_get_method_from_name (klass, "get_NeedsContextSink", -1);
700
701                 module_initialized = TRUE;
702         }
703 }
704
705 gpointer
706 mono_delegate_to_ftnptr (MonoDelegate *delegate)
707 {
708         MonoMethod *method, *wrapper;
709         MonoClass *klass;
710
711         if (!delegate)
712                 return NULL;
713
714         if (delegate->delegate_trampoline)
715                 return delegate->delegate_trampoline;
716
717         klass = ((MonoObject *)delegate)->vtable->klass;
718         g_assert (klass->delegate);
719
720         method = delegate->method;
721
722         wrapper = mono_marshal_get_managed_wrapper (method, klass, delegate->target);
723
724         delegate->delegate_trampoline =  mono_compile_method (wrapper);
725
726         // Add the delegate to the delegate hash table
727         delegate_hash_table_add (delegate);
728
729         /* when the object is collected, collect the dynamic method, too */
730         mono_object_register_finalizer ((MonoObject*)delegate);
731
732         return delegate->delegate_trampoline;
733 }
734
735 /* 
736  * this hash table maps from a delegate trampoline object to a weak reference
737  * of the delegate. As an optimizations with a non-moving GC we store the
738  * object pointer itself, otherwise we use a GC handle.
739  */
740 static GHashTable *delegate_hash_table;
741
742 static GHashTable *
743 delegate_hash_table_new (void) {
744         return g_hash_table_new (NULL, NULL);
745 }
746
747 static void 
748 delegate_hash_table_remove (MonoDelegate *d)
749 {
750 #ifdef HAVE_MOVING_COLLECTOR
751         guint32 gchandle;
752 #endif
753         mono_marshal_lock ();
754         if (delegate_hash_table == NULL)
755                 delegate_hash_table = delegate_hash_table_new ();
756 #ifdef HAVE_MOVING_COLLECTOR
757         gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
758 #endif
759         g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
760         mono_marshal_unlock ();
761 #ifdef HAVE_MOVING_COLLECTOR
762         mono_gchandle_free (gchandle);
763 #endif
764 }
765
766 static void
767 delegate_hash_table_add (MonoDelegate *d) 
768 {
769 #ifdef HAVE_MOVING_COLLECTOR
770         guint32 gchandle = mono_gchandle_new_weakref ((MonoObject*)d, FALSE);
771 #endif
772         mono_marshal_lock ();
773         if (delegate_hash_table == NULL)
774                 delegate_hash_table = delegate_hash_table_new ();
775 #ifdef HAVE_MOVING_COLLECTOR
776         g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, GUINT_TO_POINTER (gchandle));
777 #else
778         g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d);
779 #endif
780         mono_marshal_unlock ();
781 }
782
783 MonoDelegate*
784 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
785 {
786 #ifdef HAVE_MOVING_COLLECTOR
787         guint32 gchandle;
788 #endif
789         MonoDelegate *d;
790
791         mono_marshal_lock ();
792         if (delegate_hash_table == NULL)
793                 delegate_hash_table = delegate_hash_table_new ();
794
795 #ifdef HAVE_MOVING_COLLECTOR
796         gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, ftn));
797         mono_marshal_unlock ();
798         if (gchandle)
799                 d = (MonoDelegate*)mono_gchandle_get_target (gchandle);
800         else
801                 d = NULL;
802 #else
803         d = g_hash_table_lookup (delegate_hash_table, ftn);
804         mono_marshal_unlock ();
805 #endif
806         if (d == NULL) {
807                 /* This is a native function, so construct a delegate for it */
808                 static MonoClass *UnmanagedFunctionPointerAttribute;
809                 MonoMethodSignature *sig;
810                 MonoMethod *wrapper;
811                 MonoMarshalSpec **mspecs;
812                 MonoCustomAttrInfo *cinfo;
813                 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
814                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
815                 MonoMethodPInvoke piinfo;
816                 int i;
817
818                 memset (&piinfo, 0, sizeof (piinfo));
819                 if (!UnmanagedFunctionPointerAttribute)
820                         UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
821
822                 /* The attribute is only available in Net 2.0 */
823                 if (UnmanagedFunctionPointerAttribute) {
824                         /* 
825                          * The pinvoke attributes are stored in a real custom attribute so we have to
826                          * construct it.
827                          */
828                         cinfo = mono_custom_attrs_from_class (klass);
829                         if (cinfo) {
830                                 attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
831                                 if (attr) {
832                                         piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
833                                 }
834                                 if (!cinfo->cached)
835                                         mono_custom_attrs_free (cinfo);
836                         }
837                 }
838
839                 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
840                 mono_method_get_marshal_info (invoke, mspecs);
841                 /* Freed below so don't alloc from mempool */
842                 sig = mono_metadata_signature_dup (mono_method_signature (invoke));
843                 sig->hasthis = 0;
844
845                 wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn);
846
847                 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
848                         if (mspecs [i])
849                                 mono_metadata_free_marshal_spec (mspecs [i]);
850                 g_free (mspecs);
851                 g_free (sig);
852
853                 d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
854                 mono_delegate_ctor_with_method ((MonoObject*)d, NULL, mono_compile_method (wrapper), wrapper);
855         }
856
857         if (d->object.vtable->domain != mono_domain_get ())
858                 mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
859
860         return d;
861 }
862
863 void
864 mono_delegate_free_ftnptr (MonoDelegate *delegate)
865 {
866         MonoJitInfo *ji;
867         void *ptr;
868
869         delegate_hash_table_remove (delegate);
870
871         ptr = (gpointer)InterlockedExchangePointer (&delegate->delegate_trampoline, NULL);
872
873         if (!delegate->target) {
874                 /* The wrapper method is shared between delegates -> no need to free it */
875                 return;
876         }
877
878         if (ptr) {
879                 ji = mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr));
880                 g_assert (ji);
881
882                 mono_runtime_free_method (mono_object_domain (delegate), ji->method);
883         }
884 }
885
886 gpointer
887 mono_array_to_savearray (MonoArray *array)
888 {
889         if (!array)
890                 return NULL;
891
892         g_assert_not_reached ();
893         return NULL;
894 }
895
896 gpointer
897 mono_array_to_lparray (MonoArray *array)
898 {
899         if (!array)
900                 return NULL;
901
902         /* fixme: maybe we need to make a copy */
903         return array->vector;
904 }
905
906 static void
907 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *elclass, guint32 elnum)
908 {
909         g_assert (arr->obj.vtable->klass->element_class == mono_defaults.char_class);
910
911         if (elclass == mono_defaults.byte_class) {
912                 GError *error = NULL;
913                 guint16 *ut;
914                 glong items_written;
915
916                 ut = g_utf8_to_utf16 (native_arr, elnum, NULL, &items_written, &error);
917
918                 if (!error) {
919                         memcpy (mono_array_addr (arr, guint16, 0), ut, items_written * sizeof (guint16));
920                         g_free (ut);
921                 }
922                 else
923                         g_error_free (error);
924         }
925         else
926                 g_assert_not_reached ();
927 }
928
929 static void
930 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
931 {
932         g_assert (arr->obj.vtable->klass->element_class == mono_defaults.char_class);
933
934         if (elclass == mono_defaults.byte_class) {
935                 char *as;
936                 GError *error = NULL;
937
938                 as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
939                 if (error) {
940                         MonoException *exc = mono_get_exception_argument ("string", error->message);
941                         g_error_free (error);
942                         mono_raise_exception (exc);
943                 }
944
945                 memcpy (native_arr, as, MIN (strlen (as), elnum));
946                 g_free (as);
947         } else {
948                 g_assert_not_reached ();
949         }
950 }
951
952 void
953 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
954 {
955         GError *error = NULL;
956         guint16 *ut;
957         glong items_written;
958         int l;
959
960         if (!sb || !text)
961                 return;
962
963         l = strlen (text);
964
965         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
966         
967         if (items_written > mono_stringbuilder_capacity (sb))
968                 items_written = mono_stringbuilder_capacity (sb);
969         
970         if (!error) {
971                 if (! sb->str || sb->str == sb->cached_str) {
972                         MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), items_written));
973                         sb->cached_str = NULL;
974                 }
975                 
976                 memcpy (mono_string_chars (sb->str), ut, items_written * 2);
977                 sb->length = items_written;
978         } else 
979                 g_error_free (error);
980
981         g_free (ut);
982 }
983
984 MonoStringBuilder *
985 mono_string_utf8_to_builder2 (char *text)
986 {
987         int l;
988         MonoStringBuilder *sb;
989         static MonoClass *string_builder_class;
990         static MonoMethod *sb_ctor;
991         void *args [1];
992         MonoObject *exc;
993
994         if (!text)
995                 return NULL;
996
997         if (!string_builder_class) {
998                 MonoMethodDesc *desc;
999
1000                 string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
1001                 g_assert (string_builder_class);
1002                 desc = mono_method_desc_new (":.ctor(int)", FALSE);
1003                 sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
1004                 g_assert (sb_ctor);
1005                 mono_method_desc_free (desc);
1006         }
1007
1008         l = strlen (text);
1009
1010         sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
1011         g_assert (sb);
1012         args [0] = &l;
1013         mono_runtime_invoke (sb_ctor, sb, args, &exc);
1014         g_assert (!exc);
1015
1016         mono_string_utf8_to_builder (sb, text);
1017
1018         return sb;
1019 }
1020
1021 /*
1022  * FIXME: This routine does not seem to do what it seems to do
1023  * the @text is never copied into the string builder
1024  */
1025 void
1026 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
1027 {
1028         guint32 len;
1029
1030         if (!sb || !text)
1031                 return;
1032
1033         g_assert (mono_string_chars (sb->str) == text);
1034
1035         for (len = 0; text [len] != 0; ++len)
1036                 ;
1037
1038         sb->length = len;
1039 }
1040
1041 /**
1042  * mono_string_builder_to_utf8:
1043  * @sb: the string builder
1044  *
1045  * Converts to utf8 the contents of the MonoStringBuilder.
1046  *
1047  * Returns: a utf8 string with the contents of the StringBuilder.
1048  *
1049  * The return value must be released with g_free.
1050  */
1051 gpointer
1052 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
1053 {
1054         GError *error = NULL;
1055         gchar *tmp, *res = NULL;
1056
1057         if (!sb)
1058                 return NULL;
1059
1060         if ((sb->str == sb->cached_str) && (sb->str->length == 0)) {
1061                 /* 
1062                  * The sb could have been allocated with the default capacity and be empty.
1063                  * we need to alloc a buffer of the default capacity in this case.
1064                  */
1065                 MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
1066                 sb->cached_str = NULL;
1067         }
1068
1069         tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, NULL, &error);
1070         if (error) {
1071                 g_error_free (error);
1072                 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
1073         } else {
1074                 res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
1075                 memcpy (res, tmp, sb->length + 1);
1076                 g_free (tmp);
1077         }
1078
1079         return res;
1080 }
1081
1082 /**
1083  * mono_string_builder_to_utf16:
1084  * @sb: the string builder
1085  *
1086  * Converts to utf16 the contents of the MonoStringBuilder.
1087  *
1088  * Returns: a utf16 string with the contents of the StringBuilder.
1089  *
1090  * The return value must not be freed.
1091  */
1092 gpointer
1093 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
1094 {
1095         if (!sb)
1096                 return NULL;
1097
1098         g_assert (sb->str);
1099
1100         /*
1101          * The stringbuilder might not have ownership of this string. If this is
1102          * the case, we must duplicate the string, so that we don't munge immutable
1103          * strings
1104          */
1105         if (sb->str == sb->cached_str) {
1106                 /* 
1107                  * The sb could have been allocated with the default capacity and be empty.
1108                  * we need to alloc a buffer of the default capacity in this case.
1109                  */
1110                 if (sb->str->length == 0)
1111                         MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
1112                 else
1113                         MONO_OBJECT_SETREF (sb, str, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb->str), mono_stringbuilder_capacity (sb)));
1114                 sb->cached_str = NULL;
1115         }
1116         
1117         return mono_string_chars (sb->str);
1118 }
1119
1120 static gpointer
1121 mono_string_to_lpstr (MonoString *s)
1122 {
1123 #ifdef PLATFORM_WIN32
1124         char *as, *tmp;
1125         glong len;
1126         GError *error = NULL;
1127
1128         if (s == NULL)
1129                 return NULL;
1130
1131         if (!s->length) {
1132                 as = CoTaskMemAlloc (1);
1133                 as [0] = '\0';
1134                 return as;
1135         }
1136
1137         tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
1138         if (error) {
1139                 MonoException *exc = mono_get_exception_argument ("string", error->message);
1140                 g_error_free (error);
1141                 mono_raise_exception(exc);
1142                 return NULL;
1143         } else {
1144                 as = CoTaskMemAlloc (len + 1);
1145                 memcpy (as, tmp, len + 1);
1146                 g_free (tmp);
1147                 return as;
1148         }
1149 #else
1150         return mono_string_to_utf8 (s);
1151 #endif
1152 }       
1153
1154 gpointer
1155 mono_string_to_ansibstr (MonoString *string_obj)
1156 {
1157         g_error ("UnmanagedMarshal.BStr is not implemented.");
1158         return NULL;
1159 }
1160
1161 typedef gpointer (*SysAllocStringLenFunc)(gunichar* str, guint32 len);
1162 typedef guint32 (*SysStringLenFunc)(gpointer bstr);
1163 typedef void (*SysFreeStringFunc)(gunichar* str);
1164
1165 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
1166 static SysStringLenFunc sys_string_len_ms = NULL;
1167 static SysFreeStringFunc sys_free_string_ms = NULL;
1168
1169 static gboolean
1170 init_com_provider_ms (void)
1171 {
1172         static gboolean initialized = FALSE;
1173         char *error_msg;
1174         MonoDl *module = NULL;
1175         const char* scope = "liboleaut32.so";
1176
1177         if (initialized)
1178                 return TRUE;
1179
1180         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
1181         if (error_msg) {
1182                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
1183                 g_assert_not_reached ();
1184                 return FALSE;
1185         }
1186         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
1187         if (error_msg) {
1188                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
1189                 g_assert_not_reached ();
1190                 return FALSE;
1191         }
1192
1193         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
1194         if (error_msg) {
1195                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
1196                 g_assert_not_reached ();
1197                 return FALSE;
1198         }
1199
1200         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
1201         if (error_msg) {
1202                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
1203                 g_assert_not_reached ();
1204                 return FALSE;
1205         }
1206
1207         initialized = TRUE;
1208         return TRUE;
1209 }
1210
1211 gpointer
1212 mono_string_to_bstr (MonoString *string_obj)
1213 {
1214         if (!string_obj)
1215                 return NULL;
1216 #ifdef PLATFORM_WIN32
1217         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
1218 #else
1219         if (com_provider == MONO_COM_DEFAULT) {
1220                 int slen = mono_string_length (string_obj);
1221                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
1222                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
1223                 if (ret == NULL)
1224                         return NULL;
1225                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
1226                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
1227                 ret [4 + slen * sizeof(gunichar2)] = 0;
1228                 ret [5 + slen * sizeof(gunichar2)] = 0;
1229
1230                 return ret + 4;
1231         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
1232                 gpointer ret = NULL;
1233                 gunichar* str = NULL;
1234                 guint32 len;
1235                 len = mono_string_length (string_obj);
1236                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
1237                         NULL, NULL, NULL);
1238                 ret = sys_alloc_string_len_ms (str, len);
1239                 g_free(str);
1240                 return ret;
1241         } else {
1242                 g_assert_not_reached ();
1243         }
1244 #endif
1245 }
1246
1247 MonoString *
1248 mono_string_from_bstr (gpointer bstr)
1249 {
1250         if (!bstr)
1251                 return NULL;
1252 #ifdef PLATFORM_WIN32
1253         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
1254 #else
1255         if (com_provider == MONO_COM_DEFAULT) {
1256                 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
1257         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
1258                 MonoString* str = NULL;
1259                 glong written = 0;
1260                 gunichar2* utf16 = NULL;
1261
1262                 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
1263                 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
1264                 g_free (utf16);
1265                 return str;
1266         } else {
1267                 g_assert_not_reached ();
1268         }
1269
1270 #endif
1271 }
1272
1273 void
1274 mono_free_bstr (gpointer bstr)
1275 {
1276         if (!bstr)
1277                 return;
1278 #ifdef PLATFORM_WIN32
1279         SysFreeString ((BSTR)bstr);
1280 #else
1281         if (com_provider == MONO_COM_DEFAULT) {
1282                 g_free (((char *)bstr) - 4);
1283         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
1284                 sys_free_string_ms (bstr);
1285         } else {
1286                 g_assert_not_reached ();
1287         }
1288
1289 #endif
1290 }
1291
1292 /**
1293  * mono_string_to_byvalstr:
1294  * @dst: Where to store the null-terminated utf8 decoded string.
1295  * @src: the MonoString to copy.
1296  * @size: the maximum number of bytes to copy.
1297  *
1298  * Copies the MonoString pointed to by @src as a utf8 string
1299  * into @dst, it copies at most @size bytes into the destination.
1300  */
1301 void
1302 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
1303 {
1304         char *s;
1305         int len;
1306
1307         g_assert (dst != NULL);
1308         g_assert (size > 0);
1309
1310         memset (dst, 0, size);
1311         if (!src)
1312                 return;
1313
1314         s = mono_string_to_utf8 (src);
1315         len = MIN (size, strlen (s));
1316         if (len >= size)
1317                 len--;
1318         memcpy (dst, s, len);
1319         g_free (s);
1320 }
1321
1322 /**
1323  * mono_string_to_byvalwstr:
1324  * @dst: Where to store the null-terminated utf16 decoded string.
1325  * @src: the MonoString to copy.
1326  * @size: the maximum number of bytes to copy.
1327  *
1328  * Copies the MonoString pointed to by @src as a utf16 string into
1329  * @dst, it copies at most @size bytes into the destination (including
1330  * a terminating 16-bit zero terminator).
1331  */
1332 void
1333 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
1334 {
1335         int len;
1336
1337         g_assert (dst != NULL);
1338         g_assert (size > 1);
1339
1340         if (!src) {
1341                 memset (dst, 0, size * 2);
1342                 return;
1343         }
1344
1345         len = MIN (size, (mono_string_length (src)));
1346         memcpy (dst, mono_string_chars (src), size * 2);
1347         if (size <= mono_string_length (src))
1348                 len--;
1349         *((gunichar2 *) dst + len) = 0;
1350 }
1351
1352 static int
1353 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
1354 {
1355         int pos;
1356         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
1357         mono_mb_emit_byte (mb, CEE_LDIND_I);
1358         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
1359         mono_mb_emit_byte (mb, CEE_ADD);
1360         mono_mb_emit_byte (mb, CEE_LDIND_I);
1361         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1362         mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
1363         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
1364         pos = mono_mb_emit_branch (mb, branch_code);
1365         return pos;
1366 }
1367
1368 static int
1369 mono_mb_emit_xdomain_check (MonoMethodBuilder *mb, int branch_code)
1370 {
1371         int pos;
1372         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1373         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1374         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
1375         mono_mb_emit_byte (mb, CEE_LDIND_I4);
1376         mono_mb_emit_icon (mb, -1);
1377         pos = mono_mb_emit_branch (mb, branch_code);
1378         return pos;
1379 }
1380
1381 static int
1382 mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code)
1383 {
1384         static int offset = -1;
1385         static guint8 mask;
1386
1387         if (offset < 0)
1388                 mono_marshal_find_bitfield_offset (MonoClass, contextbound, &offset, &mask);
1389
1390         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
1391         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1392         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
1393         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1394         mono_mb_emit_ldflda (mb, offset);
1395         mono_mb_emit_byte (mb, CEE_LDIND_U1);
1396         mono_mb_emit_icon (mb, mask);
1397         mono_mb_emit_byte (mb, CEE_AND);
1398         mono_mb_emit_icon (mb, 0);
1399         return mono_mb_emit_branch (mb, branch_code);
1400 }
1401
1402 #ifndef DISABLE_COM
1403
1404 static void
1405 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
1406 {
1407         // get function pointer from 1st arg, the COM interface pointer
1408         mono_mb_emit_ldarg (mb, 0);
1409         mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
1410         mono_mb_emit_icall (mb, cominterop_get_function_pointer);
1411
1412         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1413         mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
1414         mono_mb_emit_calli (mb, sig);
1415         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1416         mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
1417 }
1418
1419 #endif /* DISABLE_COM */
1420
1421 static void
1422 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, const char *msg)
1423 {
1424         mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", msg);
1425 }
1426
1427 guint
1428 mono_type_to_ldind (MonoType *type)
1429 {
1430         if (type->byref)
1431                 return CEE_LDIND_I;
1432
1433 handle_enum:
1434         switch (type->type) {
1435         case MONO_TYPE_I1:
1436                 return CEE_LDIND_I1;
1437         case MONO_TYPE_U1:
1438         case MONO_TYPE_BOOLEAN:
1439                 return CEE_LDIND_U1;
1440         case MONO_TYPE_I2:
1441                 return CEE_LDIND_I2;
1442         case MONO_TYPE_U2:
1443         case MONO_TYPE_CHAR:
1444                 return CEE_LDIND_U2;
1445         case MONO_TYPE_I4:
1446                 return CEE_LDIND_I4;
1447         case MONO_TYPE_U4:
1448                 return CEE_LDIND_U4;
1449         case MONO_TYPE_I:
1450         case MONO_TYPE_U:
1451         case MONO_TYPE_PTR:
1452         case MONO_TYPE_FNPTR:
1453                 return CEE_LDIND_I;
1454         case MONO_TYPE_CLASS:
1455         case MONO_TYPE_STRING:
1456         case MONO_TYPE_OBJECT:
1457         case MONO_TYPE_SZARRAY:
1458         case MONO_TYPE_ARRAY:    
1459                 return CEE_LDIND_REF;
1460         case MONO_TYPE_I8:
1461         case MONO_TYPE_U8:
1462                 return CEE_LDIND_I8;
1463         case MONO_TYPE_R4:
1464                 return CEE_LDIND_R4;
1465         case MONO_TYPE_R8:
1466                 return CEE_LDIND_R8;
1467         case MONO_TYPE_VALUETYPE:
1468                 if (type->data.klass->enumtype) {
1469                         type = type->data.klass->enum_basetype;
1470                         goto handle_enum;
1471                 }
1472                 return CEE_LDOBJ;
1473         case MONO_TYPE_TYPEDBYREF:
1474                 return CEE_LDOBJ;
1475         case MONO_TYPE_GENERICINST:
1476                 type = &type->data.generic_class->container_class->byval_arg;
1477                 goto handle_enum;
1478         default:
1479                 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
1480         }
1481         return -1;
1482 }
1483
1484 guint
1485 mono_type_to_stind (MonoType *type)
1486 {
1487         if (type->byref)
1488                 return CEE_STIND_I;
1489
1490 handle_enum:
1491         switch (type->type) {
1492         case MONO_TYPE_I1:
1493         case MONO_TYPE_U1:
1494         case MONO_TYPE_BOOLEAN:
1495                 return CEE_STIND_I1;
1496         case MONO_TYPE_I2:
1497         case MONO_TYPE_U2:
1498         case MONO_TYPE_CHAR:
1499                 return CEE_STIND_I2;
1500         case MONO_TYPE_I4:
1501         case MONO_TYPE_U4:
1502                 return CEE_STIND_I4;
1503         case MONO_TYPE_I:
1504         case MONO_TYPE_U:
1505         case MONO_TYPE_PTR:
1506         case MONO_TYPE_FNPTR:
1507                 return CEE_STIND_I;
1508         case MONO_TYPE_CLASS:
1509         case MONO_TYPE_STRING:
1510         case MONO_TYPE_OBJECT:
1511         case MONO_TYPE_SZARRAY:
1512         case MONO_TYPE_ARRAY:    
1513                 return CEE_STIND_REF;
1514         case MONO_TYPE_I8:
1515         case MONO_TYPE_U8:
1516                 return CEE_STIND_I8;
1517         case MONO_TYPE_R4:
1518                 return CEE_STIND_R4;
1519         case MONO_TYPE_R8:
1520                 return CEE_STIND_R8;
1521         case MONO_TYPE_VALUETYPE:
1522                 if (type->data.klass->enumtype) {
1523                         type = type->data.klass->enum_basetype;
1524                         goto handle_enum;
1525                 }
1526                 return CEE_STOBJ;
1527         case MONO_TYPE_TYPEDBYREF:
1528                 return CEE_STOBJ;
1529         case MONO_TYPE_GENERICINST:
1530                 type = &type->data.generic_class->container_class->byval_arg;
1531                 goto handle_enum;
1532         default:
1533                 g_error ("unknown type 0x%02x in type_to_stind", type->type);
1534         }
1535         return -1;
1536 }
1537
1538 static void
1539 emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1540 {
1541         switch (conv) {
1542         case MONO_MARSHAL_CONV_BOOL_I4:
1543                 mono_mb_emit_ldloc (mb, 1);
1544                 mono_mb_emit_ldloc (mb, 0);
1545                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1546                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1547                 mono_mb_emit_byte (mb, 3);
1548                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1549                 mono_mb_emit_byte (mb, CEE_BR_S);
1550                 mono_mb_emit_byte (mb, 1);
1551                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1552                 mono_mb_emit_byte (mb, CEE_STIND_I1);
1553                 break;
1554         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1555                 mono_mb_emit_ldloc (mb, 1);
1556                 mono_mb_emit_ldloc (mb, 0);
1557                 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1558                 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1559                 mono_mb_emit_byte (mb, 3);
1560                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1561                 mono_mb_emit_byte (mb, CEE_BR_S);
1562                 mono_mb_emit_byte (mb, 1);
1563                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1564                 mono_mb_emit_byte (mb, CEE_STIND_I1);
1565                 break;
1566         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1567                 MonoClass *eklass = NULL;
1568                 int esize;
1569
1570                 if (type->type == MONO_TYPE_SZARRAY) {
1571                         eklass = type->data.klass;
1572                 } else {
1573                         g_assert_not_reached ();
1574                 }
1575
1576                 esize = mono_class_native_size (eklass, NULL);
1577
1578                 /* create a new array */
1579                 mono_mb_emit_ldloc (mb, 1);
1580                 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1581                 mono_mb_emit_op (mb, CEE_NEWARR, eklass);       
1582                 mono_mb_emit_byte (mb, CEE_STIND_I);
1583
1584                 if (eklass->blittable) {
1585                         /* copy the elements */
1586                         mono_mb_emit_ldloc (mb, 1);
1587                         mono_mb_emit_byte (mb, CEE_LDIND_I);
1588                         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
1589                         mono_mb_emit_byte (mb, CEE_ADD);
1590                         mono_mb_emit_ldloc (mb, 0);
1591                         mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1592                         mono_mb_emit_byte (mb, CEE_PREFIX1);
1593                         mono_mb_emit_byte (mb, CEE_CPBLK);                      
1594                 }
1595                 else {
1596                         int array_var, src_var, dst_var, index_var;
1597                         guint32 label2, label3;
1598
1599                         array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1600                         src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1601                         dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1602
1603                         /* set array_var */
1604                         mono_mb_emit_ldloc (mb, 1);
1605                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1606                         mono_mb_emit_stloc (mb, array_var);
1607                 
1608                         /* save the old src pointer */
1609                         mono_mb_emit_ldloc (mb, 0);
1610                         mono_mb_emit_stloc (mb, src_var);
1611                         /* save the old dst pointer */
1612                         mono_mb_emit_ldloc (mb, 1);
1613                         mono_mb_emit_stloc (mb, dst_var);
1614
1615                         /* Emit marshalling loop */
1616                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1617                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1618                         mono_mb_emit_stloc (mb, index_var);
1619
1620                         /* Loop header */
1621                         label2 = mono_mb_get_label (mb);
1622                         mono_mb_emit_ldloc (mb, index_var);
1623                         mono_mb_emit_ldloc (mb, array_var);
1624                         mono_mb_emit_byte (mb, CEE_LDLEN);
1625                         label3 = mono_mb_emit_branch (mb, CEE_BGE);
1626
1627                         /* src is already set */
1628
1629                         /* Set dst */
1630                         mono_mb_emit_ldloc (mb, array_var);
1631                         mono_mb_emit_ldloc (mb, index_var);
1632                         mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
1633                         mono_mb_emit_stloc (mb, 1);
1634
1635                         /* Do the conversion */
1636                         emit_struct_conv (mb, eklass, TRUE);
1637
1638                         /* Loop footer */
1639                         mono_mb_emit_add_to_local (mb, index_var, 1);
1640
1641                         mono_mb_emit_branch_label (mb, CEE_BR, label2);
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                 mono_mb_emit_ldloc (mb, 1);
1685                 mono_mb_emit_ldloc (mb, 0);
1686                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1687 #ifdef PLATFORM_WIN32
1688                 mono_mb_emit_icall (mb, mono_string_from_utf16);
1689 #else
1690                 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1691 #endif
1692                 mono_mb_emit_byte (mb, CEE_STIND_REF);  
1693                 break;
1694         case MONO_MARSHAL_CONV_STR_LPSTR:
1695                 mono_mb_emit_ldloc (mb, 1);
1696                 mono_mb_emit_ldloc (mb, 0);
1697                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1698                 mono_mb_emit_icall (mb, mono_string_new_wrapper);
1699                 mono_mb_emit_byte (mb, CEE_STIND_REF);          
1700                 break;
1701         case MONO_MARSHAL_CONV_STR_LPWSTR:
1702                 mono_mb_emit_ldloc (mb, 1);
1703                 mono_mb_emit_ldloc (mb, 0);
1704                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1705                 mono_mb_emit_icall (mb, mono_string_from_utf16);
1706                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1707                 break;
1708         case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1709                 MonoClass *klass = mono_class_from_mono_type (type);
1710                 int src_var, dst_var;
1711
1712                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1713                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1714                 
1715                 /* *dst = new object */
1716                 mono_mb_emit_ldloc (mb, 1);
1717                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1718                 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);   
1719                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1720         
1721                 /* save the old src pointer */
1722                 mono_mb_emit_ldloc (mb, 0);
1723                 mono_mb_emit_stloc (mb, src_var);
1724                 /* save the old dst pointer */
1725                 mono_mb_emit_ldloc (mb, 1);
1726                 mono_mb_emit_stloc (mb, dst_var);
1727
1728                 /* dst = pointer to newly created object data */
1729                 mono_mb_emit_ldloc (mb, 1);
1730                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1731                 mono_mb_emit_icon (mb, sizeof (MonoObject));
1732                 mono_mb_emit_byte (mb, CEE_ADD);
1733                 mono_mb_emit_stloc (mb, 1); 
1734
1735                 emit_struct_conv (mb, klass, TRUE);
1736                 
1737                 /* restore the old src pointer */
1738                 mono_mb_emit_ldloc (mb, src_var);
1739                 mono_mb_emit_stloc (mb, 0);
1740                 /* restore the old dst pointer */
1741                 mono_mb_emit_ldloc (mb, dst_var);
1742                 mono_mb_emit_stloc (mb, 1);
1743                 break;
1744         }
1745         case MONO_MARSHAL_CONV_DEL_FTN: {
1746                 MonoClass *klass = mono_class_from_mono_type (type);
1747
1748                 mono_mb_emit_ldloc (mb, 1);
1749                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1750                 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
1751                 mono_mb_emit_ldloc (mb, 0);
1752                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1753                 mono_mb_emit_icall (mb, mono_ftnptr_to_delegate);
1754                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1755                 break;
1756         }
1757         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1758                 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
1759                 break;
1760
1761 #ifndef DISABLE_COM
1762         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
1763         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
1764         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
1765                 static MonoClass* com_interop_proxy_class = NULL;
1766                 static MonoMethod* com_interop_proxy_get_proxy = NULL;
1767                 static MonoMethod* get_transparent_proxy = NULL;
1768                 int real_proxy;
1769                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1770                 MonoClass *klass = NULL; 
1771                 
1772                 /* COM types are initialized lazily */
1773                 mono_init_com_types ();
1774
1775                 klass = mono_class_from_mono_type (type);
1776
1777                 mono_mb_emit_ldloc (mb, 1);
1778                 mono_mb_emit_byte (mb, CEE_LDNULL);
1779                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1780
1781                 mono_mb_emit_ldloc (mb, 0);
1782                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1783                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1784
1785                 /* load dst to store later */
1786                 mono_mb_emit_ldloc (mb, 1);
1787
1788                 mono_mb_emit_ldloc (mb, 0);
1789                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1790                 mono_mb_emit_icon (mb, TRUE);
1791                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1792                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1793
1794                 if (!com_interop_proxy_class)
1795                         com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1796                 if (!com_interop_proxy_get_proxy)
1797                         com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
1798                 if (!get_transparent_proxy)
1799                         get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
1800
1801                 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
1802
1803                 mono_mb_emit_ldloc (mb, 0);
1804                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1805                 mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
1806                 mono_mb_emit_icall (mb, type_from_handle);
1807                 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
1808                 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
1809                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
1810                         g_assert (klass);
1811                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1812                 }
1813                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1814                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1815
1816                 /* is already managed object */
1817                 mono_mb_patch_short_branch (mb, pos_ccw);
1818                 mono_mb_emit_ldloc (mb, 0);
1819                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1820                 mono_mb_emit_icon (mb, TRUE);
1821                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1822
1823                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
1824                         g_assert (klass);
1825                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1826                 }
1827                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1828
1829                 mono_mb_patch_short_branch (mb, pos_end);
1830                 /* case if null */
1831                 mono_mb_patch_short_branch (mb, pos_null);
1832                 break;
1833         }
1834 #endif /* DISABLE_COM */
1835
1836         case MONO_MARSHAL_CONV_SAFEHANDLE: {
1837                 /*
1838                  * Passing SafeHandles as ref does not allow the unmanaged code
1839                  * to change the SafeHandle value.   If the value is changed,
1840                  * we should issue a diagnostic exception (NotSupportedException)
1841                  * that informs the user that changes to handles in unmanaged code
1842                  * is not supported. 
1843                  *
1844                  * Since we currently have no access to the original
1845                  * SafeHandle that was used during the marshalling,
1846                  * for now we just ignore this, and ignore/discard any
1847                  * changes that might have happened to the handle.
1848                  */
1849                 break;
1850         }
1851                 
1852         case MONO_MARSHAL_CONV_HANDLEREF: {
1853                 /*
1854                  * Passing HandleRefs in a struct that is ref()ed does not 
1855                  * copy the values back to the HandleRef
1856                  */
1857                 break;
1858         }
1859                 
1860         case MONO_MARSHAL_CONV_STR_BSTR:
1861         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1862         case MONO_MARSHAL_CONV_STR_TBSTR:
1863         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1864         default:
1865                 g_warning ("marshaling conversion %d not implemented", conv);
1866                 g_assert_not_reached ();
1867         }
1868 }
1869
1870 static gpointer
1871 conv_to_icall (MonoMarshalConv conv)
1872 {
1873         switch (conv) {
1874         case MONO_MARSHAL_CONV_STR_LPWSTR:
1875                 return mono_marshal_string_to_utf16;            
1876         case MONO_MARSHAL_CONV_LPWSTR_STR:
1877                 return mono_string_from_utf16;
1878         case MONO_MARSHAL_CONV_LPSTR_STR:
1879                 return mono_string_new_wrapper;
1880         case MONO_MARSHAL_CONV_STR_LPTSTR:
1881 #ifdef PLATFORM_WIN32
1882                 return mono_marshal_string_to_utf16;
1883 #else
1884                 return mono_string_to_lpstr;
1885 #endif
1886         case MONO_MARSHAL_CONV_STR_LPSTR:
1887                 return mono_string_to_lpstr;
1888         case MONO_MARSHAL_CONV_STR_BSTR:
1889                 return mono_string_to_bstr;
1890         case MONO_MARSHAL_CONV_BSTR_STR:
1891                 return mono_string_from_bstr;
1892         case MONO_MARSHAL_CONV_STR_TBSTR:
1893         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1894                 return mono_string_to_ansibstr;
1895         case MONO_MARSHAL_CONV_SB_LPSTR:
1896                 return mono_string_builder_to_utf8;
1897         case MONO_MARSHAL_CONV_SB_LPTSTR:
1898 #ifdef PLATFORM_WIN32
1899                 return mono_string_builder_to_utf16;
1900 #else
1901                 return mono_string_builder_to_utf8;
1902 #endif
1903         case MONO_MARSHAL_CONV_SB_LPWSTR:
1904                 return mono_string_builder_to_utf16;
1905         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1906                 return mono_array_to_savearray;
1907         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1908                 return mono_array_to_lparray;
1909         case MONO_MARSHAL_CONV_DEL_FTN:
1910                 return mono_delegate_to_ftnptr;
1911         case MONO_MARSHAL_CONV_FTN_DEL:
1912                 return mono_ftnptr_to_delegate;
1913         case MONO_MARSHAL_CONV_LPSTR_SB:
1914                 return mono_string_utf8_to_builder;
1915         case MONO_MARSHAL_CONV_LPTSTR_SB:
1916 #ifdef PLATFORM_WIN32
1917                 return mono_string_utf16_to_builder;
1918 #else
1919                 return mono_string_utf8_to_builder;
1920 #endif
1921         case MONO_MARSHAL_CONV_LPWSTR_SB:
1922                 return mono_string_utf16_to_builder;
1923         case MONO_MARSHAL_FREE_ARRAY:
1924                 return mono_marshal_free_array;
1925         case MONO_MARSHAL_CONV_STR_BYVALSTR:
1926                 return mono_string_to_byvalstr;
1927         case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1928                 return mono_string_to_byvalwstr;
1929         default:
1930                 g_assert_not_reached ();
1931         }
1932
1933         return NULL;
1934 }
1935
1936 static void
1937 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1938 {
1939         int pos;
1940
1941         switch (conv) {
1942         case MONO_MARSHAL_CONV_BOOL_I4:
1943                 mono_mb_emit_ldloc (mb, 1);
1944                 mono_mb_emit_ldloc (mb, 0);
1945                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1946                 mono_mb_emit_byte (mb, CEE_STIND_I4);
1947                 break;
1948         case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1949                 mono_mb_emit_ldloc (mb, 1);
1950                 mono_mb_emit_ldloc (mb, 0);
1951                 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1952                 mono_mb_emit_byte (mb, CEE_NEG);
1953                 mono_mb_emit_byte (mb, CEE_STIND_I2);
1954                 break;
1955         case MONO_MARSHAL_CONV_STR_LPWSTR:
1956         case MONO_MARSHAL_CONV_STR_LPSTR:
1957         case MONO_MARSHAL_CONV_STR_LPTSTR:
1958         case MONO_MARSHAL_CONV_STR_BSTR:
1959         case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1960         case MONO_MARSHAL_CONV_STR_TBSTR: {
1961                 int pos;
1962
1963                 /* free space if free == true */
1964                 mono_mb_emit_ldloc (mb, 2);
1965                 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1966                 mono_mb_emit_ldloc (mb, 1);
1967                 mono_mb_emit_byte (mb, CEE_LDIND_I);
1968                 mono_mb_emit_icall (mb, g_free);
1969                 mono_mb_patch_short_branch (mb, pos);
1970
1971                 mono_mb_emit_ldloc (mb, 1);
1972                 mono_mb_emit_ldloc (mb, 0);
1973                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1974                 mono_mb_emit_icall (mb, conv_to_icall (conv));
1975                 mono_mb_emit_byte (mb, CEE_STIND_I);    
1976                 break;
1977         }
1978         case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1979         case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1980         case MONO_MARSHAL_CONV_DEL_FTN:
1981                 mono_mb_emit_ldloc (mb, 1);
1982                 mono_mb_emit_ldloc (mb, 0);
1983                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1984                 mono_mb_emit_icall (mb, conv_to_icall (conv));
1985                 mono_mb_emit_byte (mb, CEE_STIND_I);    
1986                 break;
1987         case MONO_MARSHAL_CONV_STR_BYVALSTR: 
1988         case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
1989                 g_assert (mspec);
1990
1991                 mono_mb_emit_ldloc (mb, 1); /* dst */
1992                 mono_mb_emit_ldloc (mb, 0);     
1993                 mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
1994                 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1995                 mono_mb_emit_icall (mb, conv_to_icall (conv));
1996                 break;
1997         }
1998         case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1999                 MonoClass *eklass = NULL;
2000                 int esize;
2001
2002                 if (type->type == MONO_TYPE_SZARRAY) {
2003                         eklass = type->data.klass;
2004                 } else {
2005                         g_assert_not_reached ();
2006                 }
2007
2008                 if (eklass->valuetype)
2009                         esize = mono_class_native_size (eklass, NULL);
2010                 else
2011                         esize = sizeof (gpointer);
2012
2013                 mono_mb_emit_ldloc (mb, 0);
2014                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2015                 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
2016
2017                 if (eklass->blittable) {
2018                         mono_mb_emit_ldloc (mb, 1);
2019                         mono_mb_emit_ldloc (mb, 0);     
2020                         mono_mb_emit_byte (mb, CEE_LDIND_REF);  
2021                         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
2022                         mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
2023                         mono_mb_emit_byte (mb, CEE_PREFIX1);
2024                         mono_mb_emit_byte (mb, CEE_CPBLK);                      
2025                 } else {
2026                         int array_var, src_var, dst_var, index_var;
2027                         guint32 label2, label3;
2028
2029                         array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2030                         src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2031                         dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2032
2033                         /* set array_var */
2034                         mono_mb_emit_ldloc (mb, 0);     
2035                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
2036                         mono_mb_emit_stloc (mb, array_var);
2037
2038                         /* save the old src pointer */
2039                         mono_mb_emit_ldloc (mb, 0);
2040                         mono_mb_emit_stloc (mb, src_var);
2041                         /* save the old dst pointer */
2042                         mono_mb_emit_ldloc (mb, 1);
2043                         mono_mb_emit_stloc (mb, dst_var);
2044
2045                         /* Emit marshalling loop */
2046                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2047                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2048                         mono_mb_emit_stloc (mb, index_var);
2049
2050                         /* Loop header */
2051                         label2 = mono_mb_get_label (mb);
2052                         mono_mb_emit_ldloc (mb, index_var);
2053                         mono_mb_emit_ldloc (mb, array_var);
2054                         mono_mb_emit_byte (mb, CEE_LDLEN);
2055                         label3 = mono_mb_emit_branch (mb, CEE_BGE);
2056
2057                         /* Set src */
2058                         mono_mb_emit_ldloc (mb, array_var);
2059                         mono_mb_emit_ldloc (mb, index_var);
2060                         mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
2061                         mono_mb_emit_stloc (mb, 0);
2062
2063                         /* dst is already set */
2064
2065                         /* Do the conversion */
2066                         emit_struct_conv (mb, eklass, FALSE);
2067
2068                         /* Loop footer */
2069                         mono_mb_emit_add_to_local (mb, index_var, 1);
2070
2071                         mono_mb_emit_branch_label (mb, CEE_BR, label2);
2072
2073                         mono_mb_patch_branch (mb, label3);
2074                 
2075                         /* restore the old src pointer */
2076                         mono_mb_emit_ldloc (mb, src_var);
2077                         mono_mb_emit_stloc (mb, 0);
2078                         /* restore the old dst pointer */
2079                         mono_mb_emit_ldloc (mb, dst_var);
2080                         mono_mb_emit_stloc (mb, 1);
2081                 }
2082
2083                 mono_mb_patch_branch (mb, pos);
2084                 break;
2085         }
2086         case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
2087                 mono_mb_emit_ldloc (mb, 0);
2088                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2089                 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2090
2091                 mono_mb_emit_ldloc (mb, 1);
2092                 mono_mb_emit_ldloc (mb, 0);     
2093                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2094                 mono_mb_emit_ptr (mb, mono_defaults.byte_class);
2095                 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
2096                 mono_mb_emit_icall (mb, mono_array_to_byvalarray);
2097                 mono_mb_patch_short_branch (mb, pos);
2098                 break;
2099         }
2100         case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
2101                 int src_var, dst_var;
2102
2103                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2104                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2105                 
2106                 mono_mb_emit_ldloc (mb, 0);
2107                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2108                 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
2109                 
2110                 /* save the old src pointer */
2111                 mono_mb_emit_ldloc (mb, 0);
2112                 mono_mb_emit_stloc (mb, src_var);
2113                 /* save the old dst pointer */
2114                 mono_mb_emit_ldloc (mb, 1);
2115                 mono_mb_emit_stloc (mb, dst_var);
2116
2117                 /* src = pointer to object data */
2118                 mono_mb_emit_ldloc (mb, 0);
2119                 mono_mb_emit_byte (mb, CEE_LDIND_I);            
2120                 mono_mb_emit_icon (mb, sizeof (MonoObject));
2121                 mono_mb_emit_byte (mb, CEE_ADD);
2122                 mono_mb_emit_stloc (mb, 0); 
2123
2124                 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
2125                 
2126                 /* restore the old src pointer */
2127                 mono_mb_emit_ldloc (mb, src_var);
2128                 mono_mb_emit_stloc (mb, 0);
2129                 /* restore the old dst pointer */
2130                 mono_mb_emit_ldloc (mb, dst_var);
2131                 mono_mb_emit_stloc (mb, 1);
2132
2133                 mono_mb_patch_branch (mb, pos);
2134                 break;
2135         }
2136
2137 #ifndef DISABLE_COM
2138         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
2139         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
2140         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
2141                 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
2142  
2143                 /* COM types are initialized lazily */
2144                 mono_init_com_types ();
2145
2146
2147                 mono_mb_emit_ldloc (mb, 1);
2148                 mono_mb_emit_icon (mb, 0);
2149                 mono_mb_emit_byte (mb, CEE_CONV_U);
2150                 mono_mb_emit_byte (mb, CEE_STIND_I);
2151
2152                 mono_mb_emit_ldloc (mb, 0);     
2153                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2154
2155                 // if null just break, dst was already inited to 0
2156                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2157
2158                 mono_mb_emit_ldloc (mb, 0);     
2159                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2160                 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
2161                 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2162
2163                 // load dst to store later
2164                 mono_mb_emit_ldloc (mb, 1);
2165
2166                 // load src
2167                 mono_mb_emit_ldloc (mb, 0);     
2168                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2169                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
2170                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2171
2172                 /* load the RCW from the ComInteropProxy*/
2173                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
2174                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2175
2176                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
2177                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
2178                         mono_mb_emit_icon (mb, TRUE);
2179                         mono_mb_emit_icall (mb, cominterop_get_interface);
2180
2181                 }
2182                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
2183                         static MonoProperty* iunknown = NULL;
2184                         
2185                         if (!iunknown)
2186                                 iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
2187                         mono_mb_emit_managed_call (mb, iunknown->get, NULL);
2188                 }
2189                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
2190                         static MonoProperty* idispatch = NULL;
2191                         
2192                         if (!idispatch)
2193                                 idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
2194                         mono_mb_emit_managed_call (mb, idispatch->get, NULL);
2195                 }
2196                 else {
2197                         g_assert_not_reached ();
2198                 }
2199                 mono_mb_emit_byte (mb, CEE_STIND_I);
2200                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
2201                 
2202                 // if not rcw
2203                 mono_mb_patch_short_branch (mb, pos_rcw);
2204                 /* load dst to store later */
2205                 mono_mb_emit_ldloc (mb, 1);
2206                 /* load src */
2207                 mono_mb_emit_ldloc (mb, 0);     
2208                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2209                 
2210                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
2211                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
2212                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
2213                         mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
2214                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
2215                         mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
2216                 else
2217                         g_assert_not_reached ();
2218                 mono_mb_emit_icall (mb, cominterop_get_ccw);
2219                 mono_mb_emit_byte (mb, CEE_STIND_I);
2220
2221                 mono_mb_patch_short_branch (mb, pos_end);
2222                 mono_mb_patch_short_branch (mb, pos_null);
2223                 break;
2224         }
2225 #endif /* DISABLE_COM */
2226
2227         case MONO_MARSHAL_CONV_SAFEHANDLE: {
2228                 int dar_release_slot, pos;
2229                 
2230                 dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
2231
2232                 /*
2233                  * The following is ifdefed-out, because I have no way of doing the
2234                  * DangerousRelease when destroying the structure
2235                  */
2236 #if 0
2237                 /* set release = false */
2238                 mono_mb_emit_icon (mb, 0);
2239                 mono_mb_emit_stloc (mb, dar_release_slot);
2240                 if (!sh_dangerous_add_ref)
2241                         init_safe_handle ();
2242
2243                 /* safehandle.DangerousAddRef (ref release) */
2244                 mono_mb_emit_ldloc (mb, 0); /* the source */
2245                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2246                 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
2247                 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
2248 #endif
2249                 mono_mb_emit_ldloc (mb, 0);
2250                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2251                 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
2252                 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
2253                 mono_mb_patch_branch (mb, pos);
2254                 
2255                 /* Pull the handle field from SafeHandle */
2256                 mono_mb_emit_ldloc (mb, 1);
2257                 mono_mb_emit_ldloc (mb, 0);
2258                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2259                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
2260                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2261                 mono_mb_emit_byte (mb, CEE_STIND_I);
2262                 break;
2263         }
2264
2265         case MONO_MARSHAL_CONV_HANDLEREF: {
2266                 mono_mb_emit_ldloc (mb, 1);
2267                 mono_mb_emit_ldloc (mb, 0);
2268                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
2269                 mono_mb_emit_byte (mb, CEE_ADD);
2270                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2271                 mono_mb_emit_byte (mb, CEE_STIND_I);
2272                 break;
2273         }
2274                 
2275         default: {
2276                 char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
2277                 MonoException *exc = mono_get_exception_not_implemented (msg);
2278                 g_warning (msg);
2279                 g_free (msg);
2280                 mono_raise_exception (exc);
2281         }
2282         }
2283 }
2284
2285 static void
2286 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
2287 {
2288         MonoMarshalType *info;
2289         int i;
2290
2291         if (klass->parent)
2292                 emit_struct_conv(mb, klass->parent, to_object);
2293
2294         info = mono_marshal_load_type_info (klass);
2295
2296         if (info->native_size == 0)
2297                 return;
2298
2299         if (klass->blittable) {
2300                 int msize = mono_class_value_size (klass, NULL);
2301                 g_assert (msize == info->native_size);
2302                 mono_mb_emit_ldloc (mb, 1);
2303                 mono_mb_emit_ldloc (mb, 0);
2304                 mono_mb_emit_icon (mb, msize);
2305                 mono_mb_emit_byte (mb, CEE_PREFIX1);
2306                 mono_mb_emit_byte (mb, CEE_CPBLK);
2307
2308                 mono_mb_emit_add_to_local (mb, 0, msize);
2309                 mono_mb_emit_add_to_local (mb, 1, msize);
2310                 return;
2311         }
2312
2313         for (i = 0; i < info->num_fields; i++) {
2314                 MonoMarshalNative ntype;
2315                 MonoMarshalConv conv;
2316                 MonoType *ftype = info->fields [i].field->type;
2317                 int msize = 0;
2318                 int usize = 0;
2319                 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
2320
2321                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
2322                         continue;
2323
2324                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
2325
2326                 if (last_field) {
2327                         msize = klass->instance_size - info->fields [i].field->offset;
2328                         usize = info->native_size - info->fields [i].offset;
2329                 } else {
2330                         msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
2331                         usize = info->fields [i + 1].offset - info->fields [i].offset;
2332                 }
2333
2334                 if (klass != mono_defaults.safehandle_class){
2335                         /* 
2336                          * FIXME: Should really check for usize==0 and msize>0, but we apply 
2337                          * the layout to the managed structure as well.
2338                          */
2339                         
2340                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
2341                                 if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
2342                                     ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
2343                                         g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
2344                                                  "reference field at the same offset as another field.",
2345                                                  mono_type_full_name (&klass->byval_arg));
2346                         }
2347                         
2348                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
2349                                 g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute",
2350                                          mono_type_full_name (&klass->byval_arg));
2351                         
2352                 }
2353                 
2354                 switch (conv) {
2355                 case MONO_MARSHAL_CONV_NONE: {
2356                         int t;
2357
2358                         if (ftype->byref || ftype->type == MONO_TYPE_I ||
2359                             ftype->type == MONO_TYPE_U) {
2360                                 mono_mb_emit_ldloc (mb, 1);
2361                                 mono_mb_emit_ldloc (mb, 0);
2362                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
2363                                 mono_mb_emit_byte (mb, CEE_STIND_I);
2364                                 break;
2365                         }
2366
2367                 handle_enum:
2368                         t = ftype->type;
2369                         switch (t) {
2370                         case MONO_TYPE_I4:
2371                         case MONO_TYPE_U4:
2372                         case MONO_TYPE_I1:
2373                         case MONO_TYPE_U1:
2374                         case MONO_TYPE_BOOLEAN:
2375                         case MONO_TYPE_I2:
2376                         case MONO_TYPE_U2:
2377                         case MONO_TYPE_CHAR:
2378                         case MONO_TYPE_I8:
2379                         case MONO_TYPE_U8:
2380                         case MONO_TYPE_PTR:
2381                         case MONO_TYPE_R4:
2382                         case MONO_TYPE_R8:
2383                                 mono_mb_emit_ldloc (mb, 1);
2384                                 mono_mb_emit_ldloc (mb, 0);
2385                                 mono_mb_emit_byte (mb, mono_type_to_ldind (ftype));
2386                                 mono_mb_emit_byte (mb, mono_type_to_stind (ftype));
2387                                 break;
2388                         case MONO_TYPE_VALUETYPE: {
2389                                 int src_var, dst_var;
2390
2391                                 if (ftype->data.klass->enumtype) {
2392                                         ftype = ftype->data.klass->enum_basetype;
2393                                         goto handle_enum;
2394                                 }
2395
2396                                 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2397                                 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2398         
2399                                 /* save the old src pointer */
2400                                 mono_mb_emit_ldloc (mb, 0);
2401                                 mono_mb_emit_stloc (mb, src_var);
2402                                 /* save the old dst pointer */
2403                                 mono_mb_emit_ldloc (mb, 1);
2404                                 mono_mb_emit_stloc (mb, dst_var);
2405
2406                                 emit_struct_conv (mb, ftype->data.klass, to_object);
2407
2408                                 /* restore the old src pointer */
2409                                 mono_mb_emit_ldloc (mb, src_var);
2410                                 mono_mb_emit_stloc (mb, 0);
2411                                 /* restore the old dst pointer */
2412                                 mono_mb_emit_ldloc (mb, dst_var);
2413                                 mono_mb_emit_stloc (mb, 1);
2414                                 break;
2415                         }
2416                         case MONO_TYPE_OBJECT: {
2417                                 mono_init_com_types ();
2418                                 if (to_object) {
2419                                         static MonoMethod *variant_clear = NULL;
2420                                         static MonoMethod *get_object_for_native_variant = NULL;
2421
2422                                         if (!variant_clear)
2423                                                 variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
2424                                         if (!get_object_for_native_variant)
2425                                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2426                                         mono_mb_emit_ldloc (mb, 1);
2427                                         mono_mb_emit_ldloc (mb, 0);
2428                                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2429                                         mono_mb_emit_byte (mb, CEE_STIND_REF);
2430
2431                                         mono_mb_emit_ldloc (mb, 0);
2432                                         mono_mb_emit_managed_call (mb, variant_clear, NULL);
2433                                 }
2434                                 else {
2435                                         static MonoMethod *get_native_variant_for_object = NULL;
2436
2437                                         if (!get_native_variant_for_object)
2438                                                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2439
2440                                         mono_mb_emit_ldloc (mb, 0);
2441                                         mono_mb_emit_byte(mb, CEE_LDIND_REF);
2442                                         mono_mb_emit_ldloc (mb, 1);
2443                                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2444                                         }
2445                                 break;
2446                         }
2447
2448                         default: 
2449                                 g_warning ("marshaling type %02x not implemented", ftype->type);
2450                                 g_assert_not_reached ();
2451                         }
2452                         break;
2453                 }
2454                 default: {
2455                         int src_var, dst_var;
2456
2457                         src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2458                         dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2459
2460                         /* save the old src pointer */
2461                         mono_mb_emit_ldloc (mb, 0);
2462                         mono_mb_emit_stloc (mb, src_var);
2463                         /* save the old dst pointer */
2464                         mono_mb_emit_ldloc (mb, 1);
2465                         mono_mb_emit_stloc (mb, dst_var);
2466
2467                         if (to_object) 
2468                                 emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec);
2469                         else
2470                                 emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec);
2471
2472                         /* restore the old src pointer */
2473                         mono_mb_emit_ldloc (mb, src_var);
2474                         mono_mb_emit_stloc (mb, 0);
2475                         /* restore the old dst pointer */
2476                         mono_mb_emit_ldloc (mb, dst_var);
2477                         mono_mb_emit_stloc (mb, 1);
2478                 }
2479                 }
2480
2481                 if (to_object) {
2482                         mono_mb_emit_add_to_local (mb, 0, usize);
2483                         mono_mb_emit_add_to_local (mb, 1, msize);
2484                 } else {
2485                         mono_mb_emit_add_to_local (mb, 0, msize);
2486                         mono_mb_emit_add_to_local (mb, 1, usize);
2487                 }                               
2488         }
2489 }
2490
2491 static void
2492 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
2493 {
2494         /* Call DestroyStructure */
2495         /* FIXME: Only do this if needed */
2496         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2497         mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
2498         mono_mb_emit_ldloc (mb, struct_var);
2499         mono_mb_emit_icall (mb, mono_struct_delete_old);
2500 }
2501
2502 static void
2503 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoint_func)
2504 {
2505         int pos_noabort;
2506
2507         mono_mb_emit_ptr (mb, (gpointer) mono_thread_interruption_request_flag ());
2508         mono_mb_emit_byte (mb, CEE_LDIND_U4);
2509         pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
2510
2511         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2512         mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
2513
2514         mono_mb_emit_icall (mb, checkpoint_func);
2515         
2516         mono_mb_patch_branch (mb, pos_noabort);
2517 }
2518
2519 static void
2520 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
2521 {
2522         if (strstr (mb->name, "mono_thread_interruption_checkpoint"))
2523                 return;
2524         
2525         emit_thread_interrupt_checkpoint_call (mb, mono_thread_interruption_checkpoint);
2526 }
2527
2528 static void
2529 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
2530 {
2531         emit_thread_interrupt_checkpoint_call (mb, mono_thread_force_interruption_checkpoint);
2532 }
2533
2534 static MonoAsyncResult *
2535 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
2536 {
2537         MonoMethodMessage *msg;
2538         MonoDelegate *async_callback;
2539         MonoObject *state;
2540         MonoMethod *im;
2541         MonoClass *klass;
2542         MonoMethod *method = NULL, *method2 = NULL;
2543
2544         g_assert (delegate);
2545
2546         if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
2547
2548                 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
2549                 if (!tp->remote_class->proxy_class->contextbound || tp->rp->context != (MonoObject *) mono_context_get ()) {
2550
2551                         /* If the target is a proxy, make a direct call. Is proxy's work
2552                         // to make the call asynchronous.
2553                         */
2554                         MonoAsyncResult *ares;
2555                         MonoObject *exc;
2556                         MonoArray *out_args;
2557                         HANDLE handle;
2558                         method = delegate->method;
2559
2560                         msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
2561                         handle = CreateEvent (NULL, TRUE, FALSE, NULL);
2562                         g_assert(handle != NULL);
2563                         ares = mono_async_result_new (mono_domain_get (), handle, state, handle, NULL);
2564                         MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
2565                         MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
2566                         MONO_OBJECT_SETREF (msg, async_result, ares);
2567                         msg->call_type = CallType_BeginInvoke;
2568
2569                         mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
2570                         return ares;
2571                 }
2572         }
2573
2574         klass = delegate->object.vtable->klass;
2575
2576         method = mono_get_delegate_invoke (klass);
2577         method2 = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
2578         if (method2)
2579                 method = method2;
2580         g_assert (method != NULL);
2581
2582         im = mono_get_delegate_invoke (method->klass);
2583         msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
2584
2585         return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
2586 }
2587
2588 static int
2589 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
2590 {
2591         int i, params_var, tmp_var;
2592
2593         /* allocate local (pointer) *params[] */
2594         params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2595         /* allocate local (pointer) tmp */
2596         tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2597
2598         /* alloate space on stack to store an array of pointers to the arguments */
2599         mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
2600         mono_mb_emit_byte (mb, CEE_PREFIX1);
2601         mono_mb_emit_byte (mb, CEE_LOCALLOC);
2602         mono_mb_emit_stloc (mb, params_var);
2603
2604         /* tmp = params */
2605         mono_mb_emit_ldloc (mb, params_var);
2606         mono_mb_emit_stloc (mb, tmp_var);
2607
2608         if (save_this && sig->hasthis) {
2609                 mono_mb_emit_ldloc (mb, tmp_var);
2610                 mono_mb_emit_ldarg_addr (mb, 0);
2611                 mono_mb_emit_byte (mb, CEE_STIND_I);
2612                 /* tmp = tmp + sizeof (gpointer) */
2613                 if (sig->param_count)
2614                         mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
2615
2616         }
2617
2618         for (i = 0; i < sig->param_count; i++) {
2619                 mono_mb_emit_ldloc (mb, tmp_var);
2620                 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
2621                 mono_mb_emit_byte (mb, CEE_STIND_I);
2622                 /* tmp = tmp + sizeof (gpointer) */
2623                 if (i < (sig->param_count - 1))
2624                         mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
2625         }
2626
2627         return params_var;
2628 }
2629
2630 static char*
2631 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
2632 {
2633         int i;
2634         char *result;
2635         GString *res = g_string_new ("");
2636
2637         if (prefix) {
2638                 g_string_append (res, prefix);
2639                 g_string_append_c (res, '_');
2640         }
2641
2642         mono_type_get_desc (res, sig->ret, FALSE);
2643
2644         if (sig->hasthis)
2645                 g_string_append (res, "__this__");
2646
2647         for (i = 0; i < sig->param_count; ++i) {
2648                 g_string_append_c (res, '_');
2649                 mono_type_get_desc (res, sig->params [i], FALSE);
2650         }
2651         result = res->str;
2652         g_string_free (res, FALSE);
2653         return result;
2654 }
2655
2656 /**
2657  * mono_marshal_get_string_encoding:
2658  *
2659  *  Return the string encoding which should be used for a given parameter.
2660  */
2661 static MonoMarshalNative
2662 mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2663 {
2664         /* First try the parameter marshal info */
2665         if (spec) {
2666                 if (spec->native == MONO_NATIVE_LPARRAY) {
2667                         if ((spec->data.array_data.elem_type != 0) && (spec->data.array_data.elem_type != MONO_NATIVE_MAX))
2668                                 return spec->data.array_data.elem_type;
2669                 }
2670                 else
2671                         return spec->native;
2672         }
2673
2674         if (!piinfo)
2675                 return MONO_NATIVE_LPSTR;
2676
2677         /* Then try the method level marshal info */
2678         switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
2679         case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
2680                 return MONO_NATIVE_LPSTR;
2681         case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
2682                 return MONO_NATIVE_LPWSTR;
2683         case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
2684 #ifdef PLATFORM_WIN32
2685                 return MONO_NATIVE_LPWSTR;
2686 #else
2687                 return MONO_NATIVE_LPSTR;
2688 #endif
2689         default:
2690                 return MONO_NATIVE_LPSTR;
2691         }
2692 }
2693
2694 static MonoMarshalConv
2695 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2696 {
2697         MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2698
2699         switch (encoding) {
2700         case MONO_NATIVE_LPWSTR:
2701                 return MONO_MARSHAL_CONV_STR_LPWSTR;
2702         case MONO_NATIVE_LPSTR:
2703                 return MONO_MARSHAL_CONV_STR_LPSTR;
2704         case MONO_NATIVE_LPTSTR:
2705                 return MONO_MARSHAL_CONV_STR_LPTSTR;
2706         case MONO_NATIVE_BSTR:
2707                 return MONO_MARSHAL_CONV_STR_BSTR;
2708         default:
2709                 return -1;
2710         }
2711 }
2712
2713 static MonoMarshalConv
2714 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2715 {
2716         MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2717
2718         switch (encoding) {
2719         case MONO_NATIVE_LPWSTR:
2720                 return MONO_MARSHAL_CONV_SB_LPWSTR;
2721                 break;
2722         case MONO_NATIVE_LPSTR:
2723                 return MONO_MARSHAL_CONV_SB_LPSTR;
2724                 break;
2725         case MONO_NATIVE_LPTSTR:
2726                 return MONO_MARSHAL_CONV_SB_LPTSTR;
2727                 break;
2728         default:
2729                 return -1;
2730         }
2731 }
2732
2733 static MonoMarshalConv
2734 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
2735 {
2736         MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2737
2738         *need_free = TRUE;
2739
2740         switch (encoding) {
2741         case MONO_NATIVE_LPWSTR:
2742                 *need_free = FALSE;
2743                 return MONO_MARSHAL_CONV_LPWSTR_STR;
2744         case MONO_NATIVE_LPSTR:
2745                 return MONO_MARSHAL_CONV_LPSTR_STR;
2746         case MONO_NATIVE_LPTSTR:
2747                 return MONO_MARSHAL_CONV_LPTSTR_STR;
2748         case MONO_NATIVE_BSTR:
2749                 return MONO_MARSHAL_CONV_BSTR_STR;
2750         default:
2751                 return -1;
2752         }
2753 }
2754
2755 static MonoMarshalConv
2756 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
2757 {
2758         MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2759
2760         *need_free = TRUE;
2761
2762         switch (encoding) {
2763         case MONO_NATIVE_LPWSTR:
2764                 /* 
2765                  * mono_string_builder_to_utf16 does not allocate a 
2766                  * new buffer, so no need to free it.
2767                  */
2768                 *need_free = FALSE;
2769                 return MONO_MARSHAL_CONV_LPWSTR_SB;
2770         case MONO_NATIVE_LPSTR:
2771                 return MONO_MARSHAL_CONV_LPSTR_SB;
2772                 break;
2773         case MONO_NATIVE_LPTSTR:
2774                 return MONO_MARSHAL_CONV_LPTSTR_SB;
2775                 break;
2776         default:
2777                 return -1;
2778         }
2779 }
2780
2781 /*
2782  * Return whenever a field of a native structure or an array member needs to 
2783  * be freed.
2784  */
2785 static gboolean
2786 mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2787 {
2788         MonoMarshalNative encoding;
2789         MonoMarshalConv conv;
2790
2791         switch (t->type) {
2792         case MONO_TYPE_VALUETYPE:
2793                 /* FIXME: Optimize this */
2794                 return TRUE;
2795         case MONO_TYPE_OBJECT:
2796         case MONO_TYPE_CLASS:
2797                 if (t->data.klass == mono_defaults.stringbuilder_class) {
2798                         gboolean need_free;
2799                         conv = mono_marshal_get_ptr_to_stringbuilder_conv (piinfo, spec, &need_free);
2800                         return need_free;
2801                 }
2802                 return FALSE;
2803         case MONO_TYPE_STRING:
2804                 encoding = mono_marshal_get_string_encoding (piinfo, spec);
2805                 return (encoding == MONO_NATIVE_LPWSTR) ? FALSE : TRUE;
2806         default:
2807                 return FALSE;
2808         }
2809 }
2810
2811 /*
2812  * Return the hash table pointed to by VAR, lazily creating it if neccesary.
2813  */
2814 static GHashTable*
2815 get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
2816 {
2817         if (!(*var)) {
2818                 mono_marshal_lock ();
2819                 if (!(*var)) {
2820                         GHashTable *cache = 
2821                                 g_hash_table_new (hash_func, equal_func);
2822                         mono_memory_barrier ();
2823                         *var = cache;
2824                 }
2825                 mono_marshal_unlock ();
2826         }
2827         return *var;
2828 }
2829
2830 static inline MonoMethod*
2831 mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
2832 {
2833         MonoMethod *res;
2834
2835         mono_marshal_lock ();
2836         res = g_hash_table_lookup (cache, key);
2837         mono_marshal_unlock ();
2838         return res;
2839 }
2840
2841 static void
2842 mono_marshal_method_set_wrapper_data (MonoMethod *method, gpointer data)
2843 {
2844         void **datav;
2845         /* assert */
2846         if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2847                 return;
2848
2849         datav = ((MonoMethodWrapper *)method)->method_data;
2850         datav [1] = data;
2851 }
2852
2853 /* Create the method from the builder and place it in the cache */
2854 static inline MonoMethod*
2855 mono_mb_create_and_cache (GHashTable *cache, gpointer key,
2856                                                            MonoMethodBuilder *mb, MonoMethodSignature *sig,
2857                                                            int max_stack)
2858 {
2859         MonoMethod *res;
2860
2861         mono_marshal_lock ();
2862         res = g_hash_table_lookup (cache, key);
2863         mono_marshal_unlock ();
2864         if (!res) {
2865                 MonoMethod *newm;
2866                 newm = mono_mb_create_method (mb, sig, max_stack);
2867                 mono_marshal_lock ();
2868                 res = g_hash_table_lookup (cache, key);
2869                 if (!res) {
2870                         res = newm;
2871                         g_hash_table_insert (cache, key, res);
2872                         mono_marshal_method_set_wrapper_data (res, key);
2873                         mono_marshal_unlock ();
2874                 } else {
2875                         mono_marshal_unlock ();
2876                         mono_free_method (newm);
2877                 }
2878         }
2879
2880         return res;
2881 }               
2882
2883
2884 static inline MonoMethod*
2885 mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type)
2886 {
2887         MonoMethod *res = NULL;
2888         MonoRemotingMethods *wrps;
2889
2890         mono_marshal_lock ();
2891         if (method->klass->image->remoting_invoke_cache)
2892                 wrps = g_hash_table_lookup (method->klass->image->remoting_invoke_cache, method);
2893         else
2894                 wrps = NULL;
2895
2896         if (wrps) {
2897                 switch (wrapper_type) {
2898                 case MONO_WRAPPER_REMOTING_INVOKE: res = wrps->invoke; break;
2899                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = wrps->invoke_with_check; break;
2900                 case MONO_WRAPPER_XDOMAIN_INVOKE: res = wrps->xdomain_invoke; break;
2901                 case MONO_WRAPPER_XDOMAIN_DISPATCH: res = wrps->xdomain_dispatch; break;
2902                 }
2903         }
2904         
2905         /* it is important to do the unlock after the load from wrps, since in
2906          * mono_remoting_mb_create_and_cache () we drop the marshal lock to be able
2907          * to take the loader lock and some other thread may set the fields.
2908          */
2909         mono_marshal_unlock ();
2910         return res;
2911 }
2912
2913 /* Create the method from the builder and place it in the cache */
2914 static inline MonoMethod*
2915 mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb, 
2916                                                                 MonoMethodSignature *sig, int max_stack)
2917 {
2918         MonoMethod **res = NULL;
2919         MonoRemotingMethods *wrps;
2920         GHashTable *cache = get_cache (&key->klass->image->remoting_invoke_cache, mono_aligned_addr_hash, NULL);
2921
2922         mono_marshal_lock ();
2923         wrps = g_hash_table_lookup (cache, key);
2924         if (!wrps) {
2925                 wrps = g_new0 (MonoRemotingMethods, 1);
2926                 g_hash_table_insert (cache, key, wrps);
2927         }
2928
2929         switch (mb->method->wrapper_type) {
2930         case MONO_WRAPPER_REMOTING_INVOKE: res = &wrps->invoke; break;
2931         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = &wrps->invoke_with_check; break;
2932         case MONO_WRAPPER_XDOMAIN_INVOKE: res = &wrps->xdomain_invoke; break;
2933         case MONO_WRAPPER_XDOMAIN_DISPATCH: res = &wrps->xdomain_dispatch; break;
2934         default: g_assert_not_reached (); break;
2935         }
2936         mono_marshal_unlock ();
2937
2938         if (*res == NULL) {
2939                 MonoMethod *newm;
2940                 newm = mono_mb_create_method (mb, sig, max_stack);
2941
2942                 mono_marshal_lock ();
2943                 if (!*res) {
2944                         *res = newm;
2945                         mono_marshal_method_set_wrapper_data (*res, key);
2946                         mono_marshal_unlock ();
2947                 } else {
2948                         mono_marshal_unlock ();
2949                         mono_free_method (newm);
2950                 }
2951         }
2952
2953         return *res;
2954 }               
2955
2956 MonoMethod *
2957 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
2958 {
2959         gpointer res;
2960
2961         if (wrapper->wrapper_type == MONO_WRAPPER_NONE || wrapper->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2962                 return wrapper;
2963
2964         res = mono_method_get_wrapper_data (wrapper, 1);
2965         if (res == NULL)
2966                 return wrapper;
2967         return res;
2968 }
2969
2970 MonoMethod *
2971 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
2972 {
2973         MonoMethodSignature *sig;
2974         MonoMethodBuilder *mb;
2975         MonoMethod *res;
2976         GHashTable *cache;
2977         int params_var;
2978         char *name;
2979
2980         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
2981                   !strcmp (method->name, "BeginInvoke"));
2982
2983         sig = mono_signature_no_pinvoke (method);
2984
2985         cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
2986                                            (GHashFunc)mono_signature_hash, 
2987                                            (GCompareFunc)mono_metadata_signature_equal);
2988         if ((res = mono_marshal_find_in_cache (cache, sig)))
2989                 return res;
2990
2991         g_assert (sig->hasthis);
2992
2993         name = mono_signature_to_name (sig, "begin_invoke");
2994         mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
2995         g_free (name);
2996
2997         params_var = mono_mb_emit_save_args (mb, sig, FALSE);
2998
2999         mono_mb_emit_ldarg (mb, 0);
3000         mono_mb_emit_ldloc (mb, params_var);
3001         mono_mb_emit_icall (mb, mono_delegate_begin_invoke);
3002         mono_mb_emit_byte (mb, CEE_RET);
3003
3004         res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
3005         mono_mb_free (mb);
3006         return res;
3007 }
3008
3009 static MonoObject *
3010 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
3011 {
3012         MonoDomain *domain = mono_domain_get ();
3013         MonoAsyncResult *ares;
3014         MonoMethod *method = NULL;
3015         MonoMethodSignature *sig;
3016         MonoMethodMessage *msg;
3017         MonoObject *res, *exc;
3018         MonoArray *out_args;
3019         MonoClass *klass;
3020
3021         g_assert (delegate);
3022
3023         if (!delegate->method_info) {
3024                 g_assert (delegate->method);
3025                 MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, delegate->method, NULL));
3026         }
3027
3028         if (!delegate->method_info || !delegate->method_info->method)
3029                 g_assert_not_reached ();
3030
3031         klass = delegate->object.vtable->klass;
3032
3033         method = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3034         g_assert (method != NULL);
3035
3036         sig = mono_signature_no_pinvoke (method);
3037
3038         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
3039
3040         ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
3041         if (ares == NULL)
3042                 mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
3043
3044         if (ares->async_delegate != (MonoObject*)delegate && mono_framework_version () >= 2) {
3045                 mono_raise_exception (mono_get_exception_invalid_operation (
3046                         "The IAsyncResult object provided does not match this delegate."));
3047                 return NULL;
3048         }
3049
3050         if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
3051                 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
3052                 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3053                 mono_message_init (domain, msg, delegate->method_info, NULL);
3054                 msg->call_type = CallType_EndInvoke;
3055                 MONO_OBJECT_SETREF (msg, async_result, ares);
3056                 res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
3057         } else {
3058                 res = mono_thread_pool_finish (ares, &out_args, &exc);
3059         }
3060
3061         if (exc) {
3062                 if (((MonoException*)exc)->stack_trace) {
3063                         char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
3064                         char  *tmp;
3065                         tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
3066                         g_free (strace);        
3067                         MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
3068                         g_free (tmp);
3069                 }
3070                 mono_raise_exception ((MonoException*)exc);
3071         }
3072
3073         mono_method_return_message_restore (method, params, out_args);
3074         return res;
3075 }
3076
3077 static void
3078 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
3079 {
3080         MonoType *t = mono_type_get_underlying_type (return_type);
3081
3082         if (return_type->byref)
3083                 return_type = &mono_defaults.int_class->byval_arg;
3084
3085         switch (t->type) {
3086         case MONO_TYPE_VOID:
3087                 g_assert_not_reached ();
3088                 break;
3089         case MONO_TYPE_PTR:
3090         case MONO_TYPE_STRING:
3091         case MONO_TYPE_CLASS: 
3092         case MONO_TYPE_OBJECT: 
3093         case MONO_TYPE_ARRAY: 
3094         case MONO_TYPE_SZARRAY: 
3095                 /* nothing to do */
3096                 break;
3097         case MONO_TYPE_U1:
3098         case MONO_TYPE_BOOLEAN:
3099         case MONO_TYPE_I1:
3100         case MONO_TYPE_U2:
3101         case MONO_TYPE_CHAR:
3102         case MONO_TYPE_I2:
3103         case MONO_TYPE_I:
3104         case MONO_TYPE_U:
3105         case MONO_TYPE_I4:
3106         case MONO_TYPE_U4:
3107         case MONO_TYPE_U8:
3108         case MONO_TYPE_I8:
3109         case MONO_TYPE_R4:
3110         case MONO_TYPE_R8:
3111                 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (return_type));
3112                 mono_mb_emit_byte (mb, mono_type_to_ldind (return_type));
3113                 break;
3114         case MONO_TYPE_GENERICINST:
3115                 if (!mono_type_generic_inst_is_valuetype (return_type))
3116                         break;
3117                 /* fall through */
3118         case MONO_TYPE_VALUETYPE: {
3119                 MonoClass *klass = mono_class_from_mono_type (return_type);
3120                 mono_mb_emit_op (mb, CEE_UNBOX, klass);
3121                 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
3122                 break;
3123         }
3124         default:
3125                 g_warning ("type 0x%x not handled", return_type->type);
3126                 g_assert_not_reached ();
3127         }
3128
3129         mono_mb_emit_byte (mb, CEE_RET);
3130 }
3131
3132 MonoMethod *
3133 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
3134 {
3135         MonoMethodSignature *sig;
3136         MonoMethodBuilder *mb;
3137         MonoMethod *res;
3138         GHashTable *cache;
3139         int params_var;
3140         char *name;
3141
3142         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
3143                   !strcmp (method->name, "EndInvoke"));
3144
3145         sig = mono_signature_no_pinvoke (method);
3146
3147         cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
3148                                            (GHashFunc)mono_signature_hash, 
3149                                            (GCompareFunc)mono_metadata_signature_equal);
3150         if ((res = mono_marshal_find_in_cache (cache, sig)))
3151                 return res;
3152
3153         g_assert (sig->hasthis);
3154
3155         name = mono_signature_to_name (sig, "end_invoke");
3156         mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
3157         g_free (name);
3158
3159         params_var = mono_mb_emit_save_args (mb, sig, FALSE);
3160
3161         mono_mb_emit_ldarg (mb, 0);
3162         mono_mb_emit_ldloc (mb, params_var);
3163         mono_mb_emit_icall (mb, mono_delegate_end_invoke);
3164
3165         if (sig->ret->type == MONO_TYPE_VOID) {
3166                 mono_mb_emit_byte (mb, CEE_POP);
3167                 mono_mb_emit_byte (mb, CEE_RET);
3168         } else
3169                 mono_mb_emit_restore_result (mb, sig->ret);
3170
3171         res = mono_mb_create_and_cache (cache, sig,
3172                                                                                  mb, sig, sig->param_count + 16);
3173         mono_mb_free (mb);
3174
3175         return res;
3176 }
3177
3178 static MonoObject *
3179 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
3180 {
3181         MonoMethodMessage *msg;
3182         MonoTransparentProxy *this;
3183         MonoObject *res, *exc;
3184         MonoArray *out_args;
3185
3186         this = *((MonoTransparentProxy **)params [0]);
3187
3188         g_assert (this);
3189         g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
3190         
3191         /* skip the this pointer */
3192         params++;
3193
3194         if (this->remote_class->proxy_class->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
3195         {
3196                 int i;
3197                 MonoMethodSignature *sig = mono_method_signature (method);
3198                 int count = sig->param_count;
3199                 gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
3200
3201                 for (i=0; i<count; i++) {
3202                         MonoClass *class = mono_class_from_mono_type (sig->params [i]);
3203                         if (class->valuetype) {
3204                                 if (sig->params [i]->byref) {
3205                                         mparams[i] = *((gpointer *)params [i]);
3206                                 } else {
3207                                         /* runtime_invoke expects a boxed instance */
3208                                         if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i])))
3209                                                 mparams[i] = mono_nullable_box (params [i], class);
3210                                         else
3211                                                 mparams[i] = params [i];
3212                                 }
3213                         } else {
3214                                 mparams[i] = *((gpointer**)params [i]);
3215                         }
3216                 }
3217
3218                 return mono_runtime_invoke (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this): this, mparams, NULL);
3219         }
3220
3221         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
3222
3223         res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
3224
3225         if (exc)
3226                 mono_raise_exception ((MonoException *)exc);
3227
3228         mono_method_return_message_restore (method, params, out_args);
3229
3230         return res;
3231
3232
3233 #ifndef DISABLE_COM
3234
3235 /**
3236  * cominterop_get_native_wrapper_adjusted:
3237  * @method: managed COM Interop method
3238  *
3239  * Returns: the generated method to call with signature matching
3240  * the unmanaged COM Method signature
3241  */
3242 static MonoMethod *
3243 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
3244 {
3245         MonoMethod *res;
3246         MonoMethodBuilder *mb_native;
3247         MonoMarshalSpec **mspecs;
3248         MonoMethodSignature *sig, *sig_native;
3249         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
3250         int i;
3251
3252         sig = mono_method_signature (method);
3253
3254         // create unmanaged wrapper
3255         mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
3256         sig_native = cominterop_method_signature (method);
3257
3258         mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
3259         memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
3260
3261         mono_method_get_marshal_info (method, mspecs);
3262
3263         // move managed args up one
3264         for (i = sig->param_count; i >= 1; i--)
3265                 mspecs[i+1] = mspecs[i];
3266
3267         // first arg is IntPtr for interface
3268         mspecs[1] = NULL;
3269
3270         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
3271                 // move return spec to last param
3272                 if (!MONO_TYPE_IS_VOID (sig->ret))
3273                         mspecs[sig_native->param_count] = mspecs[0];
3274
3275                 mspecs[0] = NULL;
3276         }
3277
3278         for (i = 1; i < sig_native->param_count; i++) {
3279                 int mspec_index = i + 1;
3280                 if (mspecs[mspec_index] == NULL) {
3281                         // default object to VARIANT
3282                         if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
3283                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
3284                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
3285                         }
3286                         else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
3287                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
3288                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
3289                         }
3290                         else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
3291                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
3292                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
3293                         }
3294                 }
3295         }
3296
3297         if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
3298                 // move return spec to last param
3299                 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {                       
3300                         // default object to VARIANT
3301                         if (sig->ret->type == MONO_TYPE_OBJECT) {
3302                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
3303                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
3304                         }
3305                         else if (sig->ret->type == MONO_TYPE_STRING) {
3306                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
3307                                 mspecs[0]->native = MONO_NATIVE_BSTR;
3308                         }
3309                         else if (sig->ret->type == MONO_TYPE_CLASS) {
3310                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
3311                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
3312                         }
3313                 }
3314         }
3315
3316         mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE);
3317
3318         res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);      
3319
3320         mono_mb_free (mb_native);
3321
3322         for (i = sig_native->param_count; i >= 0; i--)
3323                 if (mspecs [i])
3324                         mono_metadata_free_marshal_spec (mspecs [i]);
3325         g_free (mspecs);
3326
3327         return res;
3328 }
3329
3330 /**
3331  * cominterop_get_native_wrapper:
3332  * @method: managed method
3333  *
3334  * Returns: the generated method to call
3335  */
3336 static MonoMethod *
3337 cominterop_get_native_wrapper (MonoMethod *method)
3338 {
3339         MonoMethod *res;
3340         GHashTable *cache;
3341         MonoMethodBuilder *mb;
3342         MonoMethodSignature *sig, *csig;
3343
3344         g_assert (method);
3345
3346         cache = get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
3347         if ((res = mono_marshal_find_in_cache (cache, method)))
3348                 return res;
3349
3350         mono_init_com_types ();
3351
3352         if (!method->klass->vtable)
3353                 mono_class_setup_vtable (method->klass);
3354         
3355         if (!method->klass->methods)
3356                 mono_class_setup_methods (method->klass);
3357
3358         sig = mono_method_signature (method);
3359         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
3360
3361         /* if method klass is import, that means method
3362          * is really a com call. let interop system emit it.
3363         */
3364         if (MONO_CLASS_IS_IMPORT(method->klass)) {
3365                 /* FIXME: we have to call actual class .ctor
3366                  * instead of just __ComObject .ctor.
3367                  */
3368                 if (!strcmp(method->name, ".ctor")) {
3369                         static MonoMethod *ctor = NULL;
3370
3371                         if (!ctor)
3372                                 ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
3373                         mono_mb_emit_ldarg (mb, 0);
3374                         mono_mb_emit_managed_call (mb, ctor, NULL);
3375                         mono_mb_emit_byte (mb, CEE_RET);
3376                 }
3377                 else {
3378                         static MonoMethod * ThrowExceptionForHR = NULL;
3379                         MonoMethod *adjusted_method;
3380                         int retval = 0;
3381                         int ptr_this;
3382                         int i;
3383                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
3384
3385                         // add local variables
3386                         ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3387                         if (!MONO_TYPE_IS_VOID (sig->ret))
3388                                 retval =  mono_mb_add_local (mb, sig->ret);
3389
3390                         // get the type for the interface the method is defined on
3391                         // and then get the underlying COM interface for that type
3392                         mono_mb_emit_ldarg (mb, 0);
3393                         mono_mb_emit_ptr (mb, method);
3394                         mono_mb_emit_icall (mb, cominterop_get_method_interface);
3395                         mono_mb_emit_icon (mb, TRUE);
3396                         mono_mb_emit_icall (mb, cominterop_get_interface);
3397                         mono_mb_emit_stloc (mb, ptr_this);
3398
3399                         // arg 1 is unmanaged this pointer
3400                         mono_mb_emit_ldloc (mb, ptr_this);
3401
3402                         // load args
3403                         for (i = 1; i <= sig->param_count; i++)
3404                                 mono_mb_emit_ldarg (mb, i);
3405
3406                         // push managed return value as byref last argument
3407                         if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
3408                                 mono_mb_emit_ldloc_addr (mb, retval);
3409                         
3410                         adjusted_method = cominterop_get_native_wrapper_adjusted (method);
3411                         mono_mb_emit_managed_call (mb, adjusted_method, NULL);
3412
3413                         if (!preserve_sig) {
3414                                 if (!ThrowExceptionForHR)
3415                                         ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
3416                                 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
3417
3418                                 // load return value managed is expecting
3419                                 if (!MONO_TYPE_IS_VOID (sig->ret))
3420                                         mono_mb_emit_ldloc (mb, retval);
3421                         }
3422
3423                         mono_mb_emit_byte (mb, CEE_RET);
3424                 }
3425                 
3426                 
3427         }
3428         /* Does this case ever get hit? */
3429         else {
3430                 char *msg = g_strdup ("non imported interfaces on \
3431                         imported classes is not yet implemented.");
3432                 mono_mb_emit_exception (mb, "NotSupportedException", msg);
3433         }
3434         csig = signature_dup (method->klass->image, sig);
3435         csig->pinvoke = 0;
3436         res = mono_mb_create_and_cache (cache, method,
3437                                                                         mb, csig, csig->param_count + 16);
3438         mono_mb_free (mb);
3439         return res;
3440 }
3441
3442 /**
3443  * cominterop_get_invoke:
3444  * @method: managed method
3445  *
3446  * Returns: the generated method that calls the underlying __ComObject
3447  * rather than the proxy object.
3448  */
3449 static MonoMethod *
3450 cominterop_get_invoke (MonoMethod *method)
3451 {
3452         MonoMethodSignature *sig;
3453         MonoMethodBuilder *mb;
3454         MonoMethod *res;
3455         int i, temp_obj;
3456         GHashTable* cache = get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
3457
3458         g_assert (method);
3459
3460         if ((res = mono_marshal_find_in_cache (cache, method)))
3461                 return res;
3462
3463         sig = mono_signature_no_pinvoke (method);
3464
3465         /* we cant remote methods without this pointer */
3466         if (!sig->hasthis)
3467                 return method;
3468
3469         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
3470
3471         /* get real proxy object, which is a ComInteropProxy in this case*/
3472         temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3473         mono_mb_emit_ldarg (mb, 0);
3474         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
3475         mono_mb_emit_byte (mb, CEE_LDIND_REF);
3476
3477         /* load the RCW from the ComInteropProxy*/
3478         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
3479         mono_mb_emit_byte (mb, CEE_LDIND_REF);
3480
3481         /* load args and make the call on the RCW */
3482         for (i = 1; i <= sig->param_count; i++)
3483                 mono_mb_emit_ldarg (mb, i);
3484
3485         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
3486                 MonoMethod * native_wrapper = cominterop_get_native_wrapper(method);
3487                 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
3488         }
3489         else {
3490                 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
3491                         mono_mb_emit_op (mb, CEE_CALLVIRT, method);
3492                 else
3493                         mono_mb_emit_op (mb, CEE_CALL, method);
3494         }
3495
3496         if (!strcmp(method->name, ".ctor"))     {
3497                 static MonoClass *com_interop_proxy_class = NULL;
3498                 static MonoMethod *cache_proxy = NULL;
3499
3500                 if (!com_interop_proxy_class)
3501                         com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
3502                 if (!cache_proxy)
3503                         cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
3504
3505                 mono_mb_emit_ldarg (mb, 0);
3506                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
3507                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3508                 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
3509         }
3510
3511         emit_thread_interrupt_checkpoint (mb);
3512
3513         mono_mb_emit_byte (mb, CEE_RET);
3514
3515         res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
3516         mono_mb_free (mb);
3517
3518         return res;
3519 }
3520
3521 #endif /* DISABLE_COM */
3522
3523 /* Maps a managed object to its unmanaged representation 
3524  * i.e. it's COM Callable Wrapper (CCW). 
3525  * Key: MonoObject*
3526  * Value: MonoCCW*
3527  */
3528 static GHashTable* ccw_hash = NULL;
3529
3530 /* Maps a CCW interface to it's containing CCW. 
3531  * Note that a CCW support many interfaces.
3532  * Key: MonoCCW*
3533  * Value: MonoCCWInterface*
3534  */
3535 static GHashTable* ccw_interface_hash = NULL;
3536
3537 /* Maps the IUnknown value of a RCW to
3538  * it's MonoComInteropProxy*.
3539  * Key: void*
3540  * Value: gchandle
3541  */
3542 static GHashTable* rcw_hash = NULL;
3543
3544 MonoMethod *
3545 mono_marshal_get_remoting_invoke (MonoMethod *method)
3546 {
3547         MonoMethodSignature *sig;
3548         MonoMethodBuilder *mb;
3549         MonoMethod *res;
3550         int params_var;
3551
3552         g_assert (method);
3553
3554         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
3555                 return method;
3556
3557         /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
3558         if ((method->klass->is_com_object || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote) {
3559 #ifndef DISABLE_COM
3560                 return cominterop_get_invoke(method);
3561 #else
3562                 g_assert_not_reached ();
3563 #endif
3564         }
3565
3566         sig = mono_signature_no_pinvoke (method);
3567
3568         /* we cant remote methods without this pointer */
3569         if (!sig->hasthis)
3570                 return method;
3571
3572         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE)))
3573                 return res;
3574
3575         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
3576         mb->method->save_lmf = 1;
3577
3578         params_var = mono_mb_emit_save_args (mb, sig, TRUE);
3579
3580         mono_mb_emit_ptr (mb, method);
3581         mono_mb_emit_ldloc (mb, params_var);
3582         mono_mb_emit_icall (mb, mono_remoting_wrapper);
3583         emit_thread_interrupt_checkpoint (mb);
3584
3585         if (sig->ret->type == MONO_TYPE_VOID) {
3586                 mono_mb_emit_byte (mb, CEE_POP);
3587                 mono_mb_emit_byte (mb, CEE_RET);
3588         } else {
3589                  mono_mb_emit_restore_result (mb, sig->ret);
3590         }
3591
3592         res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
3593         mono_mb_free (mb);
3594
3595         return res;
3596 }
3597
3598 /* mono_get_xdomain_marshal_type()
3599  * Returns the kind of marshalling that a type needs for cross domain calls.
3600  */
3601 static MonoXDomainMarshalType
3602 mono_get_xdomain_marshal_type (MonoType *t)
3603 {
3604         switch (t->type) {
3605         case MONO_TYPE_VOID:
3606                 g_assert_not_reached ();
3607                 break;
3608         case MONO_TYPE_U1:
3609         case MONO_TYPE_I1:
3610         case MONO_TYPE_BOOLEAN:
3611         case MONO_TYPE_U2:
3612         case MONO_TYPE_I2:
3613         case MONO_TYPE_CHAR:
3614         case MONO_TYPE_U4:
3615         case MONO_TYPE_I4:
3616         case MONO_TYPE_I8:
3617         case MONO_TYPE_U8:
3618         case MONO_TYPE_R4:
3619         case MONO_TYPE_R8:
3620                 return MONO_MARSHAL_NONE;
3621         case MONO_TYPE_STRING:
3622                 return MONO_MARSHAL_COPY;
3623         case MONO_TYPE_ARRAY:
3624         case MONO_TYPE_SZARRAY: {
3625                 MonoClass *elem_class = mono_class_from_mono_type (t)->element_class;
3626                 if (mono_get_xdomain_marshal_type (&(elem_class->byval_arg)) != MONO_MARSHAL_SERIALIZE)
3627                         return MONO_MARSHAL_COPY;
3628                 break;
3629         }
3630         }
3631
3632         return MONO_MARSHAL_SERIALIZE;
3633 }
3634
3635
3636 /* mono_marshal_xdomain_copy_value
3637  * Makes a copy of "val" suitable for the current domain.
3638  */
3639 static MonoObject *
3640 mono_marshal_xdomain_copy_value (MonoObject *val)
3641 {
3642         MonoDomain *domain;
3643         if (val == NULL) return NULL;
3644
3645         domain = mono_domain_get ();
3646
3647         switch (mono_object_class (val)->byval_arg.type) {
3648         case MONO_TYPE_VOID:
3649                 g_assert_not_reached ();
3650                 break;
3651         case MONO_TYPE_U1:
3652         case MONO_TYPE_I1:
3653         case MONO_TYPE_BOOLEAN:
3654         case MONO_TYPE_U2:
3655         case MONO_TYPE_I2:
3656         case MONO_TYPE_CHAR:
3657         case MONO_TYPE_U4:
3658         case MONO_TYPE_I4:
3659         case MONO_TYPE_I8:
3660         case MONO_TYPE_U8:
3661         case MONO_TYPE_R4:
3662         case MONO_TYPE_R8: {
3663                 return mono_value_box (domain, mono_object_class (val), ((char*)val) + sizeof(MonoObject));
3664         }
3665         case MONO_TYPE_STRING: {
3666                 MonoString *str = (MonoString *) val;
3667                 return (MonoObject *) mono_string_new_utf16 (domain, mono_string_chars (str), mono_string_length (str));
3668         }
3669         case MONO_TYPE_ARRAY:
3670         case MONO_TYPE_SZARRAY: {
3671                 MonoArray *acopy;
3672                 MonoXDomainMarshalType mt = mono_get_xdomain_marshal_type (&(mono_object_class (val)->element_class->byval_arg));
3673                 if (mt == MONO_MARSHAL_SERIALIZE) return NULL;
3674                 acopy = mono_array_clone_in_domain (domain, (MonoArray *) val);
3675                 if (mt == MONO_MARSHAL_COPY) {
3676                         int i, len = mono_array_length (acopy);
3677                         for (i = 0; i < len; i++) {
3678                                 MonoObject *item = mono_array_get (acopy, gpointer, i);
3679                                 mono_array_setref (acopy, i, mono_marshal_xdomain_copy_value (item));
3680                         }
3681                 }
3682                 return (MonoObject *) acopy;
3683         }
3684         }
3685
3686         if (mono_object_class (val) == mono_defaults.stringbuilder_class) {
3687                 MonoStringBuilder *oldsb = (MonoStringBuilder *) val;
3688                 MonoStringBuilder *newsb = (MonoStringBuilder *) mono_object_new (domain, mono_defaults.stringbuilder_class);
3689                 MONO_OBJECT_SETREF (newsb, str, mono_string_new_utf16 (domain, mono_string_chars (oldsb->str), mono_string_length (oldsb->str)));
3690                 newsb->length = oldsb->length;
3691                 newsb->max_capacity = (gint32)0x7fffffff;
3692                 return (MonoObject *) newsb;
3693         }
3694         return NULL;
3695 }
3696
3697 /* mono_marshal_xdomain_copy_out_value()
3698  * Copies the contents of the src instance into the dst instance. src and dst
3699  * must have the same type, and if they are arrays, the same size.
3700  */
3701 static void
3702 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst)
3703 {
3704         if (src == NULL || dst == NULL) return;
3705         
3706         g_assert (mono_object_class (src) == mono_object_class (dst));
3707
3708         switch (mono_object_class (src)->byval_arg.type) {
3709         case MONO_TYPE_ARRAY:
3710         case MONO_TYPE_SZARRAY: {
3711                 int mt = mono_get_xdomain_marshal_type (&(mono_object_class (src)->element_class->byval_arg));
3712                 if (mt == MONO_MARSHAL_SERIALIZE) return;
3713                 if (mt == MONO_MARSHAL_COPY) {
3714                         int i, len = mono_array_length ((MonoArray *)dst);
3715                         for (i = 0; i < len; i++) {
3716                                 MonoObject *item = mono_array_get ((MonoArray *)src, gpointer, i);
3717                                 mono_array_setref ((MonoArray *)dst, i, mono_marshal_xdomain_copy_value (item));
3718                         }
3719                 } else {
3720                         mono_array_full_copy ((MonoArray *)src, (MonoArray *)dst);
3721                 }
3722                 return;
3723         }
3724         }
3725
3726         if (mono_object_class (src) == mono_defaults.stringbuilder_class) {
3727                 MonoStringBuilder *src_sb = (MonoStringBuilder *) src;
3728                 MonoStringBuilder *dst_sb = (MonoStringBuilder *) dst;
3729         
3730                 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)));
3731                 dst_sb->cached_str = NULL;
3732                 dst_sb->length = src_sb->length;
3733         }
3734 }
3735
3736 static void
3737 mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder *mb, MonoClass *pclass)
3738 {
3739         mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_value);
3740         mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
3741 }
3742
3743 static void
3744 mono_marshal_emit_xdomain_copy_out_value (MonoMethodBuilder *mb, MonoClass *pclass)
3745 {
3746         mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_out_value);
3747 }
3748
3749 /* mono_marshal_supports_fast_xdomain()
3750  * Returns TRUE if the method can use the fast xdomain wrapper.
3751  */
3752 static gboolean
3753 mono_marshal_supports_fast_xdomain (MonoMethod *method)
3754 {
3755         return !method->klass->contextbound &&
3756                    !((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".ctor", method->name) == 0));
3757 }
3758
3759 static gint32
3760 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push)
3761 {
3762         MonoDomain *current_domain = mono_domain_get ();
3763         MonoDomain *domain = mono_domain_get_by_id (id);
3764
3765         if (!domain || !mono_domain_set (domain, FALSE))        
3766                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
3767
3768         if (push)
3769                 mono_thread_push_appdomain_ref (domain);
3770         else
3771                 mono_thread_pop_appdomain_ref ();
3772
3773         return current_domain->domain_id;
3774 }
3775
3776 static void
3777 mono_marshal_emit_switch_domain (MonoMethodBuilder *mb)
3778 {
3779         mono_mb_emit_icall (mb, mono_marshal_set_domain_by_id);
3780 }
3781
3782 /* mono_marshal_emit_load_domain_method ()
3783  * Loads into the stack a pointer to the code of the provided method for
3784  * the current domain.
3785  */
3786 static void
3787 mono_marshal_emit_load_domain_method (MonoMethodBuilder *mb, MonoMethod *method)
3788 {
3789         /* We need a pointer to the method for the running domain (not the domain
3790          * that compiles the method).
3791          */
3792         mono_mb_emit_ptr (mb, method);
3793         mono_mb_emit_icall (mb, mono_compile_method);
3794 }
3795
3796 /* mono_marshal_check_domain_image ()
3797  * Returns TRUE if the image is loaded in the specified
3798  * application domain.
3799  */
3800 static gboolean
3801 mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image)
3802 {
3803         MonoAssembly* ass;
3804         GSList *tmp;
3805         
3806         MonoDomain *domain = mono_domain_get_by_id (domain_id);
3807         if (!domain)
3808                 return FALSE;
3809         
3810         mono_domain_assemblies_lock (domain);
3811         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
3812                 ass = tmp->data;
3813                 if (ass->image == image)
3814                         break;
3815         }
3816         mono_domain_assemblies_unlock (domain);
3817         
3818         return tmp != NULL;
3819 }
3820
3821 /* mono_marshal_get_xappdomain_dispatch ()
3822  * Generates a method that dispatches a method call from another domain into
3823  * the current domain.
3824  */
3825 static MonoMethod *
3826 mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, int complex_count, int complex_out_count, int ret_marshal_type)
3827 {
3828         MonoMethodSignature *sig, *csig;
3829         MonoMethodBuilder *mb;
3830         MonoMethod *res;
3831         int i, j, param_index, copy_locals_base;
3832         MonoClass *ret_class = NULL;
3833         int loc_array=0, loc_return=0, loc_serialized_exc=0;
3834         MonoExceptionClause *main_clause;
3835         int pos, pos_leave;
3836         gboolean copy_return;
3837
3838         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_DISPATCH)))
3839                 return res;
3840
3841         sig = mono_method_signature (method);
3842         copy_return = (sig->ret->type != MONO_TYPE_VOID && ret_marshal_type != MONO_MARSHAL_SERIALIZE);
3843
3844         j = 0;
3845         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3 + sig->param_count - complex_count);
3846         csig->params [j++] = &mono_defaults.object_class->byval_arg;
3847         csig->params [j++] = &byte_array_class->this_arg;
3848         csig->params [j++] = &byte_array_class->this_arg;
3849         for (i = 0; i < sig->param_count; i++) {
3850                 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE)
3851                         csig->params [j++] = sig->params [i];
3852         }
3853         if (copy_return)
3854                 csig->ret = sig->ret;
3855         else
3856                 csig->ret = &mono_defaults.void_class->byval_arg;
3857         csig->pinvoke = 1;
3858         csig->hasthis = FALSE;
3859
3860         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_DISPATCH);
3861         mb->method->save_lmf = 1;
3862
3863         /* Locals */
3864
3865         loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
3866         if (complex_count > 0)
3867                 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3868         if (sig->ret->type != MONO_TYPE_VOID) {
3869                 loc_return = mono_mb_add_local (mb, sig->ret);
3870                 ret_class = mono_class_from_mono_type (sig->ret);
3871         }
3872
3873         /* try */
3874
3875         mono_loader_lock ();
3876         main_clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
3877         mono_loader_unlock ();
3878         main_clause->try_offset = mono_mb_get_label (mb);
3879
3880         /* Clean the call context */
3881
3882         mono_mb_emit_byte (mb, CEE_LDNULL);
3883         mono_mb_emit_managed_call (mb, method_set_call_context, NULL);
3884         mono_mb_emit_byte (mb, CEE_POP);
3885
3886         /* Deserialize call data */
3887
3888         mono_mb_emit_ldarg (mb, 1);
3889         mono_mb_emit_byte (mb, CEE_LDIND_REF);
3890         mono_mb_emit_byte (mb, CEE_DUP);
3891         pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3892         
3893         mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
3894         mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
3895         
3896         if (complex_count > 0)
3897                 mono_mb_emit_stloc (mb, loc_array);
3898         else
3899                 mono_mb_emit_byte (mb, CEE_POP);
3900
3901         mono_mb_patch_short_branch (mb, pos);
3902
3903         /* Get the target object */
3904         
3905         mono_mb_emit_ldarg (mb, 0);
3906         mono_mb_emit_managed_call (mb, method_rs_appdomain_target, NULL);
3907
3908         /* Load the arguments */
3909         
3910         copy_locals_base = mb->locals;
3911         param_index = 3;        // Index of the first non-serialized parameter of this wrapper
3912         j = 0;
3913         for (i = 0; i < sig->param_count; i++) {
3914                 MonoType *pt = sig->params [i];
3915                 MonoClass *pclass = mono_class_from_mono_type (pt);
3916                 switch (marshal_types [i]) {
3917                 case MONO_MARSHAL_SERIALIZE: {
3918                         /* take the value from the serialized array */
3919                         mono_mb_emit_ldloc (mb, loc_array);
3920                         mono_mb_emit_icon (mb, j++);
3921                         if (pt->byref) {
3922                                 if (pclass->valuetype) {
3923                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3924                                         mono_mb_emit_op (mb, CEE_UNBOX, pclass);
3925                                 } else {
3926                                         mono_mb_emit_op (mb, CEE_LDELEMA, pclass);
3927                                 }
3928                         } else {
3929                                 if (pclass->valuetype) {
3930                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3931                                         mono_mb_emit_op (mb, CEE_UNBOX, pclass);
3932                                         mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
3933                                 } else {
3934                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3935                                         if (pclass != mono_defaults.object_class) {
3936                                                 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
3937                                         }
3938                                 }
3939                         }
3940                         break;
3941                 }
3942                 case MONO_MARSHAL_COPY_OUT: {
3943                         /* Keep a local copy of the value since we need to copy it back after the call */
3944                         int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
3945                         mono_mb_emit_ldarg (mb, param_index++);
3946                         mono_marshal_emit_xdomain_copy_value (mb, pclass);
3947                         mono_mb_emit_byte (mb, CEE_DUP);
3948                         mono_mb_emit_stloc (mb, copy_local);
3949                         break;
3950                 }
3951                 case MONO_MARSHAL_COPY: {
3952                         mono_mb_emit_ldarg (mb, param_index);
3953                         if (pt->byref) {
3954                                 mono_mb_emit_byte (mb, CEE_DUP);
3955                                 mono_mb_emit_byte (mb, CEE_DUP);
3956                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3957                                 mono_marshal_emit_xdomain_copy_value (mb, pclass);
3958                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
3959                         } else {
3960                                 mono_marshal_emit_xdomain_copy_value (mb, pclass);
3961                         }
3962                         param_index++;
3963                         break;
3964                 }
3965                 case MONO_MARSHAL_NONE:
3966                         mono_mb_emit_ldarg (mb, param_index++);
3967                         break;
3968                 }
3969         }
3970
3971         /* Make the call to the real object */
3972
3973         emit_thread_force_interrupt_checkpoint (mb);
3974         
3975         mono_mb_emit_op (mb, CEE_CALLVIRT, method);
3976
3977         if (sig->ret->type != MONO_TYPE_VOID)
3978                 mono_mb_emit_stloc (mb, loc_return);
3979
3980         /* copy back MONO_MARSHAL_COPY_OUT parameters */
3981
3982         j = 0;
3983         param_index = 3;
3984         for (i = 0; i < sig->param_count; i++) {
3985                 if (marshal_types [i] == MONO_MARSHAL_SERIALIZE) continue;
3986                 if (marshal_types [i] == MONO_MARSHAL_COPY_OUT) {
3987                         mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
3988                         mono_mb_emit_ldarg (mb, param_index);
3989                         mono_marshal_emit_xdomain_copy_out_value (mb, mono_class_from_mono_type (sig->params [i]));
3990                 }
3991                 param_index++;
3992         }
3993
3994         /* Serialize the return values */
3995         
3996         if (complex_out_count > 0) {
3997                 /* Reset parameters in the array that don't need to be serialized back */
3998                 j = 0;
3999                 for (i = 0; i < sig->param_count; i++) {
4000                         if (marshal_types[i] != MONO_MARSHAL_SERIALIZE) continue;
4001                         if (!sig->params [i]->byref) {
4002                                 mono_mb_emit_ldloc (mb, loc_array);
4003                                 mono_mb_emit_icon (mb, j);
4004                                 mono_mb_emit_byte (mb, CEE_LDNULL);
4005                                 mono_mb_emit_byte (mb, CEE_STELEM_REF);
4006                         }
4007                         j++;
4008                 }
4009         
4010                 /* Add the return value to the array */
4011         
4012                 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
4013                         mono_mb_emit_ldloc (mb, loc_array);
4014                         mono_mb_emit_icon (mb, complex_count);  /* The array has an additional slot to hold the ret value */
4015                         mono_mb_emit_ldloc (mb, loc_return);
4016                         if (ret_class->valuetype) {
4017                                 mono_mb_emit_op (mb, CEE_BOX, ret_class);
4018                         }
4019                         mono_mb_emit_byte (mb, CEE_STELEM_REF);
4020                 }
4021         
4022                 /* Serialize */
4023         
4024                 mono_mb_emit_ldarg (mb, 1);
4025                 mono_mb_emit_ldloc (mb, loc_array);
4026                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
4027                 mono_mb_emit_byte (mb, CEE_STIND_REF);
4028         } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
4029                 mono_mb_emit_ldarg (mb, 1);
4030                 mono_mb_emit_ldloc (mb, loc_return);
4031                 if (ret_class->valuetype) {
4032                         mono_mb_emit_op (mb, CEE_BOX, ret_class);
4033                 }
4034                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
4035                 mono_mb_emit_byte (mb, CEE_STIND_REF);
4036         } else {
4037                 mono_mb_emit_ldarg (mb, 1);
4038                 mono_mb_emit_byte (mb, CEE_LDNULL);
4039                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
4040                 mono_mb_emit_byte (mb, CEE_STIND_REF);
4041         }
4042
4043         mono_mb_emit_ldarg (mb, 2);
4044         mono_mb_emit_byte (mb, CEE_LDNULL);
4045         mono_mb_emit_byte (mb, CEE_STIND_REF);
4046         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
4047
4048         /* Main exception catch */
4049         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
4050         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
4051         main_clause->data.catch_class = mono_defaults.object_class;
4052         
4053         /* handler code */
4054         main_clause->handler_offset = mono_mb_get_label (mb);
4055         mono_mb_emit_managed_call (mb, method_rs_serialize_exc, NULL);
4056         mono_mb_emit_stloc (mb, loc_serialized_exc);
4057         mono_mb_emit_ldarg (mb, 2);
4058         mono_mb_emit_ldloc (mb, loc_serialized_exc);
4059         mono_mb_emit_byte (mb, CEE_STIND_REF);
4060         mono_mb_emit_branch (mb, CEE_LEAVE);
4061         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
4062         /* end catch */
4063
4064         mono_mb_patch_branch (mb, pos_leave);
4065         
4066         if (copy_return)
4067                 mono_mb_emit_ldloc (mb, loc_return);
4068
4069         mono_mb_emit_byte (mb, CEE_RET);
4070
4071         mono_mb_set_clauses (mb, 1, main_clause);
4072
4073         res = mono_remoting_mb_create_and_cache (method, mb, csig, csig->param_count + 16);
4074         mono_mb_free (mb);
4075
4076         return res;
4077 }
4078
4079 /* mono_marshal_get_xappdomain_invoke ()
4080  * Generates a fast remoting wrapper for cross app domain calls.
4081  */
4082 MonoMethod *
4083 mono_marshal_get_xappdomain_invoke (MonoMethod *method)
4084 {
4085         MonoMethodSignature *sig;
4086         MonoMethodBuilder *mb;
4087         MonoMethod *res;
4088         int i, j, complex_count, complex_out_count, copy_locals_base;
4089         int *marshal_types;
4090         MonoClass *ret_class = NULL;
4091         MonoMethod *xdomain_method;
4092         int ret_marshal_type = MONO_MARSHAL_NONE;
4093         int loc_array=0, loc_serialized_data=-1, loc_real_proxy;
4094         int loc_old_domainid, loc_domainid, loc_return=0, loc_serialized_exc=0, loc_context;
4095         int pos, pos_dispatch, pos_noex;
4096         gboolean copy_return = FALSE;
4097
4098         g_assert (method);
4099         
4100         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
4101                 return method;
4102
4103         /* we cant remote methods without this pointer */
4104         if (!mono_method_signature (method)->hasthis)
4105                 return method;
4106
4107         if (!mono_marshal_supports_fast_xdomain (method))
4108                 return mono_marshal_get_remoting_invoke (method);
4109         
4110         mono_remoting_marshal_init ();
4111
4112         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE)))
4113                 return res;
4114         
4115         sig = mono_signature_no_pinvoke (method);
4116
4117         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE);
4118         mb->method->save_lmf = 1;
4119
4120         /* Count the number of parameters that need to be serialized */
4121
4122         marshal_types = alloca (sizeof (int) * sig->param_count);
4123         complex_count = complex_out_count = 0;
4124         for (i = 0; i < sig->param_count; i++) {
4125                 MonoType *ptype = sig->params[i];
4126                 int mt = mono_get_xdomain_marshal_type (ptype);
4127                 
4128                 /* If the [Out] attribute is applied to a parameter that can be internally copied,
4129                  * the copy will be made by reusing the original object instance
4130                  */
4131                 if ((ptype->attrs & PARAM_ATTRIBUTE_OUT) != 0 && mt == MONO_MARSHAL_COPY && !ptype->byref)
4132                         mt = MONO_MARSHAL_COPY_OUT;
4133                 else if (mt == MONO_MARSHAL_SERIALIZE) {
4134                         complex_count++;
4135                         if (ptype->byref) complex_out_count++;
4136                 }
4137                 marshal_types [i] = mt;
4138         }
4139
4140         if (sig->ret->type != MONO_TYPE_VOID) {
4141                 ret_marshal_type = mono_get_xdomain_marshal_type (sig->ret);
4142                 ret_class = mono_class_from_mono_type (sig->ret);
4143                 copy_return = ret_marshal_type != MONO_MARSHAL_SERIALIZE;
4144         }
4145         
4146         /* Locals */
4147
4148         if (complex_count > 0)
4149                 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4150         loc_serialized_data = mono_mb_add_local (mb, &byte_array_class->byval_arg);
4151         loc_real_proxy = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4152         if (copy_return)
4153                 loc_return = mono_mb_add_local (mb, sig->ret);
4154         loc_old_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
4155         loc_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
4156         loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
4157         loc_context = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4158
4159         /* Save thread domain data */
4160
4161         mono_mb_emit_icall (mb, mono_context_get);
4162         mono_mb_emit_byte (mb, CEE_DUP);
4163         mono_mb_emit_stloc (mb, loc_context);
4164
4165         /* If the thread is not running in the default context, it needs to go
4166          * through the whole remoting sink, since the context is going to change
4167          */
4168         mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL);
4169         pos = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
4170         
4171         /* Another case in which the fast path can't be used: when the target domain
4172          * has a different image for the same assembly.
4173          */
4174
4175         /* Get the target domain id */
4176
4177         mono_mb_emit_ldarg (mb, 0);
4178         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
4179         mono_mb_emit_byte (mb, CEE_LDIND_REF);
4180         mono_mb_emit_byte (mb, CEE_DUP);
4181         mono_mb_emit_stloc (mb, loc_real_proxy);
4182
4183         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
4184         mono_mb_emit_byte (mb, CEE_LDIND_I4);
4185         mono_mb_emit_stloc (mb, loc_domainid);
4186
4187         /* Check if the target domain has the same image for the required assembly */
4188
4189         mono_mb_emit_ldloc (mb, loc_domainid);
4190         mono_mb_emit_ptr (mb, method->klass->image);
4191         mono_mb_emit_icall (mb, mono_marshal_check_domain_image);
4192         pos_dispatch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
4193
4194         /* Use the whole remoting sink to dispatch this message */
4195
4196         mono_mb_patch_short_branch (mb, pos);
4197
4198         mono_mb_emit_ldarg (mb, 0);
4199         for (i = 0; i < sig->param_count; i++)
4200                 mono_mb_emit_ldarg (mb, i + 1);
4201         
4202         mono_mb_emit_managed_call (mb, mono_marshal_get_remoting_invoke (method), NULL);
4203         mono_mb_emit_byte (mb, CEE_RET);
4204         mono_mb_patch_short_branch (mb, pos_dispatch);
4205
4206         /* Create the array that will hold the parameters to be serialized */
4207
4208         if (complex_count > 0) {
4209                 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 */
4210                 mono_mb_emit_op (mb, CEE_NEWARR, mono_defaults.object_class);
4211         
4212                 j = 0;
4213                 for (i = 0; i < sig->param_count; i++) {
4214                         MonoClass *pclass;
4215                         if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
4216                         pclass = mono_class_from_mono_type (sig->params[i]);
4217                         mono_mb_emit_byte (mb, CEE_DUP);
4218                         mono_mb_emit_icon (mb, j);
4219                         mono_mb_emit_ldarg (mb, i + 1);         /* 0=this */
4220                         if (sig->params[i]->byref) {
4221                                 if (pclass->valuetype)
4222                                         mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
4223                                 else
4224                                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
4225                         }
4226                         if (pclass->valuetype)
4227                                 mono_mb_emit_op (mb, CEE_BOX, pclass);
4228                         mono_mb_emit_byte (mb, CEE_STELEM_REF);
4229                         j++;
4230                 }
4231                 mono_mb_emit_stloc (mb, loc_array);
4232
4233                 /* Serialize parameters */
4234         
4235                 mono_mb_emit_ldloc (mb, loc_array);
4236                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
4237                 mono_mb_emit_stloc (mb, loc_serialized_data);
4238         } else {
4239                 mono_mb_emit_byte (mb, CEE_LDNULL);
4240                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
4241                 mono_mb_emit_stloc (mb, loc_serialized_data);
4242         }
4243
4244         /* switch domain */
4245
4246         mono_mb_emit_ldloc (mb, loc_domainid);
4247         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
4248         mono_marshal_emit_switch_domain (mb);
4249         mono_mb_emit_stloc (mb, loc_old_domainid);
4250
4251         /* Load the arguments */
4252         
4253         mono_mb_emit_ldloc (mb, loc_real_proxy);
4254         mono_mb_emit_ldloc_addr (mb, loc_serialized_data);
4255         mono_mb_emit_ldloc_addr (mb, loc_serialized_exc);
4256
4257         copy_locals_base = mb->locals;
4258         for (i = 0; i < sig->param_count; i++) {
4259                 switch (marshal_types [i]) {
4260                 case MONO_MARSHAL_SERIALIZE:
4261                         continue;
4262                 case MONO_MARSHAL_COPY: {
4263                         mono_mb_emit_ldarg (mb, i+1);
4264                         if (sig->params [i]->byref) {
4265                                 /* make a local copy of the byref parameter. The real parameter
4266                                  * will be updated after the xdomain call
4267                                  */
4268                                 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
4269                                 int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
4270                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
4271                                 mono_mb_emit_stloc (mb, copy_local);
4272                                 mono_mb_emit_ldloc_addr (mb, copy_local);
4273                         }
4274                         break;
4275                 }
4276                 case MONO_MARSHAL_COPY_OUT:
4277                 case MONO_MARSHAL_NONE:
4278                         mono_mb_emit_ldarg (mb, i+1);
4279                         break;
4280                 }
4281         }
4282
4283         /* Make the call to the invoke wrapper in the target domain */
4284
4285         xdomain_method = mono_marshal_get_xappdomain_dispatch (method, marshal_types, complex_count, complex_out_count, ret_marshal_type);
4286         mono_marshal_emit_load_domain_method (mb, xdomain_method);
4287         mono_mb_emit_calli (mb, mono_method_signature (xdomain_method));
4288
4289         if (copy_return)
4290                 mono_mb_emit_stloc (mb, loc_return);
4291
4292         /* Switch domain */
4293
4294         mono_mb_emit_ldloc (mb, loc_old_domainid);
4295         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4296         mono_marshal_emit_switch_domain (mb);
4297         mono_mb_emit_byte (mb, CEE_POP);
4298         
4299         /* Restore thread domain data */
4300         
4301         mono_mb_emit_ldloc (mb, loc_context);
4302         mono_mb_emit_icall (mb, mono_context_set);
4303         
4304         /* if (loc_serialized_exc != null) ... */
4305
4306         mono_mb_emit_ldloc (mb, loc_serialized_exc);
4307         pos_noex = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
4308
4309         mono_mb_emit_ldloc (mb, loc_serialized_exc);
4310         mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
4311         mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
4312         mono_mb_emit_op (mb, CEE_CASTCLASS, mono_defaults.exception_class);
4313         mono_mb_emit_managed_call (mb, method_exc_fixexc, NULL);
4314         mono_mb_emit_byte (mb, CEE_THROW);
4315         mono_mb_patch_short_branch (mb, pos_noex);
4316
4317         /* copy back non-serialized output parameters */
4318
4319         j = 0;
4320         for (i = 0; i < sig->param_count; i++) {
4321                 if (!sig->params [i]->byref || marshal_types [i] != MONO_MARSHAL_COPY) continue;
4322                 mono_mb_emit_ldarg (mb, i + 1);
4323                 mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
4324                 mono_marshal_emit_xdomain_copy_value (mb, mono_class_from_mono_type (sig->params [i]));
4325                 mono_mb_emit_byte (mb, CEE_STIND_REF);
4326         }
4327
4328         /* Deserialize out parameters */
4329
4330         if (complex_out_count > 0) {
4331                 mono_mb_emit_ldloc (mb, loc_serialized_data);
4332                 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
4333                 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
4334                 mono_mb_emit_stloc (mb, loc_array);
4335         
4336                 /* Copy back output parameters and return type */
4337                 
4338                 j = 0;
4339                 for (i = 0; i < sig->param_count; i++) {
4340                         if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
4341                         if (sig->params[i]->byref) {
4342                                 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
4343                                 mono_mb_emit_ldarg (mb, i + 1);
4344                                 mono_mb_emit_ldloc (mb, loc_array);
4345                                 mono_mb_emit_icon (mb, j);
4346                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4347                                 if (pclass->valuetype) {
4348                                         mono_mb_emit_op (mb, CEE_UNBOX, pclass);
4349                                         mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
4350                                         mono_mb_emit_op (mb, CEE_STOBJ, pclass);
4351                                 } else {
4352                                         if (pclass != mono_defaults.object_class)
4353                                                 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
4354                                         mono_mb_emit_byte (mb, CEE_STIND_REF);
4355                                 }
4356                         }
4357                         j++;
4358                 }
4359         
4360                 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
4361                         mono_mb_emit_ldloc (mb, loc_array);
4362                         mono_mb_emit_icon (mb, complex_count);
4363                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4364                         if (ret_class->valuetype) {
4365                                 mono_mb_emit_op (mb, CEE_UNBOX, ret_class);
4366                                 mono_mb_emit_op (mb, CEE_LDOBJ, ret_class);
4367                         }
4368                 }
4369         } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
4370                 mono_mb_emit_ldloc (mb, loc_serialized_data);
4371                 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
4372                 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
4373                 if (ret_class->valuetype) {
4374                         mono_mb_emit_op (mb, CEE_UNBOX, ret_class);
4375                         mono_mb_emit_op (mb, CEE_LDOBJ, ret_class);
4376                 } else if (ret_class != mono_defaults.object_class) {
4377                         mono_mb_emit_op (mb, CEE_CASTCLASS, ret_class);
4378                 }
4379         } else {
4380                 mono_mb_emit_ldloc (mb, loc_serialized_data);
4381                 mono_mb_emit_byte (mb, CEE_DUP);
4382                 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
4383                 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
4384         
4385                 mono_mb_patch_short_branch (mb, pos);
4386                 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
4387                 mono_mb_emit_byte (mb, CEE_POP);
4388         }
4389
4390         if (copy_return) {
4391                 mono_mb_emit_ldloc (mb, loc_return);
4392                 if (ret_marshal_type == MONO_MARSHAL_COPY)
4393                         mono_marshal_emit_xdomain_copy_value (mb, ret_class);
4394         }
4395
4396         mono_mb_emit_byte (mb, CEE_RET);
4397
4398         res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
4399         mono_mb_free (mb);
4400
4401         return res;
4402 }
4403
4404 MonoMethod *
4405 mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTarget target_type)
4406 {
4407         if (target_type == MONO_REMOTING_TARGET_APPDOMAIN) {
4408                 return mono_marshal_get_xappdomain_invoke (method);
4409         } else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) {
4410 #ifndef DISABLE_COM
4411                 return cominterop_get_invoke (method);
4412 #else
4413                 g_assert_not_reached ();
4414 #endif
4415         } else {
4416                 return mono_marshal_get_remoting_invoke (method);
4417         }
4418 }
4419
4420 G_GNUC_UNUSED static gpointer
4421 mono_marshal_load_remoting_wrapper (MonoRealProxy *rp, MonoMethod *method)
4422 {
4423         if (rp->target_domain_id != -1)
4424                 return mono_compile_method (mono_marshal_get_xappdomain_invoke (method));
4425         else
4426                 return mono_compile_method (mono_marshal_get_remoting_invoke (method));
4427 }
4428
4429 MonoMethod *
4430 mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
4431 {
4432         MonoMethodSignature *sig;
4433         MonoMethodBuilder *mb;
4434         MonoMethod *res, *native;
4435         int i, pos, pos_rem;
4436
4437         g_assert (method);
4438
4439         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
4440                 return method;
4441
4442         /* we cant remote methods without this pointer */
4443         g_assert (mono_method_signature (method)->hasthis);
4444
4445         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
4446                 return res;
4447
4448         sig = mono_signature_no_pinvoke (method);
4449         
4450         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
4451
4452         for (i = 0; i <= sig->param_count; i++)
4453                 mono_mb_emit_ldarg (mb, i);
4454         
4455         mono_mb_emit_ldarg (mb, 0);
4456         pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
4457
4458         if (mono_marshal_supports_fast_xdomain (method)) {
4459                 mono_mb_emit_ldarg (mb, 0);
4460                 pos_rem = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
4461                 
4462                 /* wrapper for cross app domain calls */
4463                 native = mono_marshal_get_xappdomain_invoke (method);
4464                 mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
4465                 mono_mb_emit_byte (mb, CEE_RET);
4466                 
4467                 mono_mb_patch_branch (mb, pos_rem);
4468         }
4469         /* wrapper for normal remote calls */
4470         native = mono_marshal_get_remoting_invoke (method);
4471         mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
4472         mono_mb_emit_byte (mb, CEE_RET);
4473
4474         /* not a proxy */
4475         mono_mb_patch_branch (mb, pos);
4476         mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
4477         mono_mb_emit_byte (mb, CEE_RET);
4478
4479         res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16);
4480         mono_mb_free (mb);
4481
4482         return res;
4483 }
4484
4485 typedef struct
4486 {
4487         MonoMethodSignature *sig;
4488         MonoMethod *method;
4489 } SignatureMethodPair;
4490
4491 static guint
4492 signature_method_pair_hash (gconstpointer data)
4493 {
4494         SignatureMethodPair *pair = (SignatureMethodPair*)data;
4495
4496         return mono_signature_hash (pair->sig) ^ mono_aligned_addr_hash (pair->method);
4497 }
4498
4499 static gboolean
4500 signature_method_pair_equal (SignatureMethodPair *pair1, SignatureMethodPair *pair2)
4501 {
4502         return mono_metadata_signature_equal (pair1->sig, pair2->sig) && (pair1->method == pair2->method);
4503 }
4504
4505 static void
4506 free_signature_method_pair (SignatureMethodPair *pair)
4507 {
4508         g_free (pair);
4509 }
4510
4511 /*
4512  * the returned method invokes all methods in a multicast delegate.
4513  */
4514 MonoMethod *
4515 mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
4516 {
4517         MonoMethodSignature *sig, *static_sig;
4518         int i;
4519         MonoMethodBuilder *mb;
4520         MonoMethod *res, *newm;
4521         GHashTable *cache;
4522         SignatureMethodPair key;
4523         SignatureMethodPair *new_key;
4524         int local_prev, local_target;
4525         int pos0;
4526         char *name;
4527         MonoMethod *target_method = NULL;
4528         MonoClass *target_class = NULL;
4529         gboolean callvirt = FALSE;
4530
4531         /*
4532          * If the delegate target is null, and the target method is not static, a virtual 
4533          * call is made to that method with the first delegate argument as this. This is 
4534          * a non-documented .NET feature.
4535          */
4536         if (del && !del->target && del->method && mono_method_signature (del->method)->hasthis) {
4537                 callvirt = TRUE;
4538                 target_method = del->method;
4539                 if (target_method->is_inflated) {
4540                         MonoType *target_type;
4541
4542                         g_assert (method->signature->hasthis);
4543                         target_type = mono_class_inflate_generic_type (method->signature->params [0],
4544                                 mono_method_get_context (method));
4545                         target_class = mono_class_from_mono_type (target_type);
4546                 } else {
4547                         target_class = del->method->klass;
4548                 }
4549         }
4550
4551         g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
4552                   !strcmp (method->name, "Invoke"));
4553                 
4554         sig = mono_signature_no_pinvoke (method);
4555
4556         if (callvirt) {
4557                 /* We need to cache the signature+method pair */
4558                 mono_marshal_lock ();
4559                 if (!method->klass->image->delegate_abstract_invoke_cache)
4560                         method->klass->image->delegate_abstract_invoke_cache = g_hash_table_new_full (signature_method_pair_hash, (GEqualFunc)signature_method_pair_equal, (GDestroyNotify)free_signature_method_pair, NULL);
4561                 cache = method->klass->image->delegate_abstract_invoke_cache;
4562                 key.sig = sig;
4563                 key.method = target_method;
4564                 res = g_hash_table_lookup (cache, &key);
4565                 mono_marshal_unlock ();
4566                 if (res)
4567                         return res;
4568         } else {
4569                 cache = get_cache (&method->klass->image->delegate_invoke_cache,
4570                                                    (GHashFunc)mono_signature_hash, 
4571                                                    (GCompareFunc)mono_metadata_signature_equal);
4572                 if ((res = mono_marshal_find_in_cache (cache, sig)))
4573                         return res;
4574         }
4575
4576         static_sig = signature_dup (method->klass->image, sig);
4577         static_sig->hasthis = 0;
4578
4579         name = mono_signature_to_name (sig, "invoke");
4580         mb = mono_mb_new (method->klass, name,  MONO_WRAPPER_DELEGATE_INVOKE);
4581         g_free (name);
4582
4583         /* allocate local 0 (object) */
4584         local_target = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4585         local_prev = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4586
4587         g_assert (sig->hasthis);
4588         
4589         /*
4590          * if (prev != null)
4591          *      prev.Invoke( args .. );
4592          * return this.<target>( args .. );
4593          */
4594         
4595         /* this wrapper can be used in unmanaged-managed transitions */
4596         emit_thread_interrupt_checkpoint (mb);
4597         
4598         /* get this->prev */
4599         mono_mb_emit_ldarg (mb, 0);
4600         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
4601         mono_mb_emit_byte (mb, CEE_LDIND_REF);
4602         mono_mb_emit_stloc (mb, local_prev);
4603         mono_mb_emit_ldloc (mb, local_prev);
4604
4605         /* if prev != null */
4606         pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4607
4608         /* then recurse */
4609
4610         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4611         mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
4612
4613         mono_mb_emit_ldloc (mb, local_prev);
4614         for (i = 0; i < sig->param_count; i++)
4615                 mono_mb_emit_ldarg (mb, i + 1);
4616         mono_mb_emit_op (mb, CEE_CALLVIRT, method);
4617         if (sig->ret->type != MONO_TYPE_VOID)
4618                 mono_mb_emit_byte (mb, CEE_POP);
4619
4620         /* continued or prev == null */
4621         mono_mb_patch_branch (mb, pos0);
4622
4623         /* get this->target */
4624         mono_mb_emit_ldarg (mb, 0);
4625         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, target));
4626         mono_mb_emit_byte (mb, CEE_LDIND_REF);
4627         mono_mb_emit_stloc (mb, local_target);
4628
4629         /* if target != null */
4630         mono_mb_emit_ldloc (mb, local_target);
4631         pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4632         
4633         /* then call this->method_ptr nonstatic */
4634         if (callvirt) {
4635                 // FIXME:
4636                 mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
4637         } else {
4638                 mono_mb_emit_ldloc (mb, local_target); 
4639                 for (i = 0; i < sig->param_count; ++i)
4640                         mono_mb_emit_ldarg (mb, i + 1);
4641                 mono_mb_emit_ldarg (mb, 0);
4642                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4643                 mono_mb_emit_byte (mb, CEE_LDIND_I );
4644                 mono_mb_emit_op (mb, CEE_CALLI, sig);
4645
4646                 mono_mb_emit_byte (mb, CEE_RET);
4647         }
4648
4649         /* else [target == null] call this->method_ptr static */
4650         mono_mb_patch_branch (mb, pos0);
4651
4652         if (callvirt) {
4653                 mono_mb_emit_ldarg (mb, 1);
4654                 mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
4655                 for (i = 1; i < sig->param_count; ++i)
4656                         mono_mb_emit_ldarg (mb, i + 1);
4657                 mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
4658         } else {
4659                 for (i = 0; i < sig->param_count; ++i)
4660                         mono_mb_emit_ldarg (mb, i + 1);
4661                 mono_mb_emit_ldarg (mb, 0);
4662                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4663                 mono_mb_emit_byte (mb, CEE_LDIND_I );
4664                 mono_mb_emit_op (mb, CEE_CALLI, static_sig);
4665         }
4666
4667         mono_mb_emit_byte (mb, CEE_RET);
4668
4669         if (callvirt) {
4670                 // From mono_mb_create_and_cache
4671                 newm = mono_mb_create_method (mb, sig, sig->param_count + 16);
4672                 newm->skip_visibility = 1;
4673                 /*We perform double checked locking, so must fence before publishing*/
4674                 mono_memory_barrier ();
4675                 mono_marshal_lock ();
4676                 res = g_hash_table_lookup (cache, &key);
4677                 if (!res) {
4678                         res = newm;
4679                         new_key = g_new0 (SignatureMethodPair, 1);
4680                         new_key->sig = sig;
4681                         new_key->method = target_method;
4682                         g_hash_table_insert (cache, new_key, res);
4683                         mono_marshal_method_set_wrapper_data (res, new_key);
4684                         mono_marshal_unlock ();
4685                 } else {
4686                         mono_marshal_unlock ();
4687                         mono_free_method (newm);
4688                 }
4689         } else {
4690                 res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
4691                 res->skip_visibility = 1;
4692         }
4693         mono_mb_free (mb);
4694
4695         return res;     
4696 }
4697
4698 /*
4699  * signature_dup_add_this:
4700  *
4701  *  Make a copy of @sig, adding an explicit this argument.
4702  */
4703 static MonoMethodSignature*
4704 signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass)
4705 {
4706         MonoMethodSignature *res;
4707         int i;
4708
4709         res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1);
4710         memcpy (res, sig, sizeof (MonoMethodSignature));
4711         res->param_count = sig->param_count + 1;
4712         res->hasthis = FALSE;
4713         for (i = sig->param_count - 1; i >= 0; i --)
4714                 res->params [i + 1] = sig->params [i];
4715         res->params [0] = &mono_ptr_class_get (&klass->byval_arg)->byval_arg;
4716
4717         return res;
4718 }
4719
4720 typedef struct {
4721         MonoMethodSignature *ctor_sig;
4722         MonoMethodSignature *sig;
4723 } CtorSigPair;
4724
4725 /* protected by the marshal lock, contains CtorSigPair pointers */
4726 static GSList *strsig_list = NULL;
4727
4728 static MonoMethodSignature *
4729 lookup_string_ctor_signature (MonoMethodSignature *sig)
4730 {
4731         MonoMethodSignature *callsig;
4732         CtorSigPair *cs;
4733         GSList *item;
4734
4735         mono_marshal_lock ();
4736         callsig = NULL;
4737         for (item = strsig_list; item; item = item->next) {
4738                 cs = item->data;
4739                 /* mono_metadata_signature_equal () is safe to call with the marshal lock
4740                  * because it is lock-free.
4741                  */
4742                 if (mono_metadata_signature_equal (sig, cs->ctor_sig)) {
4743                         callsig = cs->sig;
4744                         break;
4745                 }
4746         }
4747         mono_marshal_unlock ();
4748         return callsig;
4749 }
4750
4751 static MonoMethodSignature *
4752 add_string_ctor_signature (MonoMethod *method)
4753 {
4754         MonoMethodSignature *callsig;
4755         CtorSigPair *cs;
4756
4757         callsig = signature_dup (method->klass->image, mono_method_signature (method));
4758         callsig->ret = &mono_defaults.string_class->byval_arg;
4759         cs = g_new (CtorSigPair, 1);
4760         cs->sig = callsig;
4761         cs->ctor_sig = mono_method_signature (method);
4762
4763         mono_marshal_lock ();
4764         strsig_list = g_slist_prepend (strsig_list, cs);
4765         mono_marshal_unlock ();
4766         return callsig;
4767 }
4768
4769 static MonoType*
4770 get_runtime_invoke_type (MonoType *t)
4771 {
4772         if (t->byref)
4773                 return &mono_defaults.int_class->byval_arg;
4774
4775         switch (t->type) {
4776         case MONO_TYPE_U1:
4777                 return &mono_defaults.sbyte_class->byval_arg;
4778         case MONO_TYPE_U2:
4779                 return &mono_defaults.int16_class->byval_arg;
4780         case MONO_TYPE_U4:
4781                 return &mono_defaults.int32_class->byval_arg;
4782         case MONO_TYPE_U8:
4783                 return &mono_defaults.int64_class->byval_arg;
4784         case MONO_TYPE_BOOLEAN:
4785                 return &mono_defaults.byte_class->byval_arg;
4786         case MONO_TYPE_CHAR:
4787                 return &mono_defaults.int16_class->byval_arg;
4788         case MONO_TYPE_U:
4789                 return &mono_defaults.int_class->byval_arg;
4790         case MONO_TYPE_VALUETYPE:
4791                 if (t->data.klass->enumtype)
4792                         return mono_type_get_underlying_type (t);
4793                 else
4794                         return t;
4795         default:
4796                 if (MONO_TYPE_IS_REFERENCE (t))
4797                         return &mono_defaults.object_class->byval_arg;
4798                 return t;
4799         }
4800 }
4801
4802 /*
4803  * mono_marshal_get_runtime_invoke_sig:
4804  *
4805  *   Return a common signature used for sharing runtime invoke wrappers.
4806  */
4807 static MonoMethodSignature*
4808 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig)
4809 {
4810         MonoMethodSignature *res = mono_metadata_signature_dup (sig);
4811         int i;
4812
4813         res->ret = get_runtime_invoke_type (sig->ret);
4814         for (i = 0; i < res->param_count; ++i)
4815                 res->params [i] = get_runtime_invoke_type (sig->params [i]);
4816
4817         return res;
4818 }
4819
4820 static gboolean
4821 runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
4822 {
4823         /* Can't share wrappers which return a vtype since it needs to be boxed */
4824         if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)))
4825                 return FALSE;
4826         else
4827                 return mono_metadata_signature_equal (sig1, sig2);
4828 }
4829
4830 /*
4831  * generates IL code for the runtime invoke function 
4832  * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
4833  *
4834  * we also catch exceptions if exc != null
4835  */
4836 MonoMethod *
4837 mono_marshal_get_runtime_invoke (MonoMethod *method)
4838 {
4839         MonoMethodSignature *sig, *csig, *callsig;
4840         MonoExceptionClause *clause;
4841         MonoMethodBuilder *mb;
4842         GHashTable *cache = NULL;
4843         MonoClass *target_klass;
4844         MonoMethod *res = NULL;
4845         static MonoString *string_dummy = NULL;
4846         static MonoMethodSignature *cctor_signature = NULL;
4847         static MonoMethodSignature *finalize_signature = NULL;
4848         int i, pos, posna;
4849         char *name;
4850         gboolean need_direct_wrapper = FALSE;
4851
4852         g_assert (method);
4853
4854         if (!cctor_signature) {
4855                 cctor_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4856                 cctor_signature->ret = &mono_defaults.void_class->byval_arg;
4857         }
4858         if (!finalize_signature) {
4859                 finalize_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4860                 finalize_signature->ret = &mono_defaults.void_class->byval_arg;
4861                 finalize_signature->hasthis = 1;
4862         }
4863
4864         /* 
4865          * Use a separate cache indexed by methods to speed things up and to avoid the
4866          * boundless mempool growth caused by the signature_dup stuff below.
4867          */
4868         cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
4869         res = mono_marshal_find_in_cache (cache, method);
4870         if (res)
4871                 return res;
4872
4873         if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
4874                 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
4875                 /* 
4876                  * Array Get/Set/Address methods. The JIT implements them using inline code
4877                  * so we need to create an invoke wrapper which calls the method directly.
4878                  */
4879                 need_direct_wrapper = TRUE;
4880         }
4881                 
4882         if (method->string_ctor) {
4883                 callsig = lookup_string_ctor_signature (mono_method_signature (method));
4884                 if (!callsig)
4885                         callsig = add_string_ctor_signature (method);
4886         } else {
4887                 if (method->klass->valuetype && mono_method_signature (method)->hasthis) {
4888                         /* 
4889                          * Valuetype methods receive a managed pointer as the this argument.
4890                          * Create a new signature to reflect this.
4891                          */
4892                         callsig = signature_dup_add_this (mono_method_signature (method), method->klass);
4893                 } else {
4894                         if (method->dynamic)
4895                                 callsig = signature_dup (method->klass->image, mono_method_signature (method));
4896                         else
4897                                 callsig = mono_method_signature (method);
4898                 }
4899         }
4900
4901         /*
4902          * We try to share runtime invoke wrappers between different methods but have to
4903          * be careful about methods whose klass has a type cctor, since putting the wrapper
4904          * into that klass would mean that calling a method of klass A might invoke the
4905          * type initializer of class B, or throw an exception if the type initializer 
4906          * was called before and failed. See #349621 for an example. 
4907          * We avoid that for mscorlib methods by putting every wrapper into the object class.
4908          */
4909         if (method->klass->image == mono_defaults.corlib)
4910                 target_klass = mono_defaults.object_class;
4911         else {
4912                 /* Try to share wrappers for non-corlib methods with simple signatures */
4913                 if (mono_metadata_signature_equal (callsig, cctor_signature)) {
4914                         callsig = cctor_signature;
4915                         target_klass = mono_defaults.object_class;
4916                 } else if (mono_metadata_signature_equal (callsig, finalize_signature)) {
4917                         callsig = finalize_signature;
4918                         target_klass = mono_defaults.object_class;
4919                 } else {
4920                         // FIXME: This breaks too many things
4921                         /*
4922                         if (mono_class_get_cctor (method->klass))
4923                                 need_direct_wrapper = TRUE;
4924                         */
4925
4926                         /*
4927                          * Can't put these wrappers into object, since they reference non-corlib
4928                          * metadata (callsig).
4929                          */
4930                         target_klass = method->klass;
4931                 }
4932         }
4933
4934         if (need_direct_wrapper) {
4935                 /* Already searched at the start */
4936         } else {
4937                 callsig = mono_marshal_get_runtime_invoke_sig (callsig);
4938
4939                 cache = get_cache (&target_klass->image->runtime_invoke_cache, 
4940                                                    (GHashFunc)mono_signature_hash, 
4941                                                    (GCompareFunc)runtime_invoke_signature_equal);
4942
4943                 /* from mono_marshal_find_in_cache */
4944                 mono_marshal_lock ();
4945                 res = g_hash_table_lookup (cache, callsig);
4946                 mono_marshal_unlock ();
4947
4948                 if (res) {
4949                         g_free (callsig);
4950                         return res;
4951                 }
4952
4953                 // FIXME: When to free callsig ?
4954         }
4955         
4956         /* to make it work with our special string constructors */
4957         if (!string_dummy) {
4958                 MONO_GC_REGISTER_ROOT (string_dummy);
4959                 string_dummy = mono_string_new_wrapper ("dummy");
4960         }
4961         
4962         sig = mono_method_signature (method);
4963
4964         csig = mono_metadata_signature_alloc (target_klass->image, 4);
4965
4966         csig->ret = &mono_defaults.object_class->byval_arg;
4967         if (method->klass->valuetype && mono_method_signature (method)->hasthis)
4968                 csig->params [0] = callsig->params [0];
4969         else
4970                 csig->params [0] = &mono_defaults.object_class->byval_arg;
4971         csig->params [1] = &mono_defaults.int_class->byval_arg;
4972         csig->params [2] = &mono_defaults.int_class->byval_arg;
4973         csig->params [3] = &mono_defaults.int_class->byval_arg;
4974
4975         name = mono_signature_to_name (callsig, "runtime_invoke");
4976         mb = mono_mb_new (target_klass, name,  MONO_WRAPPER_RUNTIME_INVOKE);
4977         g_free (name);
4978
4979         /* allocate local 0 (object) tmp */
4980         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4981         /* allocate local 1 (object) exc */
4982         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4983
4984         /* cond set *exc to null */
4985         mono_mb_emit_byte (mb, CEE_LDARG_2);
4986         mono_mb_emit_byte (mb, CEE_BRFALSE_S);
4987         mono_mb_emit_byte (mb, 3);      
4988         mono_mb_emit_byte (mb, CEE_LDARG_2);
4989         mono_mb_emit_byte (mb, CEE_LDNULL);
4990         mono_mb_emit_byte (mb, CEE_STIND_REF);
4991
4992         emit_thread_force_interrupt_checkpoint (mb);
4993
4994         if (sig->hasthis) {
4995                 if (method->string_ctor) {
4996                         mono_mb_emit_ptr (mb, string_dummy);
4997                 } else {
4998                         mono_mb_emit_ldarg (mb, 0);
4999                 }
5000         }
5001
5002         for (i = 0; i < sig->param_count; i++) {
5003                 MonoType *t = sig->params [i];
5004                 int type;
5005
5006                 mono_mb_emit_ldarg (mb, 1);
5007                 if (i) {
5008                         mono_mb_emit_icon (mb, sizeof (gpointer) * i);
5009                         mono_mb_emit_byte (mb, CEE_ADD);
5010                 }
5011
5012                 if (t->byref) {
5013                         mono_mb_emit_byte (mb, CEE_LDIND_I);
5014                         /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
5015                          * So to make this work we unbox it to a local variablee and push a reference to that.
5016                          */
5017                         if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
5018                                 int tmp_nullable_local = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg);
5019
5020                                 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t));
5021                                 mono_mb_emit_stloc (mb, tmp_nullable_local);
5022                                 mono_mb_emit_ldloc_addr (mb, tmp_nullable_local);
5023                         }
5024                         continue;
5025                 }
5026
5027                 type = sig->params [i]->type;
5028 handle_enum:
5029                 switch (type) {
5030                 case MONO_TYPE_I1:
5031                 case MONO_TYPE_BOOLEAN:
5032                 case MONO_TYPE_U1:
5033                 case MONO_TYPE_I2:
5034                 case MONO_TYPE_U2:
5035                 case MONO_TYPE_CHAR:
5036                 case MONO_TYPE_I:
5037                 case MONO_TYPE_U:
5038                 case MONO_TYPE_I4:
5039                 case MONO_TYPE_U4:
5040                 case MONO_TYPE_R4:
5041                 case MONO_TYPE_R8:
5042                 case MONO_TYPE_I8:
5043                 case MONO_TYPE_U8:
5044                         mono_mb_emit_byte (mb, CEE_LDIND_I);
5045                         mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
5046                         break;
5047                 case MONO_TYPE_STRING:
5048                 case MONO_TYPE_CLASS:  
5049                 case MONO_TYPE_ARRAY:
5050                 case MONO_TYPE_PTR:
5051                 case MONO_TYPE_SZARRAY:
5052                 case MONO_TYPE_OBJECT:
5053                         mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
5054                         break;
5055                 case MONO_TYPE_GENERICINST:
5056                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
5057                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
5058                                 break;
5059                         }
5060
5061                         /* fall through */
5062                 case MONO_TYPE_VALUETYPE:
5063                         if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) {
5064                                 type = t->data.klass->enum_basetype->type;
5065                                 goto handle_enum;
5066                         }
5067                         mono_mb_emit_byte (mb, CEE_LDIND_I);
5068                         if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
5069                                 /* Need to convert a boxed vtype to an mp to a Nullable struct */
5070                                 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (sig->params [i]));
5071                                 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
5072                         } else {
5073                                 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
5074                         }
5075                         break;
5076                 default:
5077                         g_assert_not_reached ();
5078                 }               
5079         }
5080         
5081         if (need_direct_wrapper) {
5082                 mono_mb_emit_op (mb, CEE_CALL, method);
5083         } else {
5084                 mono_mb_emit_ldarg (mb, 3);
5085                 mono_mb_emit_calli (mb, callsig);
5086         }
5087
5088         if (sig->ret->byref) {
5089                 /* fixme: */
5090                 g_assert_not_reached ();
5091         }
5092
5093
5094         switch (sig->ret->type) {
5095         case MONO_TYPE_VOID:
5096                 if (!method->string_ctor)
5097                         mono_mb_emit_byte (mb, CEE_LDNULL);
5098                 break;
5099         case MONO_TYPE_BOOLEAN:
5100         case MONO_TYPE_CHAR:
5101         case MONO_TYPE_I1:
5102         case MONO_TYPE_U1:
5103         case MONO_TYPE_I2:
5104         case MONO_TYPE_U2:
5105         case MONO_TYPE_I4:
5106         case MONO_TYPE_U4:
5107         case MONO_TYPE_I:
5108         case MONO_TYPE_U:
5109         case MONO_TYPE_R4:
5110         case MONO_TYPE_R8:
5111         case MONO_TYPE_I8:
5112         case MONO_TYPE_U8:
5113         case MONO_TYPE_VALUETYPE:
5114         case MONO_TYPE_TYPEDBYREF:
5115         case MONO_TYPE_GENERICINST:
5116                 /* box value types */
5117                 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
5118                 break;
5119         case MONO_TYPE_STRING:
5120         case MONO_TYPE_CLASS:  
5121         case MONO_TYPE_ARRAY:
5122         case MONO_TYPE_SZARRAY:
5123         case MONO_TYPE_OBJECT:
5124                 /* nothing to do */
5125                 break;
5126         case MONO_TYPE_PTR:
5127         default:
5128                 g_assert_not_reached ();
5129         }
5130
5131         mono_mb_emit_stloc (mb, 0);
5132                 
5133         pos = mono_mb_emit_branch (mb, CEE_LEAVE);
5134
5135         mono_loader_lock ();
5136         clause = mono_image_alloc0 (target_klass->image, sizeof (MonoExceptionClause));
5137         mono_loader_unlock ();
5138         clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
5139         clause->try_len = mono_mb_get_label (mb);
5140
5141         /* filter code */
5142         clause->data.filter_offset = mono_mb_get_label (mb);
5143         
5144         mono_mb_emit_byte (mb, CEE_POP);
5145         mono_mb_emit_byte (mb, CEE_LDARG_2);
5146         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5147         mono_mb_emit_byte (mb, CEE_PREFIX1);
5148         mono_mb_emit_byte (mb, CEE_CGT_UN);
5149         mono_mb_emit_byte (mb, CEE_PREFIX1);
5150         mono_mb_emit_byte (mb, CEE_ENDFILTER);
5151
5152         clause->handler_offset = mono_mb_get_label (mb);
5153
5154         /* handler code */
5155         /* store exception */
5156         mono_mb_emit_stloc (mb, 1);
5157         
5158         mono_mb_emit_byte (mb, CEE_LDARG_2);
5159         mono_mb_emit_ldloc (mb, 1);
5160         mono_mb_emit_byte (mb, CEE_STIND_REF);
5161
5162         mono_mb_emit_byte (mb, CEE_LDNULL);
5163         mono_mb_emit_stloc (mb, 0);
5164
5165         /* Check for the abort exception */
5166         mono_mb_emit_ldloc (mb, 1);
5167         mono_mb_emit_op (mb, CEE_ISINST, mono_defaults.threadabortexception_class);
5168         posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
5169
5170         /* Delay the abort exception */
5171         mono_mb_emit_icall (mb, ves_icall_System_Threading_Thread_ResetAbort);
5172
5173         mono_mb_patch_short_branch (mb, posna);
5174         mono_mb_emit_branch (mb, CEE_LEAVE);
5175
5176         clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
5177
5178         mono_mb_set_clauses (mb, 1, clause);
5179
5180         /* return result */
5181         mono_mb_patch_branch (mb, pos);
5182         mono_mb_emit_ldloc (mb, 0);
5183         mono_mb_emit_byte (mb, CEE_RET);
5184
5185         if (need_direct_wrapper) {
5186                 res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16);
5187         } else {
5188                 /* taken from mono_mb_create_and_cache */
5189                 mono_marshal_lock ();
5190                 res = g_hash_table_lookup (cache, callsig);
5191                 mono_marshal_unlock ();
5192
5193                 /* Somebody may have created it before us */
5194                 if (!res) {
5195                         MonoMethod *newm;
5196                         newm = mono_mb_create_method (mb, csig, sig->param_count + 16);
5197
5198                         mono_marshal_lock ();
5199                         res = g_hash_table_lookup (cache, callsig);
5200                         if (!res) {
5201                                 res = newm;
5202                                 g_hash_table_insert (cache, callsig, res);
5203                                 /* Can't insert it into wrapper_hash since the key is a signature */
5204                                 g_hash_table_insert (method->klass->image->runtime_invoke_direct_cache, method, res);
5205                         } else {
5206                                 mono_free_method (newm);
5207                         }
5208                         mono_marshal_unlock ();
5209                 }
5210
5211                 /* end mono_mb_create_and_cache */
5212         }
5213
5214         mono_mb_free (mb);
5215
5216         return res;     
5217 }
5218
5219 /*
5220  * mono_marshal_get_static_rgctx_invoke:
5221  * @method: a method
5222  *
5223  * Generates a wrapper for calling a generic shared method, either
5224  * static or generic.  We need this for virtual generic method lookup
5225  * and ldftn when we do generic code sharing.  Instead of producing
5226  * the address of the method we produce the address of a wrapper for
5227  * the method because the wrapper passes the (method) runtime generic
5228  * context argument which calli cannot do.
5229  */
5230 MonoMethod *
5231 mono_marshal_get_static_rgctx_invoke (MonoMethod *method)
5232 {
5233         static gboolean inited = FALSE;
5234         static int num_wrappers = 0;
5235
5236         MonoMethodBuilder *mb;
5237         MonoMethod *res;
5238         MonoClass *target_klass = method->klass;
5239         MonoMethodSignature *sig = mono_method_signature (method);
5240         int i;
5241         char *name;
5242         GHashTable *cache;
5243         MonoImage *image = method->klass->image;
5244
5245         cache = get_cache (&image->static_rgctx_invoke_cache, mono_aligned_addr_hash, NULL);
5246         if ((res = mono_marshal_find_in_cache (cache, method)))
5247                 return res;
5248
5249         if (!inited) {
5250                 mono_counters_register ("static rgctx invoke wrappers",
5251                                 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_wrappers);
5252                 inited = TRUE;
5253         }
5254         ++num_wrappers;
5255
5256         name = mono_signature_to_name (mono_method_signature (method), "static_rgctx_invoke");
5257         mb = mono_mb_new (target_klass, name, MONO_WRAPPER_STATIC_RGCTX_INVOKE);
5258         g_free (name);
5259
5260         for (i = 0; i < sig->param_count + sig->hasthis; i++)
5261                 mono_mb_emit_ldarg (mb, i);
5262         mono_mb_emit_op (mb, CEE_CALL, method);
5263         mono_mb_emit_byte (mb, CEE_RET);
5264
5265         res = mono_mb_create_and_cache (cache, method, mb, mono_method_signature (method),
5266                 sig->param_count + sig->hasthis + 4);
5267         res->skip_visibility = TRUE;
5268         res->flags = method->flags;
5269
5270         mono_mb_free (mb);
5271
5272         return res;
5273 }
5274
5275 static void
5276 mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
5277 {
5278         char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
5279                                      klass->name_space, klass->name);
5280
5281         mono_mb_emit_exception_marshal_directive (mb, msg);
5282 }
5283
5284 /*
5285  * mono_marshal_get_ldfld_remote_wrapper:
5286  * @klass: The return type
5287  *
5288  * This method generates a wrapper for calling mono_load_remote_field_new.
5289  * The return type is ignored for now, as mono_load_remote_field_new () always
5290  * returns an object. In the future, to optimize some codepaths, we might
5291  * call a different function that takes a pointer to a valuetype, instead.
5292  */
5293 MonoMethod *
5294 mono_marshal_get_ldfld_remote_wrapper (MonoClass *klass)
5295 {
5296         MonoMethodSignature *sig, *csig;
5297         MonoMethodBuilder *mb;
5298         MonoMethod *res;
5299         static MonoMethod* cached = NULL;
5300
5301         mono_marshal_lock ();
5302         if (cached) {
5303                 mono_marshal_unlock ();
5304                 return cached;
5305         }
5306         mono_marshal_unlock ();
5307
5308         mb = mono_mb_new_no_dup_name (mono_defaults.object_class, "__mono_load_remote_field_new_wrapper", MONO_WRAPPER_LDFLD_REMOTE);
5309
5310         mb->method->save_lmf = 1;
5311
5312         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5313         sig->params [0] = &mono_defaults.object_class->byval_arg;
5314         sig->params [1] = &mono_defaults.int_class->byval_arg;
5315         sig->params [2] = &mono_defaults.int_class->byval_arg;
5316         sig->ret = &mono_defaults.object_class->byval_arg;
5317
5318         mono_mb_emit_ldarg (mb, 0);
5319         mono_mb_emit_ldarg (mb, 1);
5320         mono_mb_emit_ldarg (mb, 2);
5321
5322         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5323         csig->params [0] = &mono_defaults.object_class->byval_arg;
5324         csig->params [1] = &mono_defaults.int_class->byval_arg;
5325         csig->params [2] = &mono_defaults.int_class->byval_arg;
5326         csig->ret = &mono_defaults.object_class->byval_arg;
5327         csig->pinvoke = 1;
5328
5329         mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
5330         emit_thread_interrupt_checkpoint (mb);
5331
5332         mono_mb_emit_byte (mb, CEE_RET);
5333  
5334         mono_marshal_lock ();
5335         res = cached;
5336         mono_marshal_unlock ();
5337         if (!res) {
5338                 MonoMethod *newm;
5339                 newm = mono_mb_create_method (mb, sig, 4);
5340                 mono_marshal_lock ();
5341                 res = cached;
5342                 if (!res) {
5343                         res = newm;
5344                         cached = res;
5345                         mono_marshal_unlock ();
5346                 } else {
5347                         mono_marshal_unlock ();
5348                         mono_free_method (newm);
5349                 }
5350         }
5351         mono_mb_free (mb);
5352
5353         return res;
5354 }
5355
5356 /*
5357  * mono_marshal_get_ldfld_wrapper:
5358  * @type: the type of the field
5359  *
5360  * This method generates a function which can be use to load a field with type
5361  * @type from an object. The generated function has the following signature:
5362  * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
5363  */
5364 MonoMethod *
5365 mono_marshal_get_ldfld_wrapper (MonoType *type)
5366 {
5367         MonoMethodSignature *sig;
5368         MonoMethodBuilder *mb;
5369         MonoMethod *res;
5370         MonoClass *klass;
5371         GHashTable *cache;
5372         char *name;
5373         int t, pos0, pos1 = 0;
5374
5375         type = mono_type_get_underlying_type (type);
5376
5377         t = type->type;
5378
5379         if (!type->byref) {
5380                 if (type->type == MONO_TYPE_SZARRAY) {
5381                         klass = mono_defaults.array_class;
5382                 } else if (type->type == MONO_TYPE_VALUETYPE) {
5383                         klass = type->data.klass;
5384                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
5385                         klass = mono_defaults.object_class;
5386                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
5387                         klass = mono_defaults.int_class;
5388                 } else if (t == MONO_TYPE_GENERICINST) {
5389                         if (mono_type_generic_inst_is_valuetype (type))
5390                                 klass = mono_class_from_mono_type (type);
5391                         else
5392                                 klass = mono_defaults.object_class;
5393                 } else {
5394                         klass = mono_class_from_mono_type (type);                       
5395                 }
5396         } else {
5397                 klass = mono_defaults.int_class;
5398         }
5399
5400         cache = get_cache (&klass->image->ldfld_wrapper_cache, mono_aligned_addr_hash, NULL);
5401         if ((res = mono_marshal_find_in_cache (cache, klass)))
5402                 return res;
5403
5404         /* we add the %p pointer value of klass because class names are not unique */
5405         name = g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); 
5406         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
5407         g_free (name);
5408
5409         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5410         sig->params [0] = &mono_defaults.object_class->byval_arg;
5411         sig->params [1] = &mono_defaults.int_class->byval_arg;
5412         sig->params [2] = &mono_defaults.int_class->byval_arg;
5413         sig->params [3] = &mono_defaults.int_class->byval_arg;
5414         sig->ret = &klass->byval_arg;
5415
5416         mono_mb_emit_ldarg (mb, 0);
5417         pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
5418
5419         mono_mb_emit_ldarg (mb, 0);
5420         mono_mb_emit_ldarg (mb, 1);
5421         mono_mb_emit_ldarg (mb, 2);
5422
5423         mono_mb_emit_managed_call (mb, mono_marshal_get_ldfld_remote_wrapper (klass), NULL);
5424
5425         /*
5426         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5427         csig->params [0] = &mono_defaults.object_class->byval_arg;
5428         csig->params [1] = &mono_defaults.int_class->byval_arg;
5429         csig->params [2] = &mono_defaults.int_class->byval_arg;
5430         csig->ret = &klass->this_arg;
5431         csig->pinvoke = 1;
5432
5433         mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
5434         emit_thread_interrupt_checkpoint (mb);
5435         */
5436
5437         if (klass->valuetype) {
5438                 mono_mb_emit_op (mb, CEE_UNBOX, klass);
5439                 pos1 = mono_mb_emit_branch (mb, CEE_BR);
5440         } else {
5441                 mono_mb_emit_byte (mb, CEE_RET);
5442         }
5443
5444
5445         mono_mb_patch_branch (mb, pos0);
5446
5447         mono_mb_emit_ldarg (mb, 0);
5448         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5449         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5450         mono_mb_emit_ldarg (mb, 3);
5451         mono_mb_emit_byte (mb, CEE_ADD);
5452
5453         if (klass->valuetype)
5454                 mono_mb_patch_branch (mb, pos1);
5455
5456         switch (t) {
5457         case MONO_TYPE_I1:
5458         case MONO_TYPE_U1:
5459         case MONO_TYPE_BOOLEAN:
5460         case MONO_TYPE_CHAR:
5461         case MONO_TYPE_I2:
5462         case MONO_TYPE_U2:
5463         case MONO_TYPE_I4:
5464         case MONO_TYPE_U4:
5465         case MONO_TYPE_I8:
5466         case MONO_TYPE_U8:
5467         case MONO_TYPE_R4:
5468         case MONO_TYPE_R8:
5469         case MONO_TYPE_ARRAY:
5470         case MONO_TYPE_SZARRAY:
5471         case MONO_TYPE_OBJECT:
5472         case MONO_TYPE_CLASS:
5473         case MONO_TYPE_STRING:
5474         case MONO_TYPE_I:
5475         case MONO_TYPE_U:
5476         case MONO_TYPE_PTR:
5477         case MONO_TYPE_FNPTR:
5478                 mono_mb_emit_byte (mb, mono_type_to_ldind (type));
5479                 break;
5480         case MONO_TYPE_VALUETYPE:
5481                 g_assert (!klass->enumtype);
5482                 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
5483                 break;
5484         case MONO_TYPE_GENERICINST:
5485                 if (mono_type_generic_inst_is_valuetype (type)) {
5486                         mono_mb_emit_op (mb, CEE_LDOBJ, klass);
5487                 } else {
5488                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
5489                 }
5490                 break;
5491         default:
5492                 g_warning ("type %x not implemented", type->type);
5493                 g_assert_not_reached ();
5494         }
5495
5496         mono_mb_emit_byte (mb, CEE_RET);
5497        
5498         res = mono_mb_create_and_cache (cache, klass,
5499                                                                         mb, sig, sig->param_count + 16);
5500         mono_mb_free (mb);
5501         
5502         return res;
5503 }
5504
5505 /*
5506  * mono_marshal_get_ldflda_wrapper:
5507  * @type: the type of the field
5508  *
5509  * This method generates a function which can be used to load a field address
5510  * from an object. The generated function has the following signature:
5511  * gpointer ldflda_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset);
5512  */
5513 MonoMethod *
5514 mono_marshal_get_ldflda_wrapper (MonoType *type)
5515 {
5516         MonoMethodSignature *sig;
5517         MonoMethodBuilder *mb;
5518         MonoMethod *res;
5519         MonoClass *klass;
5520         GHashTable *cache;
5521         char *name;
5522         int t, pos0, pos1, pos2, pos3;
5523
5524         type = mono_type_get_underlying_type (type);
5525         t = type->type;
5526
5527         if (!type->byref) {
5528                 if (type->type == MONO_TYPE_SZARRAY) {
5529                         klass = mono_defaults.array_class;
5530                 } else if (type->type == MONO_TYPE_VALUETYPE) {
5531                         klass = type->data.klass;
5532                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
5533                            t == MONO_TYPE_CLASS) { 
5534                         klass = mono_defaults.object_class;
5535                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
5536                         klass = mono_defaults.int_class;
5537                 } else if (t == MONO_TYPE_GENERICINST) {
5538                         if (mono_type_generic_inst_is_valuetype (type))
5539                                 klass = mono_class_from_mono_type (type);
5540                         else
5541                                 klass = mono_defaults.object_class;
5542                 } else {
5543                         klass = mono_class_from_mono_type (type);                       
5544                 }
5545         } else {
5546                 klass = mono_defaults.int_class;
5547         }
5548
5549         cache = get_cache (&klass->image->ldflda_wrapper_cache, mono_aligned_addr_hash, NULL);
5550         if ((res = mono_marshal_find_in_cache (cache, klass)))
5551                 return res;
5552
5553         /* we add the %p pointer value of klass because class names are not unique */
5554         name = g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); 
5555         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLDA);
5556         g_free (name);
5557
5558         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5559         sig->params [0] = &mono_defaults.object_class->byval_arg;
5560         sig->params [1] = &mono_defaults.int_class->byval_arg;
5561         sig->params [2] = &mono_defaults.int_class->byval_arg;
5562         sig->params [3] = &mono_defaults.int_class->byval_arg;
5563         sig->ret = &mono_defaults.int_class->byval_arg;
5564
5565         /* if typeof (this) != transparent_proxy goto pos0 */
5566         mono_mb_emit_ldarg (mb, 0);
5567         pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
5568
5569         /* if same_appdomain goto pos1 */
5570         mono_mb_emit_ldarg (mb, 0);
5571         pos1 = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
5572
5573         mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain.");
5574
5575         /* same app domain */
5576         mono_mb_patch_branch (mb, pos1);
5577
5578         /* if typeof (this) != contextbound goto pos2 */
5579         mono_mb_emit_ldarg (mb, 0);
5580         pos2 = mono_mb_emit_contextbound_check (mb, CEE_BEQ);
5581
5582         /* if this->rp->context == mono_context_get goto pos3 */
5583         mono_mb_emit_ldarg (mb, 0);
5584         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
5585         mono_mb_emit_byte (mb, CEE_LDIND_REF);
5586         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, context));
5587         mono_mb_emit_byte (mb, CEE_LDIND_REF);
5588         mono_mb_emit_icall (mb, mono_context_get);
5589         pos3 = mono_mb_emit_branch (mb, CEE_BEQ);
5590
5591         mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another context.");
5592
5593         mono_mb_patch_branch (mb, pos2);
5594         mono_mb_patch_branch (mb, pos3);
5595
5596         /* return the address of the field from this->rp->unwrapped_server */
5597         mono_mb_emit_ldarg (mb, 0);
5598         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
5599         mono_mb_emit_byte (mb, CEE_LDIND_REF);
5600         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, unwrapped_server));
5601         mono_mb_emit_byte (mb, CEE_LDIND_REF);
5602         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5603         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5604         mono_mb_emit_ldarg (mb, 3);
5605         mono_mb_emit_byte (mb, CEE_ADD);
5606         mono_mb_emit_byte (mb, CEE_RET);
5607
5608         /* not a proxy: return the address of the field directly */
5609         mono_mb_patch_branch (mb, pos0);
5610
5611         mono_mb_emit_ldarg (mb, 0);
5612         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5613         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5614         mono_mb_emit_ldarg (mb, 3);
5615         mono_mb_emit_byte (mb, CEE_ADD);
5616
5617         mono_mb_emit_byte (mb, CEE_RET);
5618        
5619         res = mono_mb_create_and_cache (cache, klass,
5620                                                                         mb, sig, sig->param_count + 16);
5621         mono_mb_free (mb);
5622         
5623         return res;
5624 }
5625
5626 /*
5627  * mono_marshal_get_stfld_remote_wrapper:
5628  * klass: The type of the field
5629  *
5630  *  This function generates a wrapper for calling mono_store_remote_field_new
5631  * with the appropriate signature.
5632  * Similarly to mono_marshal_get_ldfld_remote_wrapper () this doesn't depend on the
5633  * klass argument anymore.
5634  */
5635 MonoMethod *
5636 mono_marshal_get_stfld_remote_wrapper (MonoClass *klass)
5637 {
5638         MonoMethodSignature *sig, *csig;
5639         MonoMethodBuilder *mb;
5640         MonoMethod *res;
5641         static MonoMethod *cached = NULL;
5642
5643         mono_marshal_lock ();
5644         if (cached) {
5645                 mono_marshal_unlock ();
5646                 return cached;
5647         }
5648         mono_marshal_unlock ();
5649
5650         mb = mono_mb_new_no_dup_name (mono_defaults.object_class, "__mono_store_remote_field_new_wrapper", MONO_WRAPPER_STFLD_REMOTE);
5651
5652         mb->method->save_lmf = 1;
5653
5654         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5655         sig->params [0] = &mono_defaults.object_class->byval_arg;
5656         sig->params [1] = &mono_defaults.int_class->byval_arg;
5657         sig->params [2] = &mono_defaults.int_class->byval_arg;
5658         sig->params [3] = &mono_defaults.object_class->byval_arg;
5659         sig->ret = &mono_defaults.void_class->byval_arg;
5660
5661         mono_mb_emit_ldarg (mb, 0);
5662         mono_mb_emit_ldarg (mb, 1);
5663         mono_mb_emit_ldarg (mb, 2);
5664         mono_mb_emit_ldarg (mb, 3);
5665
5666         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
5667         csig->params [0] = &mono_defaults.object_class->byval_arg;
5668         csig->params [1] = &mono_defaults.int_class->byval_arg;
5669         csig->params [2] = &mono_defaults.int_class->byval_arg;
5670         csig->params [3] = &mono_defaults.object_class->byval_arg;
5671         csig->ret = &mono_defaults.void_class->byval_arg;
5672         csig->pinvoke = 1;
5673
5674         mono_mb_emit_native_call (mb, csig, mono_store_remote_field_new);
5675         emit_thread_interrupt_checkpoint (mb);
5676
5677         mono_mb_emit_byte (mb, CEE_RET);
5678  
5679         mono_marshal_lock ();
5680         res = cached;
5681         mono_marshal_unlock ();
5682         if (!res) {
5683                 MonoMethod *newm;
5684                 newm = mono_mb_create_method (mb, sig, 6);
5685                 mono_marshal_lock ();
5686                 res = cached;
5687                 if (!res) {
5688                         res = newm;
5689                         cached = res;
5690                         mono_marshal_unlock ();
5691                 } else {
5692                         mono_marshal_unlock ();
5693                         mono_free_method (newm);
5694                 }
5695         }
5696         mono_mb_free (mb);
5697         
5698         return res;
5699 }
5700
5701 /*
5702  * mono_marshal_get_stfld_wrapper:
5703  * @type: the type of the field
5704  *
5705  * This method generates a function which can be use to store a field with type
5706  * @type. The generated function has the following signature:
5707  * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
5708  */
5709 MonoMethod *
5710 mono_marshal_get_stfld_wrapper (MonoType *type)
5711 {
5712         MonoMethodSignature *sig;
5713         MonoMethodBuilder *mb;
5714         MonoMethod *res;
5715         MonoClass *klass;
5716         GHashTable *cache;
5717         char *name;
5718         int t, pos;
5719
5720         type = mono_type_get_underlying_type (type);
5721         t = type->type;
5722
5723         if (!type->byref) {
5724                 if (type->type == MONO_TYPE_SZARRAY) {
5725                         klass = mono_defaults.array_class;
5726                 } else if (type->type == MONO_TYPE_VALUETYPE) {
5727                         klass = type->data.klass;
5728                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
5729                         klass = mono_defaults.object_class;
5730                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
5731                         klass = mono_defaults.int_class;
5732                 } else if (t == MONO_TYPE_GENERICINST) {
5733                         if (mono_type_generic_inst_is_valuetype (type))
5734                                 klass = mono_class_from_mono_type (type);
5735                         else
5736                                 klass = mono_defaults.object_class;
5737                 } else {
5738                         klass = mono_class_from_mono_type (type);                       
5739                 }
5740         } else {
5741                 klass = mono_defaults.int_class;
5742         }
5743
5744         cache = get_cache (&klass->image->stfld_wrapper_cache, mono_aligned_addr_hash, NULL);
5745         if ((res = mono_marshal_find_in_cache (cache, klass)))
5746                 return res;
5747
5748         /* we add the %p pointer value of klass because class names are not unique */
5749         name = g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); 
5750         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
5751         g_free (name);
5752
5753         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
5754         sig->params [0] = &mono_defaults.object_class->byval_arg;
5755         sig->params [1] = &mono_defaults.int_class->byval_arg;
5756         sig->params [2] = &mono_defaults.int_class->byval_arg;
5757         sig->params [3] = &mono_defaults.int_class->byval_arg;
5758         sig->params [4] = &klass->byval_arg;
5759         sig->ret = &mono_defaults.void_class->byval_arg;
5760
5761         mono_mb_emit_ldarg (mb, 0);
5762         pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
5763
5764         mono_mb_emit_ldarg (mb, 0);
5765         mono_mb_emit_ldarg (mb, 1);
5766         mono_mb_emit_ldarg (mb, 2);
5767         mono_mb_emit_ldarg (mb, 4);
5768         if (klass->valuetype)
5769                 mono_mb_emit_op (mb, CEE_BOX, klass);
5770
5771         mono_mb_emit_managed_call (mb, mono_marshal_get_stfld_remote_wrapper (klass), NULL);
5772
5773         mono_mb_emit_byte (mb, CEE_RET);
5774
5775         mono_mb_patch_branch (mb, pos);
5776
5777         mono_mb_emit_ldarg (mb, 0);
5778         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5779         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5780         mono_mb_emit_ldarg (mb, 3);
5781         mono_mb_emit_byte (mb, CEE_ADD);
5782         mono_mb_emit_ldarg (mb, 4);
5783
5784         switch (t) {
5785         case MONO_TYPE_I1:
5786         case MONO_TYPE_U1:
5787         case MONO_TYPE_BOOLEAN:
5788         case MONO_TYPE_CHAR:
5789         case MONO_TYPE_I2:
5790         case MONO_TYPE_U2:
5791         case MONO_TYPE_I4:
5792         case MONO_TYPE_U4:
5793         case MONO_TYPE_I8:
5794         case MONO_TYPE_U8:
5795         case MONO_TYPE_R4:
5796         case MONO_TYPE_R8:
5797         case MONO_TYPE_ARRAY:
5798         case MONO_TYPE_SZARRAY:
5799         case MONO_TYPE_OBJECT:
5800         case MONO_TYPE_CLASS:
5801         case MONO_TYPE_STRING:
5802         case MONO_TYPE_I:
5803         case MONO_TYPE_U:
5804         case MONO_TYPE_PTR:
5805         case MONO_TYPE_FNPTR:
5806                 mono_mb_emit_byte (mb, mono_type_to_stind (type));
5807                 break;
5808         case MONO_TYPE_VALUETYPE:
5809                 g_assert (!klass->enumtype);
5810                 mono_mb_emit_op (mb, CEE_STOBJ, klass);
5811                 break;
5812         case MONO_TYPE_GENERICINST:
5813                 mono_mb_emit_op (mb, CEE_STOBJ, klass);
5814                 break;
5815         default:
5816                 g_warning ("type %x not implemented", type->type);
5817                 g_assert_not_reached ();
5818         }
5819
5820         mono_mb_emit_byte (mb, CEE_RET);
5821        
5822         res = mono_mb_create_and_cache (cache, klass,
5823                                                                         mb, sig, sig->param_count + 16);
5824         mono_mb_free (mb);
5825         
5826         return res;
5827 }
5828
5829 /*
5830  * generates IL code for the icall wrapper (the generated method
5831  * calls the unmanaged code in func)
5832  */
5833 MonoMethod *
5834 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
5835 {
5836         MonoMethodSignature *csig;
5837         MonoMethodBuilder *mb;
5838         MonoMethod *res;
5839         int i;
5840         
5841         g_assert (sig->pinvoke);
5842
5843         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
5844
5845         mb->method->save_lmf = 1;
5846
5847         /* we copy the signature, so that we can modify it */
5848
5849         if (sig->hasthis)
5850                 mono_mb_emit_byte (mb, CEE_LDARG_0);
5851
5852         for (i = 0; i < sig->param_count; i++)
5853                 mono_mb_emit_ldarg (mb, i + sig->hasthis);
5854
5855         mono_mb_emit_native_call (mb, sig, (gpointer) func);
5856         if (check_exceptions)
5857                 emit_thread_interrupt_checkpoint (mb);
5858         mono_mb_emit_byte (mb, CEE_RET);
5859
5860         csig = signature_dup (mono_defaults.corlib, sig);
5861         csig->pinvoke = 0;
5862         if (csig->call_convention == MONO_CALL_VARARG)
5863                 csig->call_convention = 0;
5864
5865         res = mono_mb_create_method (mb, csig, csig->param_count + 16);
5866         mono_mb_free (mb);
5867         
5868         return res;
5869 }
5870
5871 typedef struct {
5872         MonoMethodBuilder *mb;
5873         MonoMethodSignature *sig;
5874         MonoMethodPInvoke *piinfo;
5875         int *orig_conv_args; /* Locals containing the original values of byref args */
5876         int retobj_var;
5877         MonoClass *retobj_class;
5878         MonoMethodSignature *csig; /* Might need to be changed due to MarshalAs directives */
5879         MonoImage *image; /* The image to use for looking up custom marshallers */
5880 } EmitMarshalContext;
5881
5882 typedef enum {
5883         /*
5884          * This is invoked to convert arguments from the current types to
5885          * the underlying types expected by the platform routine.  If required,
5886          * the methods create a temporary variable with the proper type, and return
5887          * the location for it (either the passed argument, or the newly allocated
5888          * local slot).
5889          */
5890         MARSHAL_ACTION_CONV_IN,
5891
5892         /*
5893          * This operation is called to push the actual value that was optionally
5894          * converted on the first stage
5895          */
5896         MARSHAL_ACTION_PUSH,
5897
5898         /*
5899          * Convert byref arguments back or free resources allocated during the
5900          * CONV_IN stage
5901          */
5902         MARSHAL_ACTION_CONV_OUT,
5903
5904         /*
5905          * The result from the unmanaged call is at the top of the stack when
5906          * this action is invoked.    The result should be stored in the
5907          * third local variable slot. 
5908          */
5909         MARSHAL_ACTION_CONV_RESULT,
5910
5911         MARSHAL_ACTION_MANAGED_CONV_IN,
5912         MARSHAL_ACTION_MANAGED_CONV_OUT,
5913         MARSHAL_ACTION_MANAGED_CONV_RESULT
5914 } MarshalAction;
5915
5916 static int
5917 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
5918                                          MonoMarshalSpec *spec, 
5919                                          int conv_arg, MonoType **conv_arg_type, 
5920                                          MarshalAction action)
5921 {
5922         MonoType *mtype;
5923         MonoClass *mklass;
5924         static MonoClass *ICustomMarshaler = NULL;
5925         static MonoMethod *cleanup_native, *cleanup_managed;
5926         static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
5927         MonoMethod *get_instance;
5928         MonoMethodBuilder *mb = m->mb;
5929         char *exception_msg = NULL;
5930         guint32 loc1;
5931         int pos2;
5932
5933         if (!ICustomMarshaler) {
5934                 ICustomMarshaler = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
5935                 g_assert (ICustomMarshaler);
5936
5937                 cleanup_native = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpNativeData", 1);
5938                 g_assert (cleanup_native);
5939                 cleanup_managed = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpManagedData", 1);
5940                 g_assert (cleanup_managed);
5941                 marshal_managed_to_native = mono_class_get_method_from_name (ICustomMarshaler, "MarshalManagedToNative", 1);
5942                 g_assert (marshal_managed_to_native);
5943                 marshal_native_to_managed = mono_class_get_method_from_name (ICustomMarshaler, "MarshalNativeToManaged", 1);
5944                 g_assert (marshal_native_to_managed);
5945         }
5946
5947         mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
5948         g_assert (mtype != NULL);
5949         mklass = mono_class_from_mono_type (mtype);
5950         g_assert (mklass != NULL);
5951
5952         if (!mono_class_is_assignable_from (ICustomMarshaler, mklass))
5953                 exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass->name);
5954
5955         get_instance = mono_class_get_method_from_name_flags (mklass, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC);
5956         if (get_instance) {
5957                 MonoMethodSignature *get_sig = mono_method_signature (get_instance);
5958                 if ((get_sig->ret->type != MONO_TYPE_CLASS) ||
5959                         (mono_class_from_mono_type (get_sig->ret) != ICustomMarshaler) ||
5960                         (get_sig->params [0]->type != MONO_TYPE_STRING))
5961                         get_instance = NULL;
5962         }
5963
5964         if (!get_instance)
5965                 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);
5966
5967         /* Throw exception and emit compensation code if neccesary */
5968         if (exception_msg) {
5969                 switch (action) {
5970                 case MARSHAL_ACTION_CONV_IN:
5971                 case MARSHAL_ACTION_CONV_RESULT:
5972                 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5973                         if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT))
5974                                 mono_mb_emit_byte (mb, CEE_POP);
5975
5976                         mono_mb_emit_exception_full (mb, "System", "ApplicationException", exception_msg);
5977                         g_free (exception_msg);
5978
5979                         break;
5980                 case MARSHAL_ACTION_PUSH:
5981                         mono_mb_emit_byte (mb, CEE_LDNULL);
5982                         break;
5983                 default:
5984                         break;
5985                 }
5986                 return 0;
5987         }
5988
5989         /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
5990         /* FIXME: MS.NET throws an exception if GetInstance returns null */
5991
5992         switch (action) {
5993         case MARSHAL_ACTION_CONV_IN:
5994                 switch (t->type) {
5995                 case MONO_TYPE_CLASS:
5996                 case MONO_TYPE_OBJECT:
5997                 case MONO_TYPE_STRING:
5998                 case MONO_TYPE_ARRAY:
5999                 case MONO_TYPE_SZARRAY:
6000                 case MONO_TYPE_VALUETYPE:
6001                         break;
6002
6003                 default:
6004                         g_warning ("custom marshalling of type %x is currently not supported", t->type);
6005                         g_assert_not_reached ();
6006                         break;
6007                 }
6008
6009                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6010
6011                 mono_mb_emit_byte (mb, CEE_LDNULL);
6012                 mono_mb_emit_stloc (mb, conv_arg);
6013
6014                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
6015                         break;
6016
6017                 /* Minic MS.NET behavior */
6018                 if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
6019                         break;
6020
6021                 /* Check for null */
6022                 mono_mb_emit_ldarg (mb, argnum);
6023                 if (t->byref)
6024                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6025                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6026
6027                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6028
6029                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
6030                                 
6031                 mono_mb_emit_ldarg (mb, argnum);
6032                 if (t->byref)
6033                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6034
6035                 if (t->type == MONO_TYPE_VALUETYPE) {
6036                         /*
6037                          * Since we can't determine the type of the argument, we
6038                          * will assume the unmanaged function takes a pointer.
6039                          */
6040                         *conv_arg_type = &mono_defaults.int_class->byval_arg;
6041
6042                         mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
6043                 }
6044
6045                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
6046                 mono_mb_emit_stloc (mb, conv_arg);
6047
6048                 mono_mb_patch_branch (mb, pos2);
6049                 break;
6050
6051         case MARSHAL_ACTION_CONV_OUT:
6052                 /* Check for null */
6053                 mono_mb_emit_ldloc (mb, conv_arg);
6054                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6055
6056                 if (t->byref) {
6057                         mono_mb_emit_ldarg (mb, argnum);
6058
6059                         mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6060
6061                         mono_mb_emit_op (mb, CEE_CALL, get_instance);
6062
6063                         mono_mb_emit_ldloc (mb, conv_arg);
6064                         mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
6065                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6066                 } else if (t->attrs & PARAM_ATTRIBUTE_OUT) {
6067                         mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6068
6069                         mono_mb_emit_op (mb, CEE_CALL, get_instance);
6070
6071                         mono_mb_emit_ldloc (mb, conv_arg);
6072                         mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
6073
6074                         /* We have nowhere to store the result */
6075                         mono_mb_emit_byte (mb, CEE_POP);
6076                 }
6077
6078                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6079
6080                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
6081
6082                 mono_mb_emit_ldloc (mb, conv_arg);
6083
6084                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
6085
6086                 mono_mb_patch_branch (mb, pos2);
6087                 break;
6088
6089         case MARSHAL_ACTION_PUSH:
6090                 if (t->byref)
6091                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6092                 else
6093                         mono_mb_emit_ldloc (mb, conv_arg);
6094                 break;
6095
6096         case MARSHAL_ACTION_CONV_RESULT:
6097                 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6098                         
6099                 mono_mb_emit_stloc (mb, 3);
6100
6101                 mono_mb_emit_ldloc (mb, 3);
6102                 mono_mb_emit_stloc (mb, loc1);
6103
6104                 /* Check for null */
6105                 mono_mb_emit_ldloc (mb, 3);
6106                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6107
6108                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6109
6110                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
6111                 mono_mb_emit_byte (mb, CEE_DUP);
6112
6113                 mono_mb_emit_ldloc (mb, 3);
6114                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
6115                 mono_mb_emit_stloc (mb, 3);
6116
6117                 mono_mb_emit_ldloc (mb, loc1);
6118                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
6119
6120                 mono_mb_patch_branch (mb, pos2);
6121                 break;
6122
6123         case MARSHAL_ACTION_MANAGED_CONV_IN:
6124                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6125
6126                 mono_mb_emit_byte (mb, CEE_LDNULL);
6127                 mono_mb_emit_stloc (mb, conv_arg);
6128
6129                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
6130                         break;
6131
6132                 /* Check for null */
6133                 mono_mb_emit_ldarg (mb, argnum);
6134                 if (t->byref)
6135                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6136                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6137
6138                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6139                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
6140                                 
6141                 mono_mb_emit_ldarg (mb, argnum);
6142                 if (t->byref)
6143                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6144                                 
6145                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
6146                 mono_mb_emit_stloc (mb, conv_arg);
6147
6148                 mono_mb_patch_branch (mb, pos2);
6149                 break;
6150
6151         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6152                 g_assert (!t->byref);
6153
6154                 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6155                         
6156                 mono_mb_emit_stloc (mb, 3);
6157                         
6158                 mono_mb_emit_ldloc (mb, 3);
6159                 mono_mb_emit_stloc (mb, loc1);
6160
6161                 /* Check for null */
6162                 mono_mb_emit_ldloc (mb, 3);
6163                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6164
6165                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6166                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
6167                 mono_mb_emit_byte (mb, CEE_DUP);
6168
6169                 mono_mb_emit_ldloc (mb, 3);
6170                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
6171                 mono_mb_emit_stloc (mb, 3);
6172
6173                 mono_mb_emit_ldloc (mb, loc1);
6174                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
6175
6176                 mono_mb_patch_branch (mb, pos2);
6177                 break;
6178
6179         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6180
6181                 /* Check for null */
6182                 mono_mb_emit_ldloc (mb, conv_arg);
6183                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6184
6185                 if (t->byref) {
6186                         mono_mb_emit_ldarg (mb, argnum);
6187
6188                         mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6189
6190                         mono_mb_emit_op (mb, CEE_CALL, get_instance);
6191
6192                         mono_mb_emit_ldloc (mb, conv_arg);
6193                         mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
6194                         mono_mb_emit_byte (mb, CEE_STIND_I);
6195                 }
6196
6197                 /* Call CleanUpManagedData */
6198                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
6199
6200                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
6201                                 
6202                 mono_mb_emit_ldloc (mb, conv_arg);
6203                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
6204
6205                 mono_mb_patch_branch (mb, pos2);
6206                 break;
6207
6208         default:
6209                 g_assert_not_reached ();
6210         }
6211                 
6212         return conv_arg;
6213 }
6214
6215 static int
6216 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
6217                                         MonoMarshalSpec *spec, 
6218                                         int conv_arg, MonoType **conv_arg_type, 
6219                                         MarshalAction action)
6220 {
6221         MonoMethodBuilder *mb = m->mb;
6222
6223         switch (action) {
6224         case MARSHAL_ACTION_CONV_IN: {
6225                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
6226
6227                 g_assert (t->type == MONO_TYPE_OBJECT);
6228                 g_assert (!t->byref);
6229
6230                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6231                 mono_mb_emit_ldarg (mb, argnum);
6232                 mono_mb_emit_icon (mb, encoding);
6233                 mono_mb_emit_icon (mb, t->attrs);
6234                 mono_mb_emit_icall (mb, mono_marshal_asany);
6235                 mono_mb_emit_stloc (mb, conv_arg);
6236                 break;
6237         }
6238
6239         case MARSHAL_ACTION_PUSH:
6240                 mono_mb_emit_ldloc (mb, conv_arg);
6241                 break;
6242
6243         case MARSHAL_ACTION_CONV_OUT: {
6244                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
6245
6246                 mono_mb_emit_ldarg (mb, argnum);
6247                 mono_mb_emit_ldloc (mb, conv_arg);
6248                 mono_mb_emit_icon (mb, encoding);
6249                 mono_mb_emit_icon (mb, t->attrs);
6250                 mono_mb_emit_icall (mb, mono_marshal_free_asany);
6251                 break;
6252         }
6253
6254         default:
6255                 g_assert_not_reached ();
6256         }
6257
6258         return conv_arg;
6259 }
6260
6261 static int
6262 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
6263                                         MonoMarshalSpec *spec, 
6264                                         int conv_arg, MonoType **conv_arg_type, 
6265                                         MarshalAction action)
6266 {
6267         MonoMethodBuilder *mb = m->mb;
6268         MonoClass *klass;
6269         int pos = 0, pos2;
6270
6271         klass = mono_class_from_mono_type (t);
6272
6273         switch (action) {
6274         case MARSHAL_ACTION_CONV_IN:
6275                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6276                         klass->blittable || klass->enumtype)
6277                         break;
6278
6279                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6280                         
6281                 /* store the address of the source into local variable 0 */
6282                 if (t->byref)
6283                         mono_mb_emit_ldarg (mb, argnum);
6284                 else
6285                         mono_mb_emit_ldarg_addr (mb, argnum);
6286                 
6287                 mono_mb_emit_stloc (mb, 0);
6288                         
6289                 /* allocate space for the native struct and
6290                  * store the address into local variable 1 (dest) */
6291                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6292                 mono_mb_emit_byte (mb, CEE_PREFIX1);
6293                 mono_mb_emit_byte (mb, CEE_LOCALLOC);
6294                 mono_mb_emit_stloc (mb, conv_arg);
6295
6296                 if (t->byref) {
6297                         mono_mb_emit_ldloc (mb, 0);
6298                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6299                 }
6300
6301                 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
6302                         /* set dst_ptr */
6303                         mono_mb_emit_ldloc (mb, conv_arg);
6304                         mono_mb_emit_stloc (mb, 1);
6305
6306                         /* emit valuetype conversion code */
6307                         emit_struct_conv (mb, klass, FALSE);
6308                 }
6309
6310                 if (t->byref)
6311                         mono_mb_patch_branch (mb, pos);
6312                 break;
6313
6314         case MARSHAL_ACTION_PUSH:
6315                 if (spec && spec->native == MONO_NATIVE_LPSTRUCT) {
6316                         /* FIXME: */
6317                         g_assert (!t->byref);
6318
6319                         /* Have to change the signature since the vtype is passed byref */
6320                         m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
6321
6322                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6323                                 klass->blittable || klass->enumtype)
6324                                 mono_mb_emit_ldarg_addr (mb, argnum);
6325                         else
6326                                 mono_mb_emit_ldloc (mb, conv_arg);
6327                         break;
6328                 }
6329
6330                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6331                         klass->blittable || klass->enumtype) {
6332                         mono_mb_emit_ldarg (mb, argnum);
6333                         break;
6334                 }                       
6335                 mono_mb_emit_ldloc (mb, conv_arg);
6336                 if (!t->byref) {
6337                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6338                         mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass);
6339                 }
6340                 break;
6341
6342         case MARSHAL_ACTION_CONV_OUT:
6343                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6344                         klass->blittable || klass->enumtype)
6345                         break;
6346
6347                 if (t->byref) {
6348                         /* dst = argument */
6349                         mono_mb_emit_ldarg (mb, argnum);
6350                         mono_mb_emit_stloc (mb, 1);
6351
6352                         mono_mb_emit_ldloc (mb, 1);
6353                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6354
6355                         if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
6356                                 /* src = tmp_locals [i] */
6357                                 mono_mb_emit_ldloc (mb, conv_arg);
6358                                 mono_mb_emit_stloc (mb, 0);
6359
6360                                 /* emit valuetype conversion code */
6361                                 emit_struct_conv (mb, klass, TRUE);
6362                         }
6363                 }
6364
6365                 emit_struct_free (mb, klass, conv_arg);
6366                 
6367                 if (t->byref)
6368                         mono_mb_patch_branch (mb, pos);
6369                 break;
6370
6371         case MARSHAL_ACTION_CONV_RESULT:
6372                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6373                         klass->blittable) {
6374                         mono_mb_emit_stloc (mb, 3);
6375                         break;
6376                 }
6377                 /* load pointer to returned value type */
6378                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6379                 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
6380                 /* store the address of the source into local variable 0 */
6381                 mono_mb_emit_stloc (mb, 0);
6382                 /* set dst_ptr */
6383                 mono_mb_emit_ldloc_addr (mb, 3);
6384                 mono_mb_emit_stloc (mb, 1);
6385                                 
6386                 /* emit valuetype conversion code */
6387                 emit_struct_conv (mb, klass, TRUE);
6388                 break;
6389
6390         case MARSHAL_ACTION_MANAGED_CONV_IN:
6391                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6392                         klass->blittable || klass->enumtype) {
6393                         conv_arg = 0;
6394                         break;
6395                 }
6396
6397                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
6398
6399                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6400                         break;
6401
6402                 if (t->byref) 
6403                         mono_mb_emit_ldarg (mb, argnum);
6404                 else
6405                         mono_mb_emit_ldarg_addr (mb, argnum);
6406                 mono_mb_emit_stloc (mb, 0);
6407
6408                 if (t->byref) {
6409                         mono_mb_emit_ldloc (mb, 0);
6410                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6411                 }                       
6412
6413                 mono_mb_emit_ldloc_addr (mb, conv_arg);
6414                 mono_mb_emit_stloc (mb, 1);
6415
6416                 /* emit valuetype conversion code */
6417                 emit_struct_conv (mb, klass, TRUE);
6418
6419                 if (t->byref)
6420                         mono_mb_patch_branch (mb, pos);
6421                 break;
6422
6423         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6424                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6425                         klass->blittable || klass->enumtype) {
6426                         break;
6427                 }
6428
6429                 /* Check for null */
6430                 mono_mb_emit_ldarg (mb, argnum);
6431                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6432
6433                 /* Set src */
6434                 mono_mb_emit_ldloc_addr (mb, conv_arg);
6435                 mono_mb_emit_stloc (mb, 0);
6436
6437                 /* Set dest */
6438                 mono_mb_emit_ldarg (mb, argnum);
6439                 mono_mb_emit_stloc (mb, 1);
6440
6441                 /* emit valuetype conversion code */
6442                 emit_struct_conv (mb, klass, FALSE);
6443
6444                 mono_mb_patch_branch (mb, pos2);
6445                 break;
6446
6447         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6448                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
6449                         klass->blittable || klass->enumtype) {
6450                         mono_mb_emit_stloc (mb, 3);
6451                         m->retobj_var = 0;
6452                         break;
6453                 }
6454                         
6455                 /* load pointer to returned value type */
6456                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6457                 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
6458                         
6459                 /* store the address of the source into local variable 0 */
6460                 mono_mb_emit_stloc (mb, 0);
6461                 /* allocate space for the native struct and
6462                  * store the address into dst_ptr */
6463                 m->retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6464                 m->retobj_class = klass;
6465                 g_assert (m->retobj_var);
6466                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6467                 mono_mb_emit_byte (mb, CEE_CONV_I);
6468                 mono_mb_emit_icall (mb, mono_marshal_alloc);
6469                 mono_mb_emit_stloc (mb, 1);
6470                 mono_mb_emit_ldloc (mb, 1);
6471                 mono_mb_emit_stloc (mb, m->retobj_var);
6472
6473                 /* emit valuetype conversion code */
6474                 emit_struct_conv (mb, klass, FALSE);
6475                 break;
6476
6477         default:
6478                 g_assert_not_reached ();
6479         }
6480
6481         return conv_arg;
6482 }
6483
6484 static int
6485 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
6486                                          MonoMarshalSpec *spec, 
6487                                          int conv_arg, MonoType **conv_arg_type, 
6488                                          MarshalAction action)
6489 {
6490         MonoMethodBuilder *mb = m->mb;
6491         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6492         MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
6493         gboolean need_free;
6494
6495         switch (action) {
6496         case MARSHAL_ACTION_CONV_IN:
6497                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6498                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6499
6500                 if (t->byref) {
6501                         if (t->attrs & PARAM_ATTRIBUTE_OUT)
6502                                 break;
6503
6504                         mono_mb_emit_ldarg (mb, argnum);
6505                         mono_mb_emit_byte (mb, CEE_LDIND_I);                            
6506                 } else {
6507                         mono_mb_emit_ldarg (mb, argnum);
6508                 }
6509
6510                 if (conv == -1) {
6511                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6512                         MonoException *exc = mono_get_exception_not_implemented (msg);
6513                         g_warning (msg);
6514                         g_free (msg);
6515                         mono_raise_exception (exc);
6516                 }
6517                 else
6518                         mono_mb_emit_icall (mb, conv_to_icall (conv));
6519
6520                 mono_mb_emit_stloc (mb, conv_arg);
6521                 break;
6522
6523         case MARSHAL_ACTION_CONV_OUT:
6524                 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6525                 if (conv == -1) {
6526                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6527                         mono_mb_emit_exception_marshal_directive (mb, msg);
6528                         break;
6529                 }
6530
6531                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6532                         mono_mb_emit_ldarg (mb, argnum);
6533                         mono_mb_emit_ldloc (mb, conv_arg);
6534                         mono_mb_emit_icall (mb, conv_to_icall (conv));
6535                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6536                 }
6537
6538                 if (need_free || (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
6539                         mono_mb_emit_ldloc (mb, conv_arg);
6540                         if (conv == MONO_MARSHAL_CONV_BSTR_STR)
6541                                 mono_mb_emit_icall (mb, mono_free_bstr);
6542                         else
6543                                 mono_mb_emit_icall (mb, mono_marshal_free);
6544                 }
6545                 break;
6546
6547         case MARSHAL_ACTION_PUSH:
6548                 if (t->byref)
6549                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6550                 else
6551                         mono_mb_emit_ldloc (mb, conv_arg);
6552                 break;
6553
6554         case MARSHAL_ACTION_CONV_RESULT:
6555                 mono_mb_emit_stloc (mb, 0);
6556                                 
6557                 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6558                 if (conv == -1) {
6559                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6560                         mono_mb_emit_exception_marshal_directive (mb, msg);
6561                         break;
6562                 }
6563
6564                 mono_mb_emit_ldloc (mb, 0);
6565                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6566                 mono_mb_emit_stloc (mb, 3);
6567
6568                 /* free the string */
6569                 mono_mb_emit_ldloc (mb, 0);
6570                 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
6571                         mono_mb_emit_icall (mb, mono_free_bstr);
6572                 else
6573                         mono_mb_emit_icall (mb, mono_marshal_free);
6574                 break;
6575
6576         case MARSHAL_ACTION_MANAGED_CONV_IN:
6577                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6578
6579                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6580
6581                 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6582                 if (conv == -1) {
6583                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6584                         mono_mb_emit_exception_marshal_directive (mb, msg);
6585                         break;
6586                 }
6587
6588                 mono_mb_emit_ldarg (mb, argnum);
6589                 if (t->byref)
6590                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6591                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6592                 mono_mb_emit_stloc (mb, conv_arg);
6593                 break;
6594
6595         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6596                 if (t->byref) {
6597                         if (conv_arg) {
6598                                 mono_mb_emit_ldarg (mb, argnum);
6599                                 mono_mb_emit_ldloc (mb, conv_arg);
6600                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6601                                 mono_mb_emit_byte (mb, CEE_STIND_I);
6602                         }
6603                 }
6604                 break;
6605
6606         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6607                 if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
6608                         /* We need to make a copy so the caller is able to free it */
6609                         mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
6610                 else
6611                         mono_mb_emit_icall (mb, conv_to_icall (conv));
6612                 mono_mb_emit_stloc (mb, 3);
6613                 break;
6614
6615         default:
6616                 g_assert_not_reached ();
6617         }
6618
6619         return conv_arg;
6620 }
6621
6622 static int
6623 emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t, 
6624                          MonoMarshalSpec *spec, int conv_arg, 
6625                          MonoType **conv_arg_type, MarshalAction action)
6626 {
6627         MonoMethodBuilder *mb = m->mb;
6628
6629         switch (action){
6630         case MARSHAL_ACTION_CONV_IN: {
6631                 MonoType *intptr_type;
6632                 int dar_release_slot, pos;
6633
6634                 intptr_type = &mono_defaults.int_class->byval_arg;
6635                 conv_arg = mono_mb_add_local (mb, intptr_type);
6636                 *conv_arg_type = intptr_type;
6637
6638                 if (!sh_dangerous_add_ref)
6639                         init_safe_handle ();
6640
6641                 mono_mb_emit_ldarg (mb, argnum);
6642                 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6643                 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
6644                 
6645                 mono_mb_patch_branch (mb, pos);
6646                 if (t->byref){
6647                         /*
6648                          * My tests in show that ref SafeHandles are not really
6649                          * passed as ref objects.  Instead a NULL is passed as the
6650                          * value of the ref
6651                          */
6652                         mono_mb_emit_icon (mb, 0);
6653                         mono_mb_emit_stloc (mb, conv_arg);
6654                         break;
6655                 } 
6656
6657                 /* Create local to hold the ref parameter to DangerousAddRef */
6658                 dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
6659
6660                 /* set release = false; */
6661                 mono_mb_emit_icon (mb, 0);
6662                 mono_mb_emit_stloc (mb, dar_release_slot);
6663
6664                 /* safehandle.DangerousAddRef (ref release) */
6665                 mono_mb_emit_ldarg (mb, argnum);
6666                 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
6667                 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
6668
6669                 /* Pull the handle field from SafeHandle */
6670                 mono_mb_emit_ldarg (mb, argnum);
6671                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6672                 mono_mb_emit_byte (mb, CEE_LDIND_I);
6673                 mono_mb_emit_stloc (mb, conv_arg);
6674
6675                 break;
6676         }
6677
6678         case MARSHAL_ACTION_PUSH:
6679                 if (t->byref)
6680                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6681                 else 
6682                         mono_mb_emit_ldloc (mb, conv_arg);
6683                 break;
6684
6685         case MARSHAL_ACTION_CONV_OUT: {
6686                 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
6687                 int dar_release_slot = conv_arg + 1;
6688                 int label_next;
6689
6690                 if (!sh_dangerous_release)
6691                         init_safe_handle ();
6692
6693                 if (t->byref){
6694                         MonoMethod *ctor;
6695                         
6696                         /*
6697                          * My tests indicate that ref SafeHandles parameters are not actually
6698                          * passed by ref, but instead a new Handle is created regardless of
6699                          * whether a change happens in the unmanaged side.
6700                          *
6701                          * Also, the Handle is created before calling into unmanaged code,
6702                          * but we do not support that mechanism (getting to the original
6703                          * handle) and it makes no difference where we create this
6704                          */
6705                         ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
6706                         if (ctor == NULL){
6707                                 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
6708                                 break;
6709                         }
6710                         /* refval = new SafeHandleDerived ()*/
6711                         mono_mb_emit_ldarg (mb, argnum);
6712                         mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
6713                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6714
6715                         /* refval.handle = returned_handle */
6716                         mono_mb_emit_ldarg (mb, argnum);
6717                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6718                         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6719                         mono_mb_emit_ldloc (mb, conv_arg);
6720                         mono_mb_emit_byte (mb, CEE_STIND_I);
6721                 } else {
6722                         mono_mb_emit_ldloc (mb, dar_release_slot);
6723                         label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
6724                         mono_mb_emit_ldarg (mb, argnum);
6725                         mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
6726                         mono_mb_patch_branch (mb, label_next);
6727                 }
6728                 break;
6729         }
6730                 
6731         case MARSHAL_ACTION_CONV_RESULT: {
6732                 MonoMethod *ctor = NULL;
6733                 int intptr_handle_slot;
6734                 
6735                 if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
6736                         mono_mb_emit_byte (mb, CEE_POP);
6737                         mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract");
6738                         break;
6739                 }
6740
6741                 ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
6742                 if (ctor == NULL){
6743                         mono_mb_emit_byte (mb, CEE_POP);
6744                         mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
6745                         break;
6746                 }
6747                 /* Store the IntPtr results into a local */
6748                 intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6749                 mono_mb_emit_stloc (mb, intptr_handle_slot);
6750
6751                 /* Create return value */
6752                 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
6753                 mono_mb_emit_stloc (mb, 3);
6754
6755                 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
6756                 mono_mb_emit_ldloc (mb, 3);
6757                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6758                 mono_mb_emit_ldloc (mb, intptr_handle_slot);
6759                 mono_mb_emit_byte (mb, CEE_STIND_I);
6760                 break;
6761         }
6762                 
6763         case MARSHAL_ACTION_MANAGED_CONV_IN:
6764                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6765                 break;
6766                 
6767         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6768                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6769                 break;
6770
6771         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6772                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6773                 break;
6774         default:
6775                 printf ("Unhandled case for MarshalAction: %d\n", action);
6776         }
6777
6778         return conv_arg;
6779 }
6780
6781 static int
6782 emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t, 
6783                         MonoMarshalSpec *spec, int conv_arg, 
6784                         MonoType **conv_arg_type, MarshalAction action)
6785 {
6786         MonoMethodBuilder *mb = m->mb;
6787
6788         switch (action){
6789         case MARSHAL_ACTION_CONV_IN: {
6790                 MonoType *intptr_type;
6791
6792                 intptr_type = &mono_defaults.int_class->byval_arg;
6793                 conv_arg = mono_mb_add_local (mb, intptr_type);
6794                 *conv_arg_type = intptr_type;
6795
6796                 if (t->byref){
6797                         mono_mb_emit_exception_marshal_directive (mb,
6798                                 "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6799                         break;
6800                 } 
6801                 mono_mb_emit_ldarg_addr (mb, argnum);
6802                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
6803                 mono_mb_emit_byte (mb, CEE_ADD);
6804                 mono_mb_emit_byte (mb, CEE_LDIND_I);
6805                 mono_mb_emit_stloc (mb, conv_arg);
6806                 break;
6807         }
6808
6809         case MARSHAL_ACTION_PUSH:
6810                 mono_mb_emit_ldloc (mb, conv_arg);
6811                 break;
6812
6813         case MARSHAL_ACTION_CONV_OUT: {
6814                 /* no resource release required */
6815                 break;
6816         }
6817                 
6818         case MARSHAL_ACTION_CONV_RESULT: {
6819                 mono_mb_emit_exception_marshal_directive (mb,
6820                         "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6821                 break;
6822         }
6823                 
6824         case MARSHAL_ACTION_MANAGED_CONV_IN:
6825                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6826                 break;
6827                 
6828         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6829                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6830                 break;
6831
6832         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6833                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6834                 break;
6835         default:
6836                 fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
6837         }
6838
6839         return conv_arg;
6840 }
6841
6842 static int
6843 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
6844                      MonoMarshalSpec *spec, 
6845                      int conv_arg, MonoType **conv_arg_type, 
6846                      MarshalAction action)
6847 {
6848         MonoMethodBuilder *mb = m->mb;
6849         MonoClass *klass = mono_class_from_mono_type (t);
6850         int pos, pos2, loc;
6851
6852         if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
6853                 mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
6854         }
6855
6856         switch (action) {
6857         case MARSHAL_ACTION_CONV_IN:
6858                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6859                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6860
6861                 m->orig_conv_args [argnum] = 0;
6862                 
6863                 if (klass->delegate) {
6864                         if (t->byref) {
6865                                 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6866                                         char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented.");
6867                                         mono_mb_emit_exception_marshal_directive (mb, msg);
6868                                 }
6869                                 mono_mb_emit_byte (mb, CEE_LDNULL);
6870                                 mono_mb_emit_stloc (mb, conv_arg);
6871                         } else {
6872                                 mono_mb_emit_ldarg (mb, argnum);
6873                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
6874                                 mono_mb_emit_stloc (mb, conv_arg);
6875                         }
6876                 } else if (klass == mono_defaults.stringbuilder_class) {
6877                         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6878                         MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
6879                         
6880                         g_assert (!t->byref);
6881                         mono_mb_emit_ldarg (mb, argnum);
6882
6883                         if (conv != -1)
6884                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6885                         else {
6886                                 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
6887                                 MonoException *exc = mono_get_exception_not_implemented (msg);
6888                                 g_warning (msg);
6889                                 g_free (msg);
6890                                 mono_raise_exception (exc);
6891                         }
6892
6893                         mono_mb_emit_stloc (mb, conv_arg);
6894                 } else if (klass->blittable) {
6895                         mono_mb_emit_byte (mb, CEE_LDNULL);
6896                         mono_mb_emit_stloc (mb, conv_arg);
6897
6898                         mono_mb_emit_ldarg (mb, argnum);
6899                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6900
6901                         mono_mb_emit_ldarg (mb, argnum);
6902                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6903                         mono_mb_emit_stloc (mb, conv_arg);
6904
6905                         mono_mb_patch_branch (mb, pos);
6906                         break;
6907                 } else {
6908                         mono_mb_emit_byte (mb, CEE_LDNULL);
6909                         mono_mb_emit_stloc (mb, conv_arg);
6910
6911                         if (t->byref) {
6912                                 /* we dont need any conversions for out parameters */
6913                                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6914                                         break;
6915
6916                                 mono_mb_emit_ldarg (mb, argnum);                                
6917                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
6918
6919                         } else {
6920                                 mono_mb_emit_ldarg (mb, argnum);
6921                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6922                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
6923                         }
6924                                 
6925                         /* store the address of the source into local variable 0 */
6926                         mono_mb_emit_stloc (mb, 0);
6927                         mono_mb_emit_ldloc (mb, 0);
6928                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6929
6930                         /* allocate space for the native struct and store the address */
6931                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6932                         mono_mb_emit_byte (mb, CEE_PREFIX1);
6933                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
6934                         mono_mb_emit_stloc (mb, conv_arg);
6935
6936                         if (t->byref) {
6937                                 /* Need to store the original buffer so we can free it later */
6938                                 m->orig_conv_args [argnum] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6939                                 mono_mb_emit_ldloc (mb, conv_arg);
6940                                 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
6941                         }
6942
6943                         /* set the src_ptr */
6944                         mono_mb_emit_ldloc (mb, 0);
6945                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6946                         mono_mb_emit_stloc (mb, 0);
6947
6948                         /* set dst_ptr */
6949                         mono_mb_emit_ldloc (mb, conv_arg);
6950                         mono_mb_emit_stloc (mb, 1);
6951
6952                         /* emit valuetype conversion code */
6953                         emit_struct_conv (mb, klass, FALSE);
6954
6955                         mono_mb_patch_branch (mb, pos);
6956                 }
6957                 break;
6958
6959         case MARSHAL_ACTION_CONV_OUT:
6960                 if (klass == mono_defaults.stringbuilder_class) {
6961                         gboolean need_free;
6962                         MonoMarshalNative encoding;
6963                         MonoMarshalConv conv;
6964
6965                         encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6966                         conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
6967
6968                         g_assert (!t->byref);
6969                         g_assert (encoding != -1);
6970
6971                         mono_mb_emit_ldarg (mb, argnum);
6972                         mono_mb_emit_ldloc (mb, conv_arg);
6973
6974                         mono_mb_emit_icall (mb, conv_to_icall (conv));
6975
6976                         if (need_free) {
6977                                 mono_mb_emit_ldloc (mb, conv_arg);
6978                                 mono_mb_emit_icall (mb, mono_marshal_free);
6979                         }
6980                         break;
6981                 }
6982
6983                 if (klass->delegate) {
6984                         if (t->byref) {
6985                                 mono_mb_emit_ldarg (mb, argnum);
6986                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6987                                 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6988                                 mono_mb_emit_ldloc (mb, conv_arg);
6989                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6990                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
6991                         }
6992                         break;
6993                 }
6994
6995                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6996                         /* allocate a new object */
6997                         mono_mb_emit_ldarg (mb, argnum);
6998                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6999                         mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
7000                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7001                 }
7002
7003                 /* dst = *argument */
7004                 mono_mb_emit_ldarg (mb, argnum);
7005
7006                 if (t->byref)
7007                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7008
7009                 mono_mb_emit_stloc (mb, 1);
7010
7011                 mono_mb_emit_ldloc (mb, 1);
7012                 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
7013
7014                 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
7015                         mono_mb_emit_ldloc (mb, 1);
7016                         mono_mb_emit_icon (mb, sizeof (MonoObject));
7017                         mono_mb_emit_byte (mb, CEE_ADD);
7018                         mono_mb_emit_stloc (mb, 1);
7019                         
7020                         /* src = tmp_locals [i] */
7021                         mono_mb_emit_ldloc (mb, conv_arg);
7022                         mono_mb_emit_stloc (mb, 0);
7023
7024                         /* emit valuetype conversion code */
7025                         emit_struct_conv (mb, klass, TRUE);
7026
7027                         /* Free the structure returned by the native code */
7028                         emit_struct_free (mb, klass, conv_arg);
7029
7030                         if (m->orig_conv_args [argnum]) {
7031                                 /* 
7032                                  * If the native function changed the pointer, then free
7033                                  * the original structure plus the new pointer.
7034                                  */
7035                                 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
7036                                 mono_mb_emit_ldloc (mb, conv_arg);
7037                                 pos2 = mono_mb_emit_branch (mb, CEE_BEQ);
7038
7039                                 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
7040                                         g_assert (m->orig_conv_args [argnum]);
7041
7042                                         emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
7043                                 }
7044
7045                                 mono_mb_emit_ldloc (mb, conv_arg);
7046                                 mono_mb_emit_icall (mb, g_free);
7047
7048                                 mono_mb_patch_branch (mb, pos2);
7049                         }
7050                 }
7051                 else
7052                         /* Free the original structure passed to native code */
7053                         emit_struct_free (mb, klass, conv_arg);
7054
7055                 mono_mb_patch_branch (mb, pos);
7056                 break;
7057
7058         case MARSHAL_ACTION_PUSH:
7059                 if (t->byref)
7060                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7061                 else
7062                         mono_mb_emit_ldloc (mb, conv_arg);
7063                 break;
7064
7065         case MARSHAL_ACTION_CONV_RESULT:
7066                 if (klass->delegate) {
7067                         g_assert (!t->byref);
7068                         mono_mb_emit_stloc (mb, 0);
7069                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7070                         mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
7071                         mono_mb_emit_ldloc (mb, 0);
7072                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
7073                         mono_mb_emit_stloc (mb, 3);
7074                 } else {
7075                         /* set src */
7076                         mono_mb_emit_stloc (mb, 0);
7077         
7078                         /* Make a copy since emit_conv modifies local 0 */
7079                         loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7080                         mono_mb_emit_ldloc (mb, 0);
7081                         mono_mb_emit_stloc (mb, loc);
7082         
7083                         mono_mb_emit_byte (mb, CEE_LDNULL);
7084                         mono_mb_emit_stloc (mb, 3);
7085         
7086                         mono_mb_emit_ldloc (mb, 0);
7087                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
7088         
7089                         /* allocate result object */
7090         
7091                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7092                         mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);   
7093                         mono_mb_emit_stloc (mb, 3);
7094                                         
7095                         /* set dst  */
7096         
7097                         mono_mb_emit_ldloc (mb, 3);
7098                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7099                         mono_mb_emit_stloc (mb, 1);
7100                                                                 
7101                         /* emit conversion code */
7102                         emit_struct_conv (mb, klass, TRUE);
7103         
7104                         emit_struct_free (mb, klass, loc);
7105         
7106                         /* Free the pointer allocated by unmanaged code */
7107                         mono_mb_emit_ldloc (mb, loc);
7108                         mono_mb_emit_icall (mb, g_free);
7109                         mono_mb_patch_branch (mb, pos);
7110                 }
7111                 break;
7112
7113         case MARSHAL_ACTION_MANAGED_CONV_IN:
7114                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
7115
7116                 if (klass->delegate) {
7117                         g_assert (!t->byref);
7118                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7119                         mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
7120                         mono_mb_emit_ldarg (mb, argnum);
7121                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
7122                         mono_mb_emit_stloc (mb, conv_arg);
7123                         break;
7124                 }
7125
7126                 if (klass == mono_defaults.stringbuilder_class) {
7127                         MonoMarshalNative encoding;
7128
7129                         encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
7130
7131                         // FIXME:
7132                         g_assert (encoding == MONO_NATIVE_LPSTR);
7133
7134                         g_assert (!t->byref);
7135                         g_assert (encoding != -1);
7136
7137                         mono_mb_emit_ldarg (mb, argnum);
7138                         mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
7139                         mono_mb_emit_stloc (mb, conv_arg);
7140                         break;
7141                 }
7142
7143                 /* The class can not have an automatic layout */
7144                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
7145                         mono_mb_emit_auto_layout_exception (mb, klass);
7146                         break;
7147                 }
7148
7149                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
7150                         mono_mb_emit_byte (mb, CEE_LDNULL);
7151                         mono_mb_emit_stloc (mb, conv_arg);
7152                         break;
7153                 }
7154
7155                 /* Set src */
7156                 mono_mb_emit_ldarg (mb, argnum);
7157                 if (t->byref) {
7158                         int pos2;
7159
7160                         /* Check for NULL and raise an exception */
7161                         pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
7162
7163                         mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
7164
7165                         mono_mb_patch_branch (mb, pos2);
7166                         mono_mb_emit_ldarg (mb, argnum);
7167                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7168                 }                               
7169
7170                 mono_mb_emit_stloc (mb, 0);
7171
7172                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7173                 mono_mb_emit_stloc (mb, conv_arg);
7174
7175                 mono_mb_emit_ldloc (mb, 0);
7176                 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
7177
7178                 /* Create and set dst */
7179                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7180                 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);   
7181                 mono_mb_emit_stloc (mb, conv_arg);
7182                 mono_mb_emit_ldloc (mb, conv_arg);
7183                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7184                 mono_mb_emit_stloc (mb, 1); 
7185
7186                 /* emit valuetype conversion code */
7187                 emit_struct_conv (mb, klass, TRUE);
7188
7189                 mono_mb_patch_branch (mb, pos);
7190                 break;
7191
7192         case MARSHAL_ACTION_MANAGED_CONV_OUT:
7193                 if (t->byref) {
7194                         /* Check for null */
7195                         mono_mb_emit_ldloc (mb, conv_arg);
7196                         pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
7197                         mono_mb_emit_ldarg (mb, argnum);
7198                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7199                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7200                         pos2 = mono_mb_emit_branch (mb, CEE_BR);
7201
7202                         mono_mb_patch_branch (mb, pos);                 
7203                         
7204                         /* Set src */
7205                         mono_mb_emit_ldloc (mb, conv_arg);
7206                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7207                         mono_mb_emit_stloc (mb, 0);
7208
7209                         /* Allocate and set dest */
7210                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
7211                         mono_mb_emit_byte (mb, CEE_CONV_I);
7212                         mono_mb_emit_icall (mb, mono_marshal_alloc);
7213                         mono_mb_emit_stloc (mb, 1);
7214                         
7215                         /* Update argument pointer */
7216                         mono_mb_emit_ldarg (mb, argnum);
7217                         mono_mb_emit_ldloc (mb, 1);
7218                         mono_mb_emit_byte (mb, CEE_STIND_I);
7219                 
7220                         /* emit valuetype conversion code */
7221                         emit_struct_conv (mb, klass, FALSE);
7222
7223                         mono_mb_patch_branch (mb, pos2);
7224                 } else {
7225                         /* byval [Out] marshalling */
7226
7227                         /* FIXME: Handle null */
7228
7229                         /* Set src */
7230                         mono_mb_emit_ldloc (mb, conv_arg);
7231                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7232                         mono_mb_emit_stloc (mb, 0);
7233
7234                         /* Set dest */
7235                         mono_mb_emit_ldarg (mb, argnum);
7236                         mono_mb_emit_stloc (mb, 1);
7237                         
7238                         /* emit valuetype conversion code */
7239                         emit_struct_conv (mb, klass, FALSE);
7240                 }                       
7241                 break;
7242
7243         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
7244                 if (klass->delegate) {
7245                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
7246                         mono_mb_emit_stloc (mb, 3);
7247                         break;
7248                 }
7249
7250                 /* The class can not have an automatic layout */
7251                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
7252                         mono_mb_emit_auto_layout_exception (mb, klass);
7253                         break;
7254                 }
7255
7256                 mono_mb_emit_stloc (mb, 0);
7257                 /* Check for null */
7258                 mono_mb_emit_ldloc (mb, 0);
7259                 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
7260                 mono_mb_emit_byte (mb, CEE_LDNULL);
7261                 mono_mb_emit_stloc (mb, 3);
7262                 pos2 = mono_mb_emit_branch (mb, CEE_BR);
7263
7264                 mono_mb_patch_branch (mb, pos);
7265
7266                 /* Set src */
7267                 mono_mb_emit_ldloc (mb, 0);
7268                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
7269                 mono_mb_emit_stloc (mb, 0);
7270
7271                 /* Allocate and set dest */
7272                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
7273                 mono_mb_emit_byte (mb, CEE_CONV_I);
7274                 mono_mb_emit_icall (mb, mono_marshal_alloc);
7275                 mono_mb_emit_byte (mb, CEE_DUP);
7276                 mono_mb_emit_stloc (mb, 1);
7277                 mono_mb_emit_stloc (mb, 3);
7278
7279                 emit_struct_conv (mb, klass, FALSE);
7280
7281                 mono_mb_patch_branch (mb, pos2);
7282                 break;
7283
7284         default:
7285                 g_assert_not_reached ();
7286         }
7287
7288         return conv_arg;
7289 }
7290
7291 #ifndef DISABLE_COM
7292
7293 static int
7294 emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t,
7295                      MonoMarshalSpec *spec, 
7296                      int conv_arg, MonoType **conv_arg_type, 
7297                      MarshalAction action)
7298 {
7299         MonoMethodBuilder *mb = m->mb;
7300         MonoClass *klass = t->data.klass;
7301         static MonoMethod* get_object_for_iunknown = NULL;
7302         static MonoMethod* get_iunknown_for_object_internal = NULL;
7303         static MonoMethod* get_com_interface_for_object_internal = NULL;
7304         static MonoMethod* get_idispatch_for_object_internal = NULL;
7305         static MonoMethod* marshal_release = NULL;
7306         static MonoMethod* AddRef = NULL;
7307         if (!get_object_for_iunknown)
7308                 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
7309         if (!get_iunknown_for_object_internal)
7310                 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
7311         if (!get_idispatch_for_object_internal)
7312                 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
7313         if (!get_com_interface_for_object_internal)
7314                 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
7315         if (!marshal_release)
7316                 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
7317
7318         /* COM types are initialized lazily */
7319         mono_init_com_types ();
7320
7321         switch (action) {
7322         case MARSHAL_ACTION_CONV_IN: {
7323                 guint32 pos_null = 0;
7324
7325                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7326                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7327
7328                 mono_mb_emit_ptr (mb, NULL);
7329                 mono_mb_emit_stloc (mb, conv_arg);      
7330
7331                 /* we dont need any conversions for out parameters */
7332                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
7333                         break;
7334
7335                 mono_mb_emit_ldarg (mb, argnum);        
7336                 if (t->byref)
7337                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
7338                 /* if null just break, conv arg was already inited to 0 */
7339                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7340
7341                 mono_mb_emit_ldarg (mb, argnum);
7342                 if (t->byref)
7343                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
7344
7345                 if (klass && klass != mono_defaults.object_class) {
7346                         mono_mb_emit_ptr (mb, t);
7347                         mono_mb_emit_icall (mb, type_from_handle);
7348                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
7349                 }
7350                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
7351                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7352                 else if (spec->native == MONO_NATIVE_IDISPATCH)
7353                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
7354                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
7355                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7356                 else
7357                         g_assert_not_reached ();
7358                 mono_mb_emit_stloc (mb, conv_arg);
7359                 mono_mb_patch_short_branch (mb, pos_null);
7360                 break;
7361         }
7362
7363         case MARSHAL_ACTION_CONV_OUT: {
7364                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
7365                         int ccw_obj;
7366                         guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
7367                         ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7368
7369                         mono_mb_emit_ldarg (mb, argnum);
7370                         mono_mb_emit_byte (mb, CEE_LDNULL);
7371                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7372
7373                         mono_mb_emit_ldloc (mb, conv_arg);
7374                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7375
7376                         mono_mb_emit_ldloc (mb, conv_arg);
7377                         mono_mb_emit_icon (mb, TRUE);
7378                         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
7379                         mono_mb_emit_stloc (mb, ccw_obj);
7380                         mono_mb_emit_ldloc (mb, ccw_obj);
7381                         pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
7382
7383                         mono_mb_emit_ldarg (mb, argnum);
7384                         mono_mb_emit_ldloc (mb, conv_arg);
7385                         mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
7386
7387                         if (klass && klass != mono_defaults.object_class)
7388                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
7389                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7390
7391                         pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
7392
7393                         /* is already managed object */
7394                         mono_mb_patch_short_branch (mb, pos_ccw);
7395                         mono_mb_emit_ldarg (mb, argnum);
7396                         mono_mb_emit_ldloc (mb, ccw_obj);
7397
7398                         if (klass && klass != mono_defaults.object_class)
7399                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
7400                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7401
7402                         mono_mb_patch_short_branch (mb, pos_end);
7403
7404                         /* need to call Release to follow COM rules of ownership */
7405                         mono_mb_emit_ldloc (mb, conv_arg);
7406                         mono_mb_emit_managed_call (mb, marshal_release, NULL);
7407                         mono_mb_emit_byte (mb, CEE_POP);
7408
7409                         /* case if null */
7410                         mono_mb_patch_short_branch (mb, pos_null);
7411                 }
7412                 break;
7413         }
7414         case MARSHAL_ACTION_PUSH:
7415                 if (t->byref)
7416                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7417                 else
7418                         mono_mb_emit_ldloc (mb, conv_arg);
7419                 break;
7420
7421         case MARSHAL_ACTION_CONV_RESULT: {
7422                 int ccw_obj, ret_ptr;
7423                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
7424                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7425                 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7426
7427                 /* store return value */
7428                 mono_mb_emit_stloc (mb, ret_ptr);
7429
7430                 mono_mb_emit_ldloc (mb, ret_ptr);
7431                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7432
7433                 mono_mb_emit_ldloc (mb, ret_ptr);
7434                 mono_mb_emit_icon (mb, TRUE);
7435                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
7436                 mono_mb_emit_stloc (mb, ccw_obj);
7437                 mono_mb_emit_ldloc (mb, ccw_obj);
7438                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
7439
7440                 mono_mb_emit_ldloc (mb, ret_ptr);
7441                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
7442
7443                 if (klass && klass != mono_defaults.object_class)
7444                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
7445                 mono_mb_emit_stloc (mb, 3);
7446
7447                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
7448
7449                 /* is already managed object */
7450                 mono_mb_patch_short_branch (mb, pos_ccw);
7451                 mono_mb_emit_ldloc (mb, ccw_obj);
7452
7453                 if (klass && klass != mono_defaults.object_class)
7454                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
7455                 mono_mb_emit_stloc (mb, 3);
7456
7457                 mono_mb_patch_short_branch (mb, pos_end);
7458
7459                 /* need to call Release to follow COM rules of ownership */
7460                 mono_mb_emit_ldloc (mb, ret_ptr);
7461                 mono_mb_emit_managed_call (mb, marshal_release, NULL);
7462                 mono_mb_emit_byte (mb, CEE_POP);
7463
7464                 /* case if null */
7465                 mono_mb_patch_short_branch (mb, pos_null);
7466                 break;
7467         } 
7468
7469         case MARSHAL_ACTION_MANAGED_CONV_IN: {
7470                 int ccw_obj;
7471                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
7472                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7473
7474                 klass = mono_class_from_mono_type (t);
7475                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
7476                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7477
7478                 mono_mb_emit_byte (mb, CEE_LDNULL);
7479                 mono_mb_emit_stloc (mb, conv_arg);
7480                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
7481                         break;
7482
7483                 mono_mb_emit_ldarg (mb, argnum);
7484                 if (t->byref)
7485                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
7486                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7487
7488                 mono_mb_emit_ldarg (mb, argnum);
7489                 if (t->byref)
7490                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
7491                 mono_mb_emit_icon (mb, TRUE);
7492                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
7493                 mono_mb_emit_stloc (mb, ccw_obj);
7494                 mono_mb_emit_ldloc (mb, ccw_obj);
7495                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
7496
7497
7498                 mono_mb_emit_ldarg (mb, argnum);
7499                 if (t->byref)
7500                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
7501                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
7502
7503                 if (klass && klass != mono_defaults.object_class)
7504                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
7505                 mono_mb_emit_stloc (mb, conv_arg);
7506                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
7507
7508                 /* is already managed object */
7509                 mono_mb_patch_short_branch (mb, pos_ccw);
7510                 mono_mb_emit_ldloc (mb, ccw_obj);
7511                 if (klass && klass != mono_defaults.object_class)
7512                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
7513                 mono_mb_emit_stloc (mb, conv_arg);
7514
7515                 mono_mb_patch_short_branch (mb, pos_end);
7516                 /* case if null */
7517                 mono_mb_patch_short_branch (mb, pos_null);
7518                 break;
7519         }
7520
7521         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7522                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
7523                         guint32 pos_null = 0;
7524
7525                         if (!AddRef)
7526                                 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
7527
7528                         mono_mb_emit_ldloc (mb, conv_arg);      
7529                         /* if null just break, conv arg was already inited to 0 */
7530                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7531
7532                         /* to store later */
7533                         mono_mb_emit_ldarg (mb, argnum);        
7534                         mono_mb_emit_ldloc (mb, conv_arg);
7535                         if (klass && klass != mono_defaults.object_class) {
7536                                 mono_mb_emit_ptr (mb, t);
7537                                 mono_mb_emit_icall (mb, type_from_handle);
7538                                 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
7539                         }
7540                         else if (spec->native == MONO_NATIVE_IUNKNOWN)
7541                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7542                         else if (spec->native == MONO_NATIVE_IDISPATCH)
7543                                 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
7544                         else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
7545                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7546                         else
7547                                 g_assert_not_reached ();
7548                         mono_mb_emit_byte (mb, CEE_STIND_I);
7549
7550                         mono_mb_emit_ldarg (mb, argnum);
7551                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7552                         mono_mb_emit_managed_call (mb, AddRef, NULL);
7553                         mono_mb_emit_byte (mb, CEE_POP);
7554
7555                         mono_mb_patch_short_branch (mb, pos_null);
7556                 }
7557                 break;
7558         }
7559
7560         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7561                 guint32 pos_null = 0;
7562                 int ccw_obj;
7563                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7564
7565                 if (!AddRef)
7566                         AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
7567
7568                 /* store return value */
7569                 mono_mb_emit_stloc (mb, ccw_obj);
7570
7571                 mono_mb_emit_ldloc (mb, ccw_obj);
7572
7573                 /* if null just break, conv arg was already inited to 0 */
7574                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7575
7576                 /* to store later */
7577                 mono_mb_emit_ldloc (mb, ccw_obj);
7578                 if (klass && klass != mono_defaults.object_class) {
7579                         mono_mb_emit_ptr (mb, t);
7580                         mono_mb_emit_icall (mb, type_from_handle);
7581                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
7582                 }
7583                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
7584                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7585                 else if (spec->native == MONO_NATIVE_IDISPATCH)
7586                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
7587                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
7588                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7589                 else
7590                         g_assert_not_reached ();
7591                 mono_mb_emit_stloc (mb, 3);
7592                 mono_mb_emit_ldloc (mb, 3);
7593                 
7594                 mono_mb_emit_managed_call (mb, AddRef, NULL);
7595                 mono_mb_emit_byte (mb, CEE_POP);
7596
7597                 mono_mb_patch_short_branch (mb, pos_null);
7598                 break;
7599         }
7600
7601         default:
7602                 g_assert_not_reached ();
7603         }
7604
7605         return conv_arg;
7606 }
7607
7608 #endif /* DISABLE_COM */
7609
7610 static int
7611 emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
7612                      MonoMarshalSpec *spec, 
7613                      int conv_arg, MonoType **conv_arg_type, 
7614                      MarshalAction action)
7615 {
7616         MonoMethodBuilder *mb = m->mb;
7617         static MonoMethod *get_object_for_native_variant = NULL;
7618         static MonoMethod *get_native_variant_for_object = NULL;
7619
7620         mono_init_com_types ();
7621         
7622         if (!get_object_for_native_variant)
7623                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
7624         g_assert (get_object_for_native_variant);
7625
7626         if (!get_native_variant_for_object)
7627                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
7628         g_assert (get_native_variant_for_object);
7629
7630         switch (action) {
7631         case MARSHAL_ACTION_CONV_IN: {
7632                 conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
7633                 
7634                 if (t->byref)
7635                         *conv_arg_type = &mono_defaults.variant_class->this_arg;
7636                 else
7637                         *conv_arg_type = &mono_defaults.variant_class->byval_arg;
7638
7639                 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
7640                         break;
7641
7642                 mono_mb_emit_ldarg (mb, argnum);
7643                 if (t->byref)
7644                         mono_mb_emit_byte(mb, CEE_LDIND_REF);
7645                 mono_mb_emit_ldloc_addr (mb, conv_arg);
7646                 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
7647                 break;
7648         }
7649
7650         case MARSHAL_ACTION_CONV_OUT: {
7651                 static MonoMethod *variant_clear = NULL;
7652
7653                 if (!variant_clear)
7654                         variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
7655                 g_assert (variant_clear);
7656
7657
7658                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
7659                         mono_mb_emit_ldarg (mb, argnum);
7660                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7661                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
7662                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7663                 }
7664
7665                 mono_mb_emit_ldloc_addr (mb, conv_arg);
7666                 mono_mb_emit_managed_call (mb, variant_clear, NULL);
7667                 break;
7668         }
7669
7670         case MARSHAL_ACTION_PUSH:
7671                 if (t->byref)
7672                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7673                 else
7674                         mono_mb_emit_ldloc (mb, conv_arg);
7675                 break;
7676
7677         case MARSHAL_ACTION_CONV_RESULT: {
7678                 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
7679                 mono_mb_emit_exception_marshal_directive (mb, msg);
7680                 break;
7681         }
7682
7683         case MARSHAL_ACTION_MANAGED_CONV_IN: {
7684                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7685
7686                 if (t->byref)
7687                         *conv_arg_type = &mono_defaults.variant_class->this_arg;
7688                 else
7689                         *conv_arg_type = &mono_defaults.variant_class->byval_arg;
7690
7691                 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
7692                         break;
7693
7694                 if (t->byref)
7695                         mono_mb_emit_ldarg (mb, argnum);
7696                 else
7697                         mono_mb_emit_ldarg_addr (mb, argnum);
7698                 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
7699                 mono_mb_emit_stloc (mb, conv_arg);
7700                 break;
7701         }
7702
7703         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7704                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
7705                         mono_mb_emit_ldloc (mb, conv_arg);
7706                         mono_mb_emit_ldarg (mb, argnum);
7707                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
7708                 }
7709                 break;
7710         }
7711
7712         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7713                 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
7714                 mono_mb_emit_exception_marshal_directive (mb, msg);
7715                 break;
7716         }
7717
7718         default:
7719                 g_assert_not_reached ();
7720         }
7721
7722         return conv_arg;
7723 }
7724
7725 static int
7726 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
7727                                         MonoMarshalSpec *spec, 
7728                                         int conv_arg, MonoType **conv_arg_type, 
7729                                         MarshalAction action)
7730 {
7731         MonoMethodBuilder *mb = m->mb;
7732         MonoClass *klass = mono_class_from_mono_type (t);
7733         gboolean need_convert, need_free;
7734         MonoMarshalNative encoding;
7735
7736         encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
7737
7738         switch (action) {
7739         case MARSHAL_ACTION_CONV_IN:
7740                 *conv_arg_type = &mono_defaults.object_class->byval_arg;
7741                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7742
7743                 if (klass->element_class->blittable) {
7744                         mono_mb_emit_ldarg (mb, argnum);
7745                         if (t->byref)
7746                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7747                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
7748                         mono_mb_emit_stloc (mb, conv_arg);
7749                 } else {
7750                         MonoClass *eklass;
7751                         guint32 label1, label2, label3;
7752                         int index_var, src_var, dest_ptr, esize;
7753                         MonoMarshalConv conv;
7754                         gboolean is_string = FALSE;
7755
7756                         dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7757
7758                         eklass = klass->element_class;
7759
7760                         if (eklass == mono_defaults.string_class) {
7761                                 is_string = TRUE;
7762                                 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7763                         }
7764                         else if (eklass == mono_defaults.stringbuilder_class) {
7765                                 is_string = TRUE;
7766                                 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
7767                         }
7768                         else
7769                                 conv = -1;
7770
7771                         src_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7772                         mono_mb_emit_ldarg (mb, argnum);
7773                         if (t->byref)
7774                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7775                         mono_mb_emit_stloc (mb, src_var);
7776
7777                         /* Check null */
7778                         mono_mb_emit_ldloc (mb, src_var);
7779                         mono_mb_emit_stloc (mb, conv_arg);
7780                         mono_mb_emit_ldloc (mb, src_var);
7781                         label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7782
7783                         if (is_string) {
7784                                 if (conv == -1) {
7785                                         char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
7786                                         MonoException *exc = mono_get_exception_not_implemented (msg);
7787                                         g_warning (msg);
7788                                         g_free (msg);
7789                                         mono_raise_exception (exc);
7790                                 }
7791                         }
7792
7793                         if (is_string)
7794                                 esize = sizeof (gpointer);
7795                         else
7796                                 esize = mono_class_native_size (eklass, NULL);
7797
7798                         /* allocate space for the native struct and store the address */
7799                         mono_mb_emit_icon (mb, esize);
7800                         mono_mb_emit_ldloc (mb, src_var);
7801                         mono_mb_emit_byte (mb, CEE_LDLEN);
7802
7803                         if (eklass == mono_defaults.string_class) {
7804                                 /* Make the array bigger for the terminating null */
7805                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7806                                 mono_mb_emit_byte (mb, CEE_ADD);
7807                         }
7808                         mono_mb_emit_byte (mb, CEE_MUL);
7809                         mono_mb_emit_byte (mb, CEE_PREFIX1);
7810                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
7811                         mono_mb_emit_stloc (mb, conv_arg);
7812
7813                         mono_mb_emit_ldloc (mb, conv_arg);
7814                         mono_mb_emit_stloc (mb, dest_ptr);
7815
7816                         /* Emit marshalling loop */
7817                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
7818                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7819                         mono_mb_emit_stloc (mb, index_var);
7820                         label2 = mono_mb_get_label (mb);
7821                         mono_mb_emit_ldloc (mb, index_var);
7822                         mono_mb_emit_ldloc (mb, src_var);
7823                         mono_mb_emit_byte (mb, CEE_LDLEN);
7824                         label3 = mono_mb_emit_branch (mb, CEE_BGE);
7825
7826                         /* Emit marshalling code */
7827
7828                         if (is_string) {
7829                                 mono_mb_emit_ldloc (mb, dest_ptr);
7830                                 mono_mb_emit_ldloc (mb, src_var);
7831                                 mono_mb_emit_ldloc (mb, index_var);
7832                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7833                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
7834                                 mono_mb_emit_byte (mb, CEE_STIND_I);
7835                         } else {
7836                                 /* set the src_ptr */
7837                                 mono_mb_emit_ldloc (mb, src_var);
7838                                 mono_mb_emit_ldloc (mb, index_var);
7839                                 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
7840                                 mono_mb_emit_stloc (mb, 0);
7841
7842                                 /* set dst_ptr */
7843                                 mono_mb_emit_ldloc (mb, dest_ptr);
7844                                 mono_mb_emit_stloc (mb, 1);
7845
7846                                 /* emit valuetype conversion code */
7847                                 emit_struct_conv (mb, eklass, FALSE);
7848                         }
7849
7850                         mono_mb_emit_add_to_local (mb, index_var, 1);
7851                         mono_mb_emit_add_to_local (mb, dest_ptr, esize);
7852                         
7853                         mono_mb_emit_branch_label (mb, CEE_BR, label2);
7854
7855                         mono_mb_patch_branch (mb, label3);
7856
7857                         if (eklass == mono_defaults.string_class) {
7858                                 /* Null terminate */
7859                                 mono_mb_emit_ldloc (mb, dest_ptr);
7860                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7861                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
7862                         }
7863
7864                         mono_mb_patch_branch (mb, label1);
7865                 }
7866
7867                 break;
7868
7869         case MARSHAL_ACTION_CONV_OUT:
7870                 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
7871                 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);
7872                 need_free = mono_marshal_need_free (&klass->element_class->byval_arg, 
7873                                                                                         m->piinfo, spec);
7874
7875                 if (need_convert || need_free) {
7876                         /* FIXME: Optimize blittable case */
7877                         MonoClass *eklass;
7878                         guint32 label1, label2, label3;
7879                         int index_var, src_ptr, loc, esize;
7880
7881                         eklass = klass->element_class;
7882                         if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
7883                                 esize = sizeof (gpointer);
7884                         else
7885                                 esize = mono_class_native_size (eklass, NULL);
7886                         src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7887                         loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7888
7889                         /* Check null */
7890                         mono_mb_emit_ldarg (mb, argnum);
7891                         if (t->byref)
7892                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7893                         label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7894
7895                         mono_mb_emit_ldloc (mb, conv_arg);
7896                         mono_mb_emit_stloc (mb, src_ptr);
7897
7898                         /* Emit marshalling loop */
7899                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
7900                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7901                         mono_mb_emit_stloc (mb, index_var);
7902                         label2 = mono_mb_get_label (mb);
7903                         mono_mb_emit_ldloc (mb, index_var);
7904                         mono_mb_emit_ldarg (mb, argnum);
7905                         if (t->byref)
7906                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
7907                         mono_mb_emit_byte (mb, CEE_LDLEN);
7908                         label3 = mono_mb_emit_branch (mb, CEE_BGE);
7909
7910                         /* Emit marshalling code */
7911
7912                         if (eklass == mono_defaults.stringbuilder_class) {
7913                                 gboolean need_free2;
7914                                 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
7915
7916                                 g_assert (conv != -1);
7917
7918                                 /* dest */
7919                                 mono_mb_emit_ldarg (mb, argnum);
7920                                 if (t->byref)
7921                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7922                                 mono_mb_emit_ldloc (mb, index_var);
7923                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7924
7925                                 /* src */
7926                                 mono_mb_emit_ldloc (mb, src_ptr);
7927                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7928
7929                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
7930
7931                                 if (need_free) {
7932                                         /* src */
7933                                         mono_mb_emit_ldloc (mb, src_ptr);
7934                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7935
7936                                         mono_mb_emit_icall (mb, mono_marshal_free);
7937                                 }
7938                         }
7939                         else if (eklass == mono_defaults.string_class) {
7940                                 if (need_free) {
7941                                         /* src */
7942                                         mono_mb_emit_ldloc (mb, src_ptr);
7943                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7944
7945                                         mono_mb_emit_icall (mb, mono_marshal_free);
7946                                 }
7947                         }
7948                         else {
7949                                 if (need_convert) {
7950                                         /* set the src_ptr */
7951                                         mono_mb_emit_ldloc (mb, src_ptr);
7952                                         mono_mb_emit_stloc (mb, 0);
7953
7954                                         /* set dst_ptr */
7955                                         mono_mb_emit_ldarg (mb, argnum);
7956                                         if (t->byref)
7957                                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
7958                                         mono_mb_emit_ldloc (mb, index_var);
7959                                         mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
7960                                         mono_mb_emit_stloc (mb, 1);
7961
7962                                         /* emit valuetype conversion code */
7963                                         emit_struct_conv (mb, eklass, TRUE);
7964                                 }
7965
7966                                 if (need_free) {
7967                                         mono_mb_emit_ldloc (mb, src_ptr);
7968                                         mono_mb_emit_stloc (mb, loc);
7969                                         mono_mb_emit_ldloc (mb, loc);
7970
7971                                         emit_struct_free (mb, eklass, loc);
7972                                 }
7973                         }
7974
7975                         mono_mb_emit_add_to_local (mb, index_var, 1);
7976                         mono_mb_emit_add_to_local (mb, src_ptr, esize);
7977
7978                         mono_mb_emit_branch_label (mb, CEE_BR, label2);
7979
7980                         mono_mb_patch_branch (mb, label1);
7981                         mono_mb_patch_branch (mb, label3);
7982                 }
7983                 break;
7984
7985         case MARSHAL_ACTION_PUSH:
7986                 if (t->byref)
7987                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7988                 else
7989                         mono_mb_emit_ldloc (mb, conv_arg);
7990                 break;
7991
7992         case MARSHAL_ACTION_CONV_RESULT:
7993                 /* fixme: we need conversions here */
7994                 mono_mb_emit_stloc (mb, 3);
7995                 break;
7996
7997         case MARSHAL_ACTION_MANAGED_CONV_IN: {
7998                 MonoClass *eklass;
7999                 guint32 label1, label2, label3;
8000                 int index_var, src_ptr, loc, esize, param_num, num_elem;
8001                 MonoMarshalConv conv;
8002                 gboolean is_string = FALSE;
8003                 
8004                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
8005                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
8006
8007                 if (t->byref) {
8008                         char *msg = g_strdup ("Byref array marshalling to managed code is not implemented.");
8009                         mono_mb_emit_exception_marshal_directive (mb, msg);
8010                         return conv_arg;
8011                 }
8012                 if (!spec) {
8013                         char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
8014                         mono_mb_emit_exception_marshal_directive (mb, msg);
8015                         return conv_arg;
8016                 }                       
8017                 if (spec->native != MONO_NATIVE_LPARRAY) {
8018                         char *msg = g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
8019                         mono_mb_emit_exception_marshal_directive (mb, msg);
8020                         return conv_arg;                        
8021                 }
8022
8023                 /* FIXME: t is from the method which is wrapped, not the delegate type */
8024                 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
8025
8026                 param_num = spec->data.array_data.param_num;
8027                 num_elem = spec->data.array_data.num_elem;
8028                 if (spec->data.array_data.elem_mult == 0)
8029                         /* param_num is not specified */
8030                         param_num = -1;
8031
8032                 if (param_num == -1) {
8033                         if (num_elem <= 0) {
8034                                 char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
8035                                 mono_mb_emit_exception_marshal_directive (mb, msg);
8036                                 return conv_arg;
8037                         }
8038                 }
8039
8040                 /* FIXME: Optimize blittable case */
8041
8042                 eklass = klass->element_class;
8043                 if (eklass == mono_defaults.string_class) {
8044                         is_string = TRUE;
8045                         conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
8046                 }
8047                 else if (eklass == mono_defaults.stringbuilder_class) {
8048                         is_string = TRUE;
8049                         conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
8050                 }
8051                 else
8052                         conv = -1;
8053
8054                 mono_marshal_load_type_info (eklass);
8055
8056                 if (is_string)
8057                         esize = sizeof (gpointer);
8058                 else
8059                         esize = mono_class_native_size (eklass, NULL);
8060                 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8061                 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8062
8063                 mono_mb_emit_byte (mb, CEE_LDNULL);
8064                 mono_mb_emit_stloc (mb, conv_arg);
8065
8066                 /* Check param index */
8067                 if (param_num != -1) {
8068                         if (param_num >= m->sig->param_count) {
8069                                 char *msg = g_strdup ("Array size control parameter index is out of range.");
8070                                 mono_mb_emit_exception_marshal_directive (mb, msg);
8071                                 return conv_arg;
8072                         }
8073                         switch (m->sig->params [param_num]->type) {
8074                         case MONO_TYPE_I1:
8075                         case MONO_TYPE_U1:
8076                         case MONO_TYPE_I2:
8077                         case MONO_TYPE_U2:
8078                         case MONO_TYPE_I4:
8079                         case MONO_TYPE_U4:
8080                         case MONO_TYPE_I:
8081                         case MONO_TYPE_U:
8082                         case MONO_TYPE_I8:
8083                         case MONO_TYPE_U8:
8084                                 break;
8085                         default: {
8086                                 char *msg = g_strdup ("Array size control parameter must be an integral type.");
8087                                 mono_mb_emit_exception_marshal_directive (mb, msg);
8088                                 return conv_arg;
8089                         }
8090                         }
8091                 }
8092
8093                 /* Check null */
8094                 mono_mb_emit_ldarg (mb, argnum);
8095                 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
8096
8097                 mono_mb_emit_ldarg (mb, argnum);
8098                 mono_mb_emit_stloc (mb, src_ptr);
8099
8100                 /* Create managed array */
8101                 /* 
8102                  * The LPArray marshalling spec says that sometimes param_num starts 
8103                  * from 1, sometimes it starts from 0. But MS seems to allways start
8104                  * from 0.
8105                  */
8106
8107                 if (param_num == -1)
8108                         mono_mb_emit_icon (mb, num_elem);
8109                 else {
8110                         /* FIXME: Add the two together */
8111                         mono_mb_emit_ldarg (mb, param_num);
8112                         if (num_elem > 0) {
8113                                 mono_mb_emit_icon (mb, num_elem);
8114                                 mono_mb_emit_byte (mb, CEE_ADD);
8115                         }
8116                 }
8117
8118                 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
8119                 mono_mb_emit_stloc (mb, conv_arg);
8120
8121                 if (eklass->blittable) {
8122                         mono_mb_emit_ldloc (mb, conv_arg);
8123                         mono_mb_emit_byte (mb, CEE_CONV_I);
8124                         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
8125                         mono_mb_emit_byte (mb, CEE_ADD);
8126                         mono_mb_emit_ldarg (mb, argnum);
8127                         mono_mb_emit_ldloc (mb, conv_arg);
8128                         mono_mb_emit_byte (mb, CEE_LDLEN);
8129                         mono_mb_emit_icon (mb, esize);
8130                         mono_mb_emit_byte (mb, CEE_MUL);
8131                         mono_mb_emit_byte (mb, CEE_PREFIX1);
8132                         mono_mb_emit_byte (mb, CEE_CPBLK);                      
8133                         break;
8134                 }
8135
8136                 /* Emit marshalling loop */
8137                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8138                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
8139                 mono_mb_emit_stloc (mb, index_var);
8140                 label2 = mono_mb_get_label (mb);
8141                 mono_mb_emit_ldloc (mb, index_var);
8142                 mono_mb_emit_ldloc (mb, conv_arg);
8143                 mono_mb_emit_byte (mb, CEE_LDLEN);
8144                 label3 = mono_mb_emit_branch (mb, CEE_BGE);
8145
8146                 /* Emit marshalling code */
8147                 if (is_string) {
8148                         g_assert (conv != -1);
8149
8150                         mono_mb_emit_ldloc (mb, conv_arg);
8151                         mono_mb_emit_ldloc (mb, index_var);
8152
8153                         mono_mb_emit_ldloc (mb, src_ptr);
8154                         mono_mb_emit_byte (mb, CEE_LDIND_I);
8155
8156                         mono_mb_emit_icall (mb, conv_to_icall (conv));
8157                         mono_mb_emit_byte (mb, CEE_STELEM_REF);
8158                 }
8159                 else {
8160                         char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
8161                         mono_mb_emit_exception_marshal_directive (mb, msg);
8162                         return conv_arg;
8163                 }
8164
8165                 mono_mb_emit_add_to_local (mb, index_var, 1);
8166                 mono_mb_emit_add_to_local (mb, src_ptr, esize);
8167
8168                 mono_mb_emit_branch_label (mb, CEE_BR, label2);
8169
8170                 mono_mb_patch_branch (mb, label1);
8171                 mono_mb_patch_branch (mb, label3);
8172                 
8173                 break;
8174         }
8175         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
8176                 MonoClass *eklass;
8177                 guint32 label1, label2, label3;
8178                 int index_var, dest_ptr, loc, esize, param_num, num_elem;
8179                 MonoMarshalConv conv;
8180                 gboolean is_string = FALSE;
8181
8182                 if (!spec)
8183                         /* Already handled in CONV_IN */
8184                         break;
8185                 
8186                 /* These are already checked in CONV_IN */
8187                 g_assert (!t->byref);
8188                 g_assert (spec->native == MONO_NATIVE_LPARRAY);
8189                 g_assert (t->attrs & PARAM_ATTRIBUTE_OUT);
8190
8191                 param_num = spec->data.array_data.param_num;
8192                 num_elem = spec->data.array_data.num_elem;
8193
8194                 if (spec->data.array_data.elem_mult == 0)
8195                         /* param_num is not specified */
8196                         param_num = -1;
8197
8198                 if (param_num == -1) {
8199                         if (num_elem <= 0) {
8200                                 g_assert_not_reached ();
8201                         }
8202                 }
8203
8204                 /* FIXME: Optimize blittable case */
8205
8206                 eklass = klass->element_class;
8207                 if (eklass == mono_defaults.string_class) {
8208                         is_string = TRUE;
8209                         conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
8210                 }
8211                 else if (eklass == mono_defaults.stringbuilder_class) {
8212                         is_string = TRUE;
8213                         conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
8214                 }
8215                 else
8216                         conv = -1;
8217
8218                 mono_marshal_load_type_info (eklass);
8219
8220                 if (is_string)
8221                         esize = sizeof (gpointer);
8222                 else
8223                         esize = mono_class_native_size (eklass, NULL);
8224
8225                 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8226                 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8227
8228                 /* Check null */
8229                 mono_mb_emit_ldloc (mb, conv_arg);
8230                 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
8231
8232                 mono_mb_emit_ldarg (mb, argnum);
8233                 mono_mb_emit_stloc (mb, dest_ptr);
8234
8235                 if (eklass->blittable) {
8236                         /* dest */
8237                         mono_mb_emit_ldarg (mb, argnum);
8238                         /* src */
8239                         mono_mb_emit_ldloc (mb, conv_arg);
8240                         mono_mb_emit_byte (mb, CEE_CONV_I);
8241                         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
8242                         mono_mb_emit_byte (mb, CEE_ADD);
8243                         /* length */
8244                         mono_mb_emit_ldloc (mb, conv_arg);
8245                         mono_mb_emit_byte (mb, CEE_LDLEN);
8246                         mono_mb_emit_icon (mb, esize);
8247                         mono_mb_emit_byte (mb, CEE_MUL);
8248                         mono_mb_emit_byte (mb, CEE_PREFIX1);
8249                         mono_mb_emit_byte (mb, CEE_CPBLK);                      
8250                         break;
8251                 }
8252
8253                 /* Emit marshalling loop */
8254                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8255                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
8256                 mono_mb_emit_stloc (mb, index_var);
8257                 label2 = mono_mb_get_label (mb);
8258                 mono_mb_emit_ldloc (mb, index_var);
8259                 mono_mb_emit_ldloc (mb, conv_arg);
8260                 mono_mb_emit_byte (mb, CEE_LDLEN);
8261                 label3 = mono_mb_emit_branch (mb, CEE_BGE);
8262
8263                 /* Emit marshalling code */
8264                 if (is_string) {
8265                         g_assert (conv != -1);
8266
8267                         /* dest */
8268                         mono_mb_emit_ldloc (mb, dest_ptr);
8269
8270                         /* src */
8271                         mono_mb_emit_ldloc (mb, conv_arg);
8272                         mono_mb_emit_ldloc (mb, index_var);
8273
8274                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
8275
8276                         mono_mb_emit_icall (mb, conv_to_icall (conv));
8277                         mono_mb_emit_byte (mb, CEE_STIND_I);
8278                 }
8279                 else {
8280                         char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
8281                         mono_mb_emit_exception_marshal_directive (mb, msg);
8282                         return conv_arg;
8283                 }
8284
8285                 mono_mb_emit_add_to_local (mb, index_var, 1);
8286                 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
8287
8288                 mono_mb_emit_branch_label (mb, CEE_BR, label2);
8289
8290                 mono_mb_patch_branch (mb, label1);
8291                 mono_mb_patch_branch (mb, label3);
8292
8293                 break;
8294         }
8295         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
8296                 MonoClass *eklass;
8297                 guint32 label1, label2, label3;
8298                 int index_var, src, dest, esize;
8299                 MonoMarshalConv conv = -1;
8300                 gboolean is_string = FALSE;
8301                 
8302                 g_assert (!t->byref);
8303
8304                 eklass = klass->element_class;
8305
8306                 mono_marshal_load_type_info (eklass);
8307
8308                 if (eklass == mono_defaults.string_class) {
8309                         is_string = TRUE;
8310                         conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
8311                 }
8312                 else {
8313                         g_assert_not_reached ();
8314                 }
8315
8316                 if (is_string)
8317                         esize = sizeof (gpointer);
8318                 else
8319                         esize = mono_class_native_size (eklass, NULL);
8320
8321                 src = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
8322                 dest = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8323                         
8324                 mono_mb_emit_stloc (mb, src);
8325                 mono_mb_emit_ldloc (mb, src);
8326                 mono_mb_emit_stloc (mb, 3);
8327
8328                 /* Check for null */
8329                 mono_mb_emit_ldloc (mb, src);
8330                 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
8331
8332                 /* Allocate native array */
8333                 mono_mb_emit_icon (mb, esize);
8334                 mono_mb_emit_ldloc (mb, src);
8335                 mono_mb_emit_byte (mb, CEE_LDLEN);
8336
8337                 if (eklass == mono_defaults.string_class) {
8338                         /* Make the array bigger for the terminating null */
8339                         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
8340                         mono_mb_emit_byte (mb, CEE_ADD);
8341                 }
8342                 mono_mb_emit_byte (mb, CEE_MUL);
8343                 mono_mb_emit_icall (mb, mono_marshal_alloc);
8344                 mono_mb_emit_stloc (mb, dest);
8345                 mono_mb_emit_ldloc (mb, dest);
8346                 mono_mb_emit_stloc (mb, 3);
8347
8348                 /* Emit marshalling loop */
8349                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8350                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
8351                 mono_mb_emit_stloc (mb, index_var);
8352                 label2 = mono_mb_get_label (mb);
8353                 mono_mb_emit_ldloc (mb, index_var);
8354                 mono_mb_emit_ldloc (mb, src);
8355                 mono_mb_emit_byte (mb, CEE_LDLEN);
8356                 label3 = mono_mb_emit_branch (mb, CEE_BGE);
8357
8358                 /* Emit marshalling code */
8359                 if (is_string) {
8360                         g_assert (conv != -1);
8361
8362                         /* dest */
8363                         mono_mb_emit_ldloc (mb, dest);
8364
8365                         /* src */
8366                         mono_mb_emit_ldloc (mb, src);
8367                         mono_mb_emit_ldloc (mb, index_var);
8368
8369                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
8370
8371                         mono_mb_emit_icall (mb, conv_to_icall (conv));
8372                         mono_mb_emit_byte (mb, CEE_STIND_I);
8373                 }
8374                 else {
8375                         char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
8376                         mono_mb_emit_exception_marshal_directive (mb, msg);
8377                         return conv_arg;
8378                 }
8379
8380                 mono_mb_emit_add_to_local (mb, index_var, 1);
8381                 mono_mb_emit_add_to_local (mb, dest, esize);
8382
8383                 mono_mb_emit_branch_label (mb, CEE_BR, label2);
8384
8385                 mono_mb_patch_branch (mb, label3);
8386                 mono_mb_patch_branch (mb, label1);
8387                 break;
8388         }
8389         default:
8390                 g_assert_not_reached ();
8391         }
8392
8393         return conv_arg;
8394 }
8395
8396 static int
8397 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
8398                       MonoMarshalSpec *spec, 
8399                       int conv_arg, MonoType **conv_arg_type, 
8400                       MarshalAction action)
8401 {
8402         MonoMethodBuilder *mb = m->mb;
8403
8404         switch (action) {
8405         case MARSHAL_ACTION_CONV_IN: {
8406                 MonoType *local_type;
8407                 int variant_bool = 0;
8408                 if (!t->byref)
8409                         break;
8410                 if (spec == NULL) {
8411                         local_type = &mono_defaults.int32_class->byval_arg;
8412                 } else {
8413                         switch (spec->native) {
8414                         case MONO_NATIVE_I1:
8415                         case MONO_NATIVE_U1:
8416                                 local_type = &mono_defaults.byte_class->byval_arg;
8417                                 break;
8418                         case MONO_NATIVE_VARIANTBOOL:
8419                                 local_type = &mono_defaults.int16_class->byval_arg;
8420                                 variant_bool = 1;
8421                                 break;
8422                         default:
8423                                 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
8424                                 local_type = &mono_defaults.int32_class->byval_arg;
8425                                 break;
8426                         }
8427                 }
8428                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
8429                 conv_arg = mono_mb_add_local (mb, local_type);
8430                 mono_mb_emit_ldarg (mb, argnum);
8431                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
8432                 if (variant_bool)
8433                         mono_mb_emit_byte (mb, CEE_NEG);
8434                 mono_mb_emit_stloc (mb, conv_arg);
8435                 break;
8436         }
8437
8438         case MARSHAL_ACTION_CONV_OUT:
8439                 if (!t->byref)
8440                         break;
8441                 mono_mb_emit_ldarg (mb, argnum);
8442                 mono_mb_emit_ldloc (mb, conv_arg);
8443                 if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL)
8444                         mono_mb_emit_byte (mb, CEE_NEG);
8445                 mono_mb_emit_byte (mb, CEE_STIND_I1);
8446                 break;
8447
8448         case MARSHAL_ACTION_PUSH:
8449                 if (t->byref)
8450                         mono_mb_emit_ldloc_addr (mb, conv_arg);
8451                 else
8452                         mono_mb_emit_ldarg (mb, argnum);
8453                 break;
8454
8455         case MARSHAL_ACTION_CONV_RESULT:
8456                 /* maybe we need to make sure that it fits within 8 bits */
8457                 mono_mb_emit_stloc (mb, 3);
8458                 break;
8459
8460         default:
8461                 g_assert_not_reached ();
8462         }
8463
8464         return conv_arg;
8465 }
8466
8467 static int
8468 emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t, 
8469                   MonoMarshalSpec *spec, int conv_arg, 
8470                   MonoType **conv_arg_type, MarshalAction action)
8471 {
8472         MonoMethodBuilder *mb = m->mb;
8473
8474         switch (action) {
8475         case MARSHAL_ACTION_CONV_IN:
8476                 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
8477                         char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
8478                         mono_mb_emit_exception_marshal_directive (m->mb, msg);
8479                 }
8480                 break;
8481
8482         case MARSHAL_ACTION_PUSH:
8483                 mono_mb_emit_ldarg (mb, argnum);
8484                 break;
8485
8486         case MARSHAL_ACTION_CONV_RESULT:
8487                 /* no conversions necessary */
8488                 mono_mb_emit_stloc (mb, 3);
8489                 break;
8490
8491         default:
8492                 break;
8493         }
8494
8495         return conv_arg;
8496 }
8497
8498 static int
8499 emit_marshal_char (EmitMarshalContext *m, int argnum, MonoType *t, 
8500                    MonoMarshalSpec *spec, int conv_arg, 
8501                    MonoType **conv_arg_type, MarshalAction action)
8502 {
8503         MonoMethodBuilder *mb = m->mb;
8504
8505         switch (action) {
8506         case MARSHAL_ACTION_PUSH:
8507                 /* fixme: dont know how to marshal that. We cant simply
8508                  * convert it to a one byte UTF8 character, because an
8509                  * unicode character may need more that one byte in UTF8 */
8510                 mono_mb_emit_ldarg (mb, argnum);
8511                 break;
8512
8513         case MARSHAL_ACTION_CONV_RESULT:
8514                 /* fixme: we need conversions here */
8515                 mono_mb_emit_stloc (mb, 3);
8516                 break;
8517
8518         default:
8519                 break;
8520         }
8521
8522         return conv_arg;
8523 }
8524
8525 static int
8526 emit_marshal_scalar (EmitMarshalContext *m, int argnum, MonoType *t, 
8527                      MonoMarshalSpec *spec, int conv_arg, 
8528                      MonoType **conv_arg_type, MarshalAction action)
8529 {
8530         MonoMethodBuilder *mb = m->mb;
8531
8532         switch (action) {
8533         case MARSHAL_ACTION_PUSH:
8534                 mono_mb_emit_ldarg (mb, argnum);
8535                 break;
8536
8537         case MARSHAL_ACTION_CONV_RESULT:
8538                 /* no conversions necessary */
8539                 mono_mb_emit_stloc (mb, 3);
8540                 break;
8541
8542         default:
8543                 break;
8544         }
8545
8546         return conv_arg;
8547 }
8548
8549 static int
8550 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, 
8551               MonoMarshalSpec *spec, int conv_arg, 
8552               MonoType **conv_arg_type, MarshalAction action)
8553 {
8554         /* Ensure that we have marshalling info for this param */
8555         mono_marshal_load_type_info (mono_class_from_mono_type (t));
8556
8557         if (spec && spec->native == MONO_NATIVE_CUSTOM)
8558                 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8559
8560         if (spec && spec->native == MONO_NATIVE_ASANY)
8561                 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8562                         
8563         switch (t->type) {
8564         case MONO_TYPE_VALUETYPE:
8565                 if (t->data.klass == mono_defaults.handleref_class)
8566                         return emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8567                 
8568                 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8569         case MONO_TYPE_STRING:
8570                 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8571         case MONO_TYPE_CLASS:
8572         case MONO_TYPE_OBJECT:
8573                 if (spec && spec->native == MONO_NATIVE_STRUCT)
8574                         return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8575
8576 #ifndef DISABLE_COM
8577                 if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
8578                         spec->native == MONO_NATIVE_IDISPATCH ||
8579                         spec->native == MONO_NATIVE_INTERFACE))
8580                         return emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8581 #endif
8582
8583                 if (mono_defaults.safehandle_class != NULL &&
8584                     mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
8585                         return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8586                 
8587                 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8588         case MONO_TYPE_ARRAY:
8589         case MONO_TYPE_SZARRAY:
8590                 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8591         case MONO_TYPE_BOOLEAN:
8592                 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8593         case MONO_TYPE_PTR:
8594                 return emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8595         case MONO_TYPE_CHAR:
8596                 return emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8597         case MONO_TYPE_I1:
8598         case MONO_TYPE_U1:
8599         case MONO_TYPE_I2:
8600         case MONO_TYPE_U2:
8601         case MONO_TYPE_I4:
8602         case MONO_TYPE_U4:
8603         case MONO_TYPE_I:
8604         case MONO_TYPE_U:
8605         case MONO_TYPE_R4:
8606         case MONO_TYPE_R8:
8607         case MONO_TYPE_I8:
8608         case MONO_TYPE_U8:
8609         case MONO_TYPE_FNPTR:
8610                 return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8611         case MONO_TYPE_GENERICINST:
8612                 if (mono_type_generic_inst_is_valuetype (t))
8613                         return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8614                 else
8615                         return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8616         }
8617
8618         return conv_arg;
8619 }
8620
8621 /**
8622  * mono_marshal_emit_native_wrapper:
8623  * @image: the image to use for looking up custom marshallers
8624  * @sig: The signature of the native function
8625  * @piinfo: Marshalling information
8626  * @mspecs: Marshalling information
8627  * @aot: whenever the created method will be compiled by the AOT compiler
8628  * @method: if non-NULL, the pinvoke method to call
8629  * @check_exceptions: Whenever to check for pending exceptions after the native call
8630  *
8631  * generates IL code for the pinvoke wrapper, the generated code calls @func.
8632  */
8633 static void
8634 mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions)
8635 {
8636         EmitMarshalContext m;
8637         MonoMethodSignature *csig;
8638         MonoClass *klass;
8639         int i, argnum, *tmp_locals;
8640         int type;
8641         static MonoMethodSignature *get_last_error_sig = NULL;
8642
8643         m.mb = mb;
8644         m.piinfo = piinfo;
8645
8646         /* we copy the signature, so that we can set pinvoke to 0 */
8647         csig = signature_dup (mb->method->klass->image, sig);
8648         csig->pinvoke = 1;
8649         m.csig = csig;
8650         m.image = image;
8651
8652         /* we allocate local for use with emit_struct_conv() */
8653         /* allocate local 0 (pointer) src_ptr */
8654         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8655         /* allocate local 1 (pointer) dst_ptr */
8656         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8657         /* allocate local 2 (boolean) delete_old */
8658         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
8659
8660         /* delete_old = FALSE */
8661         mono_mb_emit_icon (mb, 0);
8662         mono_mb_emit_stloc (mb, 2);
8663
8664         if (!MONO_TYPE_IS_VOID(sig->ret)) {
8665                 /* allocate local 3 to store the return value */
8666                 mono_mb_add_local (mb, sig->ret);
8667         }
8668
8669         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
8670                 /* Return type custom marshaling */
8671                 /*
8672                  * Since we can't determine the return type of the unmanaged function,
8673                  * we assume it returns a pointer, and pass that pointer to
8674                  * MarshalNativeToManaged.
8675                  */
8676                 csig->ret = &mono_defaults.int_class->byval_arg;
8677         }
8678
8679         /* we first do all conversions */
8680         tmp_locals = alloca (sizeof (int) * sig->param_count);
8681         m.orig_conv_args = alloca (sizeof (int) * (sig->param_count + 1));
8682
8683         for (i = 0; i < sig->param_count; i ++) {
8684                 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
8685         }
8686
8687         /* push all arguments */
8688
8689         if (sig->hasthis)
8690                 mono_mb_emit_byte (mb, CEE_LDARG_0);
8691
8692         for (i = 0; i < sig->param_count; i++) {
8693                 emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
8694         }                       
8695
8696         /* call the native method */
8697         if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
8698 #ifndef DISABLE_COM
8699                 mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
8700 #else
8701                 g_assert_not_reached ();
8702 #endif
8703         }
8704         else {
8705                 if (aot) {
8706                         /* Reuse the ICALL_ADDR opcode for pinvokes too */
8707                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8708                         mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
8709                         mono_mb_emit_calli (mb, csig);
8710                 } else {                        
8711                         mono_mb_emit_native_call (mb, csig, func);
8712                 }
8713         }
8714
8715         /* Set LastError if needed */
8716         if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
8717                 if (!get_last_error_sig) {
8718                         get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
8719                         get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
8720                         get_last_error_sig->pinvoke = 1;
8721                 }
8722
8723 #ifdef PLATFORM_WIN32
8724                 /* 
8725                  * Have to call GetLastError () early and without a wrapper, since various runtime components could
8726                  * clobber its value.
8727                  */
8728                 mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
8729                 mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
8730 #else
8731                 mono_mb_emit_icall (mb, mono_marshal_set_last_error);
8732 #endif
8733         }               
8734
8735         /* convert the result */
8736         if (!sig->ret->byref) {
8737                 MonoMarshalSpec *spec = mspecs [0];
8738                 type = sig->ret->type;
8739
8740                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
8741                         emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8742                 } else {
8743
8744                 handle_enum:
8745                         switch (type) {
8746                         case MONO_TYPE_VOID:
8747                                 break;
8748                         case MONO_TYPE_VALUETYPE:
8749                                 klass = sig->ret->data.klass;
8750                                 if (klass->enumtype) {
8751                                         type = sig->ret->data.klass->enum_basetype->type;
8752                                         goto handle_enum;
8753                                 }
8754                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8755                                 break;
8756                         case MONO_TYPE_I1:
8757                         case MONO_TYPE_U1:
8758                         case MONO_TYPE_I2:
8759                         case MONO_TYPE_U2:
8760                         case MONO_TYPE_I4:
8761                         case MONO_TYPE_U4:
8762                         case MONO_TYPE_I:
8763                         case MONO_TYPE_U:
8764                         case MONO_TYPE_R4:
8765                         case MONO_TYPE_R8:
8766                         case MONO_TYPE_I8:
8767                         case MONO_TYPE_U8:
8768                         case MONO_TYPE_FNPTR:
8769                         case MONO_TYPE_STRING:
8770                         case MONO_TYPE_CLASS:
8771                         case MONO_TYPE_OBJECT:
8772                         case MONO_TYPE_BOOLEAN:
8773                         case MONO_TYPE_ARRAY:
8774                         case MONO_TYPE_SZARRAY:
8775                         case MONO_TYPE_CHAR:
8776                         case MONO_TYPE_PTR:
8777                         case MONO_TYPE_GENERICINST:
8778                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8779                                 break;
8780                         case MONO_TYPE_TYPEDBYREF:
8781                         default:
8782                                 g_warning ("return type 0x%02x unknown", sig->ret->type);       
8783                                 g_assert_not_reached ();
8784                         }
8785                 }
8786         } else {
8787                 mono_mb_emit_stloc (mb, 3);
8788         }
8789
8790         /* 
8791          * Need to call this after converting the result since MONO_VTADDR needs 
8792          * to be adjacent to the call instruction.
8793          */
8794         if (check_exceptions)
8795                 emit_thread_interrupt_checkpoint (mb);
8796
8797         /* we need to convert byref arguments back and free string arrays */
8798         for (i = 0; i < sig->param_count; i++) {
8799                 MonoType *t = sig->params [i];
8800                 MonoMarshalSpec *spec = mspecs [i + 1];
8801
8802                 argnum = i + sig->hasthis;
8803
8804                 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
8805                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
8806                         continue;
8807                 }
8808
8809                 switch (t->type) {
8810                 case MONO_TYPE_STRING:
8811                 case MONO_TYPE_VALUETYPE:
8812                 case MONO_TYPE_CLASS:
8813                 case MONO_TYPE_OBJECT:
8814                 case MONO_TYPE_SZARRAY:
8815                 case MONO_TYPE_BOOLEAN:
8816                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
8817                         break;
8818                 }
8819         }
8820
8821         if (!MONO_TYPE_IS_VOID(sig->ret))
8822                 mono_mb_emit_ldloc (mb, 3);
8823
8824         mono_mb_emit_byte (mb, CEE_RET);
8825 }
8826
8827 /**
8828  * mono_marshal_get_native_wrapper:
8829  * @method: The MonoMethod to wrap.
8830  * @check_exceptions: Whenever to check for pending exceptions
8831  *
8832  * generates IL code for the pinvoke wrapper (the generated method
8833  * calls the unmanaged code in piinfo->addr)
8834  */
8835 MonoMethod *
8836 mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
8837 {
8838         MonoMethodSignature *sig, *csig;
8839         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
8840         MonoMethodBuilder *mb;
8841         MonoMarshalSpec **mspecs;
8842         MonoMethod *res;
8843         GHashTable *cache;
8844         gboolean pinvoke = FALSE;
8845         gpointer iter;
8846         int i;
8847         const char *exc_class = "MissingMethodException";
8848         const char *exc_arg = NULL;
8849
8850         g_assert (method != NULL);
8851         g_assert (mono_method_signature (method)->pinvoke);
8852
8853         cache = method->klass->image->native_wrapper_cache;
8854         if ((res = mono_marshal_find_in_cache (cache, method)))
8855                 return res;
8856
8857         if (MONO_CLASS_IS_IMPORT (method->klass)) {
8858 #ifndef DISABLE_COM
8859                 return cominterop_get_native_wrapper (method);
8860 #else
8861                 g_assert_not_reached ();
8862 #endif
8863         }
8864
8865         sig = mono_method_signature (method);
8866
8867         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
8868             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
8869                 pinvoke = TRUE;
8870
8871         if (!piinfo->addr) {
8872                 if (pinvoke)
8873                         if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
8874                                 exc_arg = "Method contains unsupported native code";
8875                         else
8876                                 mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
8877                 else
8878                         piinfo->addr = mono_lookup_internal_call (method);
8879         }
8880
8881         /* hack - redirect certain string constructors to CreateString */
8882         if (piinfo->addr == ves_icall_System_String_ctor_RedirectToCreateString) {
8883                 g_assert (!pinvoke);
8884                 g_assert (method->string_ctor);
8885                 g_assert (sig->hasthis);
8886
8887                 /* CreateString returns a value */
8888                 csig = signature_dup (method->klass->image, sig);
8889                 csig->ret = &mono_defaults.string_class->byval_arg;
8890                 csig->pinvoke = 0;
8891
8892                 iter = NULL;
8893                 while ((res = mono_class_get_methods (mono_defaults.string_class, &iter))) {
8894                         if (!strcmp ("CreateString", res->name) &&
8895                                 mono_metadata_signature_equal (csig, mono_method_signature (res))) {
8896
8897                                 g_assert (!(res->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
8898                                 g_assert (!(res->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
8899
8900                                 /* create a wrapper to preserve .ctor in stack trace */
8901                                 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
8902
8903                                 mono_mb_emit_byte (mb, CEE_LDARG_0);
8904                                 for (i = 1; i <= csig->param_count; i++)
8905                                         mono_mb_emit_ldarg (mb, i);
8906                                 mono_mb_emit_managed_call (mb, res, NULL);
8907                                 mono_mb_emit_byte (mb, CEE_RET);
8908
8909                                 /* use native_wrapper_cache because internal calls are looked up there */
8910                                 res = mono_mb_create_and_cache (cache, method,
8911                                         mb, csig, csig->param_count + 1);
8912
8913                                 mono_mb_free (mb);
8914
8915                                 return res;
8916                         }
8917                 }
8918
8919                 /* exception will be thrown */
8920                 piinfo->addr = NULL;
8921                 g_warning ("cannot find CreateString for .ctor");
8922         }
8923
8924         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8925
8926         mb->method->save_lmf = 1;
8927
8928         /*
8929          * In AOT mode and embedding scenarios, it is possible that the icall is not
8930          * registered in the runtime doing the AOT compilation.
8931          */
8932         if (!piinfo->addr && !aot) {
8933                 mono_mb_emit_exception (mb, exc_class, exc_arg);
8934                 csig = signature_dup (method->klass->image, sig);
8935                 csig->pinvoke = 0;
8936                 res = mono_mb_create_and_cache (cache, method,
8937                                                                                 mb, csig, csig->param_count + 16);
8938                 mono_mb_free (mb);
8939                 return res;
8940         }
8941
8942         /* internal calls: we simply push all arguments and call the method (no conversions) */
8943         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
8944
8945                 /* hack - string constructors returns a value */
8946                 if (method->string_ctor) {
8947                         csig = signature_dup (method->klass->image, sig);
8948                         csig->ret = &mono_defaults.string_class->byval_arg;
8949                 } else
8950                         csig = sig;
8951
8952                 if (sig->hasthis)
8953                         mono_mb_emit_byte (mb, CEE_LDARG_0);
8954
8955                 for (i = 0; i < sig->param_count; i++)
8956                         mono_mb_emit_ldarg (mb, i + sig->hasthis);
8957
8958                 if (aot) {
8959                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8960                         mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
8961                         mono_mb_emit_calli (mb, csig);
8962                 } else {
8963                         g_assert (piinfo->addr);
8964                         mono_mb_emit_native_call (mb, csig, piinfo->addr);
8965                 }
8966                 if (check_exceptions)
8967                         emit_thread_interrupt_checkpoint (mb);
8968                 mono_mb_emit_byte (mb, CEE_RET);
8969
8970                 csig = signature_dup (method->klass->image, csig);
8971                 csig->pinvoke = 0;
8972                 res = mono_mb_create_and_cache (cache, method,
8973                                                                                 mb, csig, csig->param_count + 16);
8974                 mono_mb_free (mb);
8975                 return res;
8976         }
8977
8978         g_assert (pinvoke);
8979         if (!aot)
8980                 g_assert (piinfo->addr);
8981
8982         mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
8983         mono_method_get_marshal_info (method, mspecs);
8984
8985         mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, aot, check_exceptions);
8986
8987         csig = signature_dup (method->klass->image, sig);
8988         csig->pinvoke = 0;
8989         res = mono_mb_create_and_cache (cache, method,
8990                                                                         mb, csig, csig->param_count + 16);
8991         mono_mb_free (mb);
8992
8993         for (i = sig->param_count; i >= 0; i--)
8994                 if (mspecs [i])
8995                         mono_metadata_free_marshal_spec (mspecs [i]);
8996         g_free (mspecs);
8997
8998         /* 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)); */ 
8999
9000         return res;
9001 }
9002
9003 /**
9004  * mono_marshal_get_native_func_wrapper:
9005  * @image: The image to use for memory allocation and for looking up custom marshallers.
9006  * @sig: The signature of the function
9007  * @func: The native function to wrap
9008  *
9009  *   Returns a wrapper method around native functions, similar to the pinvoke
9010  * wrapper.
9011  */
9012 MonoMethod *
9013 mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig, 
9014                                                                           MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
9015 {
9016         MonoMethodSignature *csig;
9017
9018         MonoMethodBuilder *mb;
9019         MonoMethod *res;
9020         GHashTable *cache;
9021         char *name;
9022
9023         cache = image->native_wrapper_cache;
9024         if ((res = mono_marshal_find_in_cache (cache, func)))
9025                 return res;
9026
9027         name = g_strdup_printf ("wrapper_native_%p", func);
9028         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
9029         mb->method->save_lmf = 1;
9030
9031         mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE);
9032
9033         csig = signature_dup (image, sig);
9034         csig->pinvoke = 0;
9035         res = mono_mb_create_and_cache (cache, func,
9036                                                                         mb, csig, csig->param_count + 16);
9037         mono_mb_free (mb);
9038
9039         /* 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)); */ 
9040
9041         return res;
9042 }
9043                             
9044 /* FIXME: moving GC */
9045 static void
9046 mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this)
9047 {
9048         MonoMethodSignature *sig, *csig;
9049         int i, *tmp_locals;
9050
9051         sig = m->sig;
9052         csig = m->csig;
9053
9054         /* allocate local 0 (pointer) src_ptr */
9055         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9056         /* allocate local 1 (pointer) dst_ptr */
9057         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9058         /* allocate local 2 (boolean) delete_old */
9059         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
9060
9061         if (!MONO_TYPE_IS_VOID(sig->ret)) {
9062                 /* allocate local 3 to store the return value */
9063                 mono_mb_add_local (mb, sig->ret);
9064         }
9065
9066         mono_mb_emit_icon (mb, 0);
9067         mono_mb_emit_stloc (mb, 2);
9068
9069         /* we first do all conversions */
9070         tmp_locals = alloca (sizeof (int) * sig->param_count);
9071         for (i = 0; i < sig->param_count; i ++) {
9072                 MonoType *t = sig->params [i];
9073                 
9074                 switch (t->type) {
9075                 case MONO_TYPE_OBJECT:
9076                 case MONO_TYPE_CLASS:
9077                 case MONO_TYPE_VALUETYPE:
9078                 case MONO_TYPE_ARRAY:
9079                 case MONO_TYPE_SZARRAY:
9080                 case MONO_TYPE_STRING:
9081                         tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
9082
9083                         break;
9084                 default:
9085                         tmp_locals [i] = 0;
9086                         break;
9087                 }
9088         }
9089
9090         emit_thread_interrupt_checkpoint (mb);
9091
9092         /* fixme: howto handle this ? */
9093         if (sig->hasthis) {
9094                 if (this) {
9095                         /* FIXME: need a solution for the moving GC here */
9096                         mono_mb_emit_ptr (mb, this);
9097                 } else {
9098                         /* fixme: */
9099                         g_assert_not_reached ();
9100                 }
9101         } 
9102
9103         for (i = 0; i < sig->param_count; i++) {
9104                 MonoType *t = sig->params [i];
9105
9106                 if (tmp_locals [i]) {
9107                         if (t->byref)
9108                                 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
9109                         else
9110                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
9111                 }
9112                 else
9113                         mono_mb_emit_ldarg (mb, i);
9114         }
9115
9116         mono_mb_emit_managed_call (mb, method, NULL);
9117
9118         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
9119                 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
9120         }
9121         else
9122         if (!sig->ret->byref) { 
9123                 switch (sig->ret->type) {
9124                 case MONO_TYPE_VOID:
9125                         break;
9126                 case MONO_TYPE_BOOLEAN:
9127                 case MONO_TYPE_I1:
9128                 case MONO_TYPE_U1:
9129                 case MONO_TYPE_CHAR:
9130                 case MONO_TYPE_I2:
9131                 case MONO_TYPE_U2:
9132                 case MONO_TYPE_I4:
9133                 case MONO_TYPE_U4:
9134                 case MONO_TYPE_I:
9135                 case MONO_TYPE_U:
9136                 case MONO_TYPE_PTR:
9137                 case MONO_TYPE_R4:
9138                 case MONO_TYPE_R8:
9139                 case MONO_TYPE_I8:
9140                 case MONO_TYPE_U8:
9141                 case MONO_TYPE_OBJECT:
9142                         mono_mb_emit_stloc (mb, 3);
9143                         break;
9144                 case MONO_TYPE_STRING:
9145                         csig->ret = &mono_defaults.int_class->byval_arg;
9146                         emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
9147                         break;
9148                 case MONO_TYPE_VALUETYPE:
9149                 case MONO_TYPE_CLASS:
9150                 case MONO_TYPE_SZARRAY:
9151                         emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
9152                         break;
9153                 default:
9154                         g_warning ("return type 0x%02x unknown", sig->ret->type);       
9155                         g_assert_not_reached ();
9156                 }
9157         } else {
9158                 mono_mb_emit_stloc (mb, 3);
9159         }
9160
9161         /* Convert byref arguments back */
9162         for (i = 0; i < sig->param_count; i ++) {
9163                 MonoType *t = sig->params [i];
9164                 MonoMarshalSpec *spec = mspecs [i + 1];
9165
9166                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
9167                         emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
9168                 }
9169                 else if (t->byref) {
9170                         switch (t->type) {
9171                         case MONO_TYPE_CLASS:
9172                         case MONO_TYPE_VALUETYPE:
9173                         case MONO_TYPE_OBJECT:
9174                         case MONO_TYPE_STRING:
9175                                 emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
9176                                 break;
9177                         }
9178                 }
9179                 else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
9180                         /* The [Out] information is encoded in the delegate signature */
9181                         switch (t->type) {
9182                         case MONO_TYPE_SZARRAY:
9183                         case MONO_TYPE_CLASS:
9184                         case MONO_TYPE_VALUETYPE:
9185                                 emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
9186                                 break;
9187                         default:
9188                                 g_assert_not_reached ();
9189                         }
9190                 }
9191         }
9192
9193         if (m->retobj_var) {
9194                 mono_mb_emit_ldloc (mb, m->retobj_var);
9195                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
9196                 mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
9197         }
9198         else {
9199                 if (!MONO_TYPE_IS_VOID(sig->ret))
9200                         mono_mb_emit_ldloc (mb, 3);
9201                 mono_mb_emit_byte (mb, CEE_RET);
9202         }
9203 }
9204
9205
9206 static void 
9207 mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *csig)
9208 {
9209         MonoMethodSignature *sig;
9210         int i;
9211
9212 #ifdef PLATFORM_WIN32
9213         /* 
9214          * Under windows, delegates passed to native code must use the STDCALL
9215          * calling convention.
9216          */
9217         csig->call_convention = MONO_CALL_STDCALL;
9218 #endif
9219
9220         sig = mono_method_signature (method);
9221
9222         /* Change default calling convention if needed */
9223         /* Why is this a modopt ? */
9224         if (sig->ret && sig->ret->num_mods) {
9225                 for (i = 0; i < sig->ret->num_mods; ++i) {
9226                         MonoClass *cmod_class = mono_class_get (method->klass->image, sig->ret->modifiers [i].token);
9227                         g_assert (cmod_class);
9228                         if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
9229                                 if (!strcmp (cmod_class->name, "CallConvCdecl"))
9230                                         csig->call_convention = MONO_CALL_C;
9231                                 else if (!strcmp (cmod_class->name, "CallConvStdcall"))
9232                                         csig->call_convention = MONO_CALL_STDCALL;
9233                                 else if (!strcmp (cmod_class->name, "CallConvFastcall"))
9234                                         csig->call_convention = MONO_CALL_FASTCALL;
9235                                 else if (!strcmp (cmod_class->name, "CallConvThiscall"))
9236                                         csig->call_convention = MONO_CALL_THISCALL;
9237                         }
9238                 }
9239         }
9240 }
9241
9242 /*
9243  * generates IL code to call managed methods from unmanaged code 
9244  */
9245 MonoMethod *
9246 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
9247 {
9248         static MonoClass *UnmanagedFunctionPointerAttribute;
9249         MonoMethodSignature *sig, *csig, *invoke_sig;
9250         MonoMethodBuilder *mb;
9251         MonoMethod *res, *invoke;
9252         MonoMarshalSpec **mspecs;
9253         MonoMethodPInvoke piinfo;
9254         GHashTable *cache;
9255         int i;
9256         EmitMarshalContext m;
9257
9258         g_assert (method != NULL);
9259         g_assert (!mono_method_signature (method)->pinvoke);
9260
9261         /* 
9262          * FIXME: Should cache the method+delegate type pair, since the same method
9263          * could be called with different delegates, thus different marshalling
9264          * options.
9265          */
9266         cache = get_cache (&method->klass->image->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
9267         if (!this && (res = mono_marshal_find_in_cache (cache, method)))
9268                 return res;
9269
9270         invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
9271         invoke_sig = mono_method_signature (invoke);
9272
9273         mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
9274         mono_method_get_marshal_info (invoke, mspecs);
9275
9276         sig = mono_method_signature (method);
9277
9278         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
9279
9280
9281         /* we copy the signature, so that we can modify it */
9282         if (this)
9283                 /* Need to free this later */
9284                 csig = mono_metadata_signature_dup (sig);
9285         else
9286                 csig = signature_dup (method->klass->image, sig);
9287         csig->hasthis = 0;
9288         csig->pinvoke = 1;
9289
9290         m.mb = mb;
9291         m.sig = sig;
9292         m.piinfo = NULL;
9293         m.retobj_var = 0;
9294         m.csig = csig;
9295         m.image = method->klass->image;
9296
9297         mono_marshal_set_callconv_from_modopt (invoke, csig);
9298
9299         /* Handle the UnmanagedFunctionPointerAttribute */
9300         if (!UnmanagedFunctionPointerAttribute)
9301                 UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
9302
9303         /* The attribute is only available in Net 2.0 */
9304         if (UnmanagedFunctionPointerAttribute) {
9305                 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
9306                 MonoCustomAttrInfo *cinfo;
9307
9308                 /* 
9309                  * The pinvoke attributes are stored in a real custom attribute so we have to
9310                  * construct it.
9311                  */
9312                 cinfo = mono_custom_attrs_from_class (delegate_klass);
9313                 if (cinfo) {
9314                         attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
9315                         if (attr) {
9316                                 memset (&piinfo, 0, sizeof (piinfo));
9317                                 m.piinfo = &piinfo;
9318                                 piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
9319
9320                                 csig->call_convention = attr->call_conv - 1;
9321                         }
9322                         if (!cinfo->cached)
9323                                 mono_custom_attrs_free (cinfo);
9324                 }
9325         }
9326
9327         mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this);
9328
9329         if (!this)
9330                 res = mono_mb_create_and_cache (cache, method,
9331                                                                                          mb, csig, sig->param_count + 16);
9332         else {
9333                 mb->dynamic = 1;
9334                 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
9335         }
9336         mono_mb_free (mb);
9337
9338         for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
9339                 if (mspecs [i])
9340                         mono_metadata_free_marshal_spec (mspecs [i]);
9341         g_free (mspecs);
9342
9343         /* 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)); */
9344
9345         return res;
9346 }
9347
9348 gpointer
9349 mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
9350 {
9351         MonoMethod *method;
9352         MonoMethodSignature *sig;
9353         MonoMethodBuilder *mb;
9354         int i, param_count;
9355
9356         g_assert (token);
9357
9358         method = mono_get_method (image, token, NULL);
9359         g_assert (method);
9360
9361         if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) {
9362                 MonoMethodSignature *csig;
9363                 MonoMarshalSpec **mspecs;
9364                 EmitMarshalContext m;
9365
9366                 sig = mono_method_signature (method);
9367                 g_assert (!sig->hasthis);
9368
9369                 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
9370                 mono_method_get_marshal_info (method, mspecs);
9371
9372                 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
9373                 csig = signature_dup (image, sig);
9374                 csig->hasthis = 0;
9375                 csig->pinvoke = 1;
9376
9377                 m.mb = mb;
9378                 m.sig = sig;
9379                 m.piinfo = NULL;
9380                 m.retobj_var = 0;
9381                 m.csig = csig;
9382                 m.image = image;
9383
9384                 mono_marshal_set_callconv_from_modopt (method, csig);
9385
9386                 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
9387
9388                 mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, NULL);
9389
9390                 mb->dynamic = 1;
9391                 method = mono_mb_create_method (mb, csig, sig->param_count + 16);
9392                 mono_mb_free (mb);
9393
9394                 for (i = sig->param_count; i >= 0; i--)
9395                         if (mspecs [i])
9396                                 mono_metadata_free_marshal_spec (mspecs [i]);
9397                 g_free (mspecs);
9398
9399                 return mono_compile_method (method);
9400         }
9401
9402         sig = mono_method_signature (method);
9403         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
9404
9405         param_count = sig->param_count + sig->hasthis;
9406         for (i = 0; i < param_count; i++)
9407                 mono_mb_emit_ldarg (mb, i);
9408
9409         if (type & VTFIXUP_TYPE_CALL_MOST_DERIVED)
9410                 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
9411         else
9412                 mono_mb_emit_op (mb, CEE_CALL, method);
9413         mono_mb_emit_byte (mb, CEE_RET);
9414
9415         mb->dynamic = 1;
9416         method = mono_mb_create_method (mb, sig, param_count);
9417         mono_mb_free (mb);
9418
9419         return mono_compile_method (method);
9420 }
9421
9422 static MonoReflectionType *
9423 type_from_handle (MonoType *handle)
9424 {
9425         MonoDomain *domain = mono_domain_get (); 
9426         MonoClass *klass = mono_class_from_mono_type (handle);
9427
9428         MONO_ARCH_SAVE_REGS;
9429
9430         mono_class_init (klass);
9431         return mono_type_get_object (domain, handle);
9432 }
9433
9434 /*
9435  * mono_marshal_get_isinst:
9436  * @klass: the type of the field
9437  *
9438  * This method generates a function which can be used to check if an object is
9439  * an instance of the given type, icluding the case where the object is a proxy.
9440  * The generated function has the following signature:
9441  * MonoObject* __isinst_wrapper_ (MonoObject *obj)
9442  */
9443 MonoMethod *
9444 mono_marshal_get_isinst (MonoClass *klass)
9445 {
9446         static MonoMethodSignature *isint_sig = NULL;
9447         GHashTable *cache;
9448         MonoMethod *res;
9449         int pos_was_ok, pos_failed, pos_end, pos_end2;
9450         char *name;
9451         MonoMethodBuilder *mb;
9452
9453         cache = get_cache (&klass->image->isinst_cache, mono_aligned_addr_hash, NULL);
9454         if ((res = mono_marshal_find_in_cache (cache, klass)))
9455                 return res;
9456
9457         if (!isint_sig) {
9458                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
9459                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
9460                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
9461                 isint_sig->pinvoke = 0;
9462         }
9463         
9464         name = g_strdup_printf ("__isinst_wrapper_%s", klass->name); 
9465         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
9466         g_free (name);
9467         
9468         mb->method->save_lmf = 1;
9469
9470         /* check if the object is a proxy that needs special cast */
9471         mono_mb_emit_ldarg (mb, 0);
9472         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
9473         mono_mb_emit_op (mb, CEE_MONO_CISINST, klass);
9474
9475         /* The result of MONO_ISINST can be:
9476                 0) the type check succeeded
9477                 1) the type check did not succeed
9478                 2) a CanCastTo call is needed */
9479         
9480         mono_mb_emit_byte (mb, CEE_DUP);
9481         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
9482
9483         mono_mb_emit_byte (mb, CEE_LDC_I4_2);
9484         pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
9485         
9486         /* get the real proxy from the transparent proxy*/
9487
9488         mono_mb_emit_ldarg (mb, 0);
9489         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
9490         pos_end = mono_mb_emit_branch (mb, CEE_BR);
9491         
9492         /* fail */
9493         
9494         mono_mb_patch_branch (mb, pos_failed);
9495         mono_mb_emit_byte (mb, CEE_LDNULL);
9496         pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
9497         
9498         /* success */
9499         
9500         mono_mb_patch_branch (mb, pos_was_ok);
9501         mono_mb_emit_byte (mb, CEE_POP);
9502         mono_mb_emit_ldarg (mb, 0);
9503         
9504         /* the end */
9505         
9506         mono_mb_patch_branch (mb, pos_end);
9507         mono_mb_patch_branch (mb, pos_end2);
9508         mono_mb_emit_byte (mb, CEE_RET);
9509
9510         res = mono_mb_create_and_cache (cache, klass, mb, isint_sig, isint_sig->param_count + 16);
9511         mono_mb_free (mb);
9512
9513         return res;
9514 }
9515
9516 /*
9517  * mono_marshal_get_castclass:
9518  * @klass: the type of the field
9519  *
9520  * This method generates a function which can be used to cast an object to
9521  * an instance of the given type, icluding the case where the object is a proxy.
9522  * The generated function has the following signature:
9523  * MonoObject* __castclass_wrapper_ (MonoObject *obj)
9524  */
9525 MonoMethod *
9526 mono_marshal_get_castclass (MonoClass *klass)
9527 {
9528         static MonoMethodSignature *castclass_sig = NULL;
9529         GHashTable *cache;
9530         MonoMethod *res;
9531         int pos_was_ok, pos_was_ok2;
9532         char *name;
9533         MonoMethodBuilder *mb;
9534
9535         cache = get_cache (&klass->image->castclass_cache, mono_aligned_addr_hash, NULL);
9536         if ((res = mono_marshal_find_in_cache (cache, klass)))
9537                 return res;
9538
9539         if (!castclass_sig) {
9540                 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
9541                 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
9542                 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
9543                 castclass_sig->pinvoke = 0;
9544         }
9545         
9546         name = g_strdup_printf ("__castclass_wrapper_%s", klass->name); 
9547         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
9548         g_free (name);
9549         
9550         mb->method->save_lmf = 1;
9551
9552         /* check if the object is a proxy that needs special cast */
9553         mono_mb_emit_ldarg (mb, 0);
9554         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
9555         mono_mb_emit_op (mb, CEE_MONO_CCASTCLASS, klass);
9556
9557         /* The result of MONO_ISINST can be:
9558                 0) the cast is valid
9559                 1) cast of unknown proxy type
9560                 or an exception if the cast is is invalid
9561         */
9562         
9563         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
9564
9565         /* get the real proxy from the transparent proxy*/
9566
9567         mono_mb_emit_ldarg (mb, 0);
9568         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
9569         pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
9570         
9571         /* fail */
9572         mono_mb_emit_exception (mb, "InvalidCastException", NULL);
9573         
9574         /* success */
9575         mono_mb_patch_branch (mb, pos_was_ok);
9576         mono_mb_patch_branch (mb, pos_was_ok2);
9577         mono_mb_emit_ldarg (mb, 0);
9578         
9579         /* the end */
9580         mono_mb_emit_byte (mb, CEE_RET);
9581
9582         res = mono_mb_create_and_cache (cache, klass, mb, castclass_sig, castclass_sig->param_count + 16);
9583         mono_mb_free (mb);
9584
9585         return res;
9586 }
9587
9588 MonoMethod *
9589 mono_marshal_get_proxy_cancast (MonoClass *klass)
9590 {
9591         static MonoMethodSignature *isint_sig = NULL;
9592         GHashTable *cache;
9593         MonoMethod *res;
9594         int pos_failed, pos_end;
9595         char *name;
9596         MonoMethod *can_cast_to;
9597         MonoMethodDesc *desc;
9598         MonoMethodBuilder *mb;
9599
9600         cache = get_cache (&klass->image->proxy_isinst_cache, mono_aligned_addr_hash, NULL);
9601         if ((res = mono_marshal_find_in_cache (cache, klass)))
9602                 return res;
9603
9604         if (!isint_sig) {
9605                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
9606                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
9607                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
9608                 isint_sig->pinvoke = 0;
9609         }
9610         
9611         name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name); 
9612         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
9613         g_free (name);
9614         
9615         mb->method->save_lmf = 1;
9616
9617         /* get the real proxy from the transparent proxy*/
9618         mono_mb_emit_ldarg (mb, 0);
9619         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
9620         mono_mb_emit_byte (mb, CEE_LDIND_REF);
9621         
9622         /* get the reflection type from the type handle */
9623         mono_mb_emit_ptr (mb, &klass->byval_arg);
9624         mono_mb_emit_icall (mb, type_from_handle);
9625         
9626         mono_mb_emit_ldarg (mb, 0);
9627         
9628         /* make the call to CanCastTo (type, ob) */
9629         desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
9630         can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
9631         g_assert (can_cast_to);
9632         mono_method_desc_free (desc);
9633         mono_mb_emit_op (mb, CEE_CALLVIRT, can_cast_to);
9634         
9635         pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
9636
9637         /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
9638         mono_mb_emit_ptr (mb, &klass->byval_arg);
9639         mono_mb_emit_icall (mb, type_from_handle);
9640         mono_mb_emit_ldarg (mb, 0);
9641         
9642         mono_mb_emit_icall (mb, mono_upgrade_remote_class_wrapper);
9643         emit_thread_interrupt_checkpoint (mb);
9644         
9645         mono_mb_emit_ldarg (mb, 0);
9646         pos_end = mono_mb_emit_branch (mb, CEE_BR);
9647         
9648         /* fail */
9649         
9650         mono_mb_patch_branch (mb, pos_failed);
9651         mono_mb_emit_byte (mb, CEE_LDNULL);
9652         
9653         /* the end */
9654         
9655         mono_mb_patch_branch (mb, pos_end);
9656         mono_mb_emit_byte (mb, CEE_RET);
9657
9658         res = mono_mb_create_and_cache (cache, klass, mb, isint_sig, isint_sig->param_count + 16);
9659         mono_mb_free (mb);
9660
9661         return res;
9662 }
9663
9664 void
9665 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
9666 {
9667         MonoClass *klass;
9668         MonoDomain *domain = ((MonoObject*)tproxy)->vtable->domain;
9669         klass = mono_class_from_mono_type (rtype->type);
9670         mono_upgrade_remote_class (domain, (MonoObject*)tproxy, klass);
9671 }
9672
9673 /**
9674  * mono_marshal_get_struct_to_ptr:
9675  * @klass:
9676  *
9677  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
9678  */
9679 MonoMethod *
9680 mono_marshal_get_struct_to_ptr (MonoClass *klass)
9681 {
9682         MonoMethodBuilder *mb;
9683         static MonoMethod *stoptr = NULL;
9684         MonoMethod *res;
9685
9686         g_assert (klass != NULL);
9687
9688         mono_marshal_load_type_info (klass);
9689
9690         if (klass->marshal_info->str_to_ptr)
9691                 return klass->marshal_info->str_to_ptr;
9692
9693         if (!stoptr) 
9694                 stoptr = mono_class_get_method_from_name (mono_defaults.marshal_class, "StructureToPtr", 3);
9695         g_assert (stoptr);
9696
9697         mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
9698
9699         if (klass->blittable) {
9700                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9701                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9702                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9703                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9704                 mono_mb_emit_byte (mb, CEE_PREFIX1);
9705                 mono_mb_emit_byte (mb, CEE_CPBLK);
9706         } else {
9707
9708                 /* allocate local 0 (pointer) src_ptr */
9709                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9710                 /* allocate local 1 (pointer) dst_ptr */
9711                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9712                 /* allocate local 2 (boolean) delete_old */
9713                 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
9714                 mono_mb_emit_byte (mb, CEE_LDARG_2);
9715                 mono_mb_emit_stloc (mb, 2);
9716
9717                 /* initialize src_ptr to point to the start of object data */
9718                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9719                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9720                 mono_mb_emit_stloc (mb, 0);
9721
9722                 /* initialize dst_ptr */
9723                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9724                 mono_mb_emit_stloc (mb, 1);
9725
9726                 emit_struct_conv (mb, klass, FALSE);
9727         }
9728
9729         mono_mb_emit_byte (mb, CEE_RET);
9730
9731         res = mono_mb_create_method (mb, mono_signature_no_pinvoke (stoptr), 0);
9732         mono_mb_free (mb);
9733
9734         klass->marshal_info->str_to_ptr = res;
9735         return res;
9736 }
9737
9738 /**
9739  * mono_marshal_get_ptr_to_struct:
9740  * @klass:
9741  *
9742  * generates IL code for PtrToStructure (IntPtr src, object structure)
9743  */
9744 MonoMethod *
9745 mono_marshal_get_ptr_to_struct (MonoClass *klass)
9746 {
9747         MonoMethodBuilder *mb;
9748         static MonoMethodSignature *ptostr = NULL;
9749         MonoMethod *res;
9750
9751         g_assert (klass != NULL);
9752
9753         mono_marshal_load_type_info (klass);
9754
9755         if (klass->marshal_info->ptr_to_str)
9756                 return klass->marshal_info->ptr_to_str;
9757
9758         if (!ptostr) {
9759                 MonoMethodSignature *sig;
9760
9761                 /* Create the signature corresponding to
9762                           static void PtrToStructure (IntPtr ptr, object structure);
9763                    defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9764                 sig = mono_create_icall_signature ("void ptr object");
9765                 sig = signature_dup (mono_defaults.corlib, sig);
9766                 sig->pinvoke = 0;
9767                 mono_memory_barrier ();
9768                 ptostr = sig;
9769         }
9770
9771         mb = mono_mb_new (klass, "PtrToStructure", MONO_WRAPPER_UNKNOWN);
9772
9773         if (klass->blittable) {
9774                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9775                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9776                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9777                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9778                 mono_mb_emit_byte (mb, CEE_PREFIX1);
9779                 mono_mb_emit_byte (mb, CEE_CPBLK);
9780         } else {
9781
9782                 /* allocate local 0 (pointer) src_ptr */
9783                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9784                 /* allocate local 1 (pointer) dst_ptr */
9785                 mono_mb_add_local (mb, &klass->this_arg);
9786                 
9787                 /* initialize src_ptr to point to the start of object data */
9788                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9789                 mono_mb_emit_stloc (mb, 0);
9790
9791                 /* initialize dst_ptr */
9792                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9793                 mono_mb_emit_op (mb, CEE_UNBOX, klass);
9794                 mono_mb_emit_stloc (mb, 1);
9795
9796                 emit_struct_conv (mb, klass, TRUE);
9797         }
9798
9799         mono_mb_emit_byte (mb, CEE_RET);
9800
9801         res = mono_mb_create_method (mb, ptostr, 0);
9802         mono_mb_free (mb);
9803
9804         klass->marshal_info->ptr_to_str = res;
9805         return res;
9806 }
9807
9808 /*
9809  * generates IL code for the synchronized wrapper: the generated method
9810  * calls METHOD while locking 'this' or the parent type.
9811  */
9812 MonoMethod *
9813 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
9814 {
9815         static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method;
9816         MonoMethodSignature *sig;
9817         MonoExceptionClause *clause;
9818         MonoMethodBuilder *mb;
9819         MonoMethod *res;
9820         GHashTable *cache;
9821         int i, pos, this_local, ret_local = 0;
9822
9823         g_assert (method);
9824
9825         if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
9826                 return method;
9827
9828         cache = get_cache (&method->klass->image->synchronized_cache, mono_aligned_addr_hash, NULL);
9829         if ((res = mono_marshal_find_in_cache (cache, method)))
9830                 return res;
9831
9832         sig = signature_dup (method->klass->image, mono_method_signature (method));
9833         sig->pinvoke = 0;
9834
9835         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
9836
9837         /* result */
9838         if (!MONO_TYPE_IS_VOID (sig->ret))
9839                 ret_local = mono_mb_add_local (mb, sig->ret);
9840
9841         if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
9842                 mono_class_set_failure (method->klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
9843                 /* This will throw the type load exception when the wrapper is compiled */
9844                 mono_mb_emit_byte (mb, CEE_LDNULL);
9845                 mono_mb_emit_op (mb, CEE_ISINST, method->klass);
9846                 mono_mb_emit_byte (mb, CEE_POP);
9847
9848                 if (!MONO_TYPE_IS_VOID (sig->ret))
9849                         mono_mb_emit_ldloc (mb, ret_local);
9850                 mono_mb_emit_byte (mb, CEE_RET);
9851
9852                 res = mono_mb_create_and_cache (cache, method,
9853                                                                                 mb, sig, sig->param_count + 16);
9854                 mono_mb_free (mb);
9855
9856                 return res;
9857         }
9858
9859         /* this */
9860         this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
9861
9862         mono_loader_lock ();
9863         clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
9864         mono_loader_unlock ();
9865         clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
9866
9867         mono_loader_lock ();
9868
9869         if (!enter_method) {
9870                 MonoMethodDesc *desc;
9871
9872                 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
9873                 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9874                 g_assert (enter_method);
9875                 mono_method_desc_free (desc);
9876
9877                 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
9878                 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9879                 g_assert (exit_method);
9880                 mono_method_desc_free (desc);
9881
9882                 desc = mono_method_desc_new ("Type:GetTypeFromHandle", FALSE);
9883                 gettypefromhandle_method = mono_method_desc_search_in_class (desc, mono_defaults.monotype_class->parent);
9884                 g_assert (gettypefromhandle_method);
9885                 mono_method_desc_free (desc);
9886         }
9887
9888         mono_loader_unlock ();
9889
9890         /* Push this or the type object */
9891         if (method->flags & METHOD_ATTRIBUTE_STATIC) {
9892                 /* We have special handling for this in the JIT */
9893                 int index = mono_mb_add_data (mb, method->klass);
9894                 mono_mb_add_data (mb, mono_defaults.typehandle_class);
9895                 mono_mb_emit_byte (mb, CEE_LDTOKEN);
9896                 mono_mb_emit_i4 (mb, index);
9897
9898                 mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL);
9899         }
9900         else
9901                 mono_mb_emit_ldarg (mb, 0);
9902         mono_mb_emit_stloc (mb, this_local);
9903
9904         /* Call Monitor::Enter() */
9905         mono_mb_emit_ldloc (mb, this_local);
9906         mono_mb_emit_managed_call (mb, enter_method, NULL);
9907
9908         clause->try_offset = mono_mb_get_label (mb);
9909
9910         /* Call the method */
9911         if (sig->hasthis)
9912                 mono_mb_emit_ldarg (mb, 0);
9913         for (i = 0; i < sig->param_count; i++)
9914                 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
9915
9916         mono_mb_emit_managed_call (mb, method, NULL);
9917
9918         if (!MONO_TYPE_IS_VOID (sig->ret))
9919                 mono_mb_emit_stloc (mb, ret_local);
9920
9921         pos = mono_mb_emit_branch (mb, CEE_LEAVE);
9922
9923         clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
9924         clause->handler_offset = mono_mb_get_label (mb);
9925
9926         /* Call Monitor::Exit() */
9927         mono_mb_emit_ldloc (mb, this_local);
9928         mono_mb_emit_managed_call (mb, exit_method, NULL);
9929         mono_mb_emit_byte (mb, CEE_ENDFINALLY);
9930
9931         clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
9932
9933         mono_mb_patch_branch (mb, pos);
9934         if (!MONO_TYPE_IS_VOID (sig->ret))
9935                 mono_mb_emit_ldloc (mb, ret_local);
9936         mono_mb_emit_byte (mb, CEE_RET);
9937
9938         mono_mb_set_clauses (mb, 1, clause);
9939
9940         res = mono_mb_create_and_cache (cache, method,
9941                                                                         mb, sig, sig->param_count + 16);
9942         mono_mb_free (mb);
9943
9944         return res;     
9945 }
9946
9947
9948 /*
9949  * the returned method calls 'method' unboxing the this argument
9950  */
9951 MonoMethod *
9952 mono_marshal_get_unbox_wrapper (MonoMethod *method)
9953 {
9954         MonoMethodSignature *sig = mono_method_signature (method);
9955         int i;
9956         MonoMethodBuilder *mb;
9957         MonoMethod *res;
9958         GHashTable *cache;
9959
9960         cache = get_cache (&method->klass->image->unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
9961         if ((res = mono_marshal_find_in_cache (cache, method)))
9962                 return res;
9963
9964         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNBOX);
9965
9966         g_assert (sig->hasthis);
9967         
9968         mono_mb_emit_ldarg (mb, 0); 
9969         mono_mb_emit_icon (mb, sizeof (MonoObject));
9970         mono_mb_emit_byte (mb, CEE_ADD);
9971         for (i = 0; i < sig->param_count; ++i)
9972                 mono_mb_emit_ldarg (mb, i + 1);
9973         mono_mb_emit_managed_call (mb, method, NULL);
9974         mono_mb_emit_byte (mb, CEE_RET);
9975
9976         res = mono_mb_create_and_cache (cache, method,
9977                                                                                  mb, sig, sig->param_count + 16);
9978         mono_mb_free (mb);
9979
9980         /* 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)); */
9981
9982         return res;     
9983 }
9984
9985 MonoMethod*
9986 mono_marshal_get_stelemref ()
9987 {
9988         static MonoMethod* ret = NULL;
9989         MonoMethodSignature *sig;
9990         MonoMethodBuilder *mb;
9991         
9992         guint32 b1, b2, b3, b4;
9993         guint32 copy_pos;
9994         int aklass, vklass;
9995         int array_slot_addr;
9996         
9997         if (ret)
9998                 return ret;
9999         
10000         mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
10001         
10002
10003         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
10004
10005         /* void stelemref (void* array, int idx, void* value) */
10006         sig->ret = &mono_defaults.void_class->byval_arg;
10007         sig->params [0] = &mono_defaults.object_class->byval_arg;
10008         sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
10009         sig->params [2] = &mono_defaults.object_class->byval_arg;
10010                 
10011         aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10012         vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10013         array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10014         
10015         /*
10016         the method:
10017         <ldelema (bound check)>
10018         if (!value)
10019                 goto store;
10020         
10021         aklass = array->vtable->klass->element_class;
10022         vklass = value->vtable->klass;
10023         
10024         if (vklass->idepth < aklass->idepth)
10025                 goto long;
10026         
10027         if (vklass->supertypes [aklass->idepth - 1] != aklass)
10028                 goto long;
10029         
10030         store:
10031                 *array_slot_addr = value;
10032                 return;
10033         
10034         long:
10035                 if (mono_object_isinst (value, aklass))
10036                         goto store;
10037                 
10038                 throw new ArrayTypeMismatchException ();
10039         */
10040         
10041         /* ldelema (implicit bound check) */
10042         mono_mb_emit_ldarg (mb, 0);
10043         mono_mb_emit_ldarg (mb, 1);
10044         mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
10045         mono_mb_emit_stloc (mb, array_slot_addr);
10046                 
10047         /* if (!value) goto do_store */
10048         mono_mb_emit_ldarg (mb, 2);
10049         b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10050         
10051         /* aklass = array->vtable->klass->element_class */
10052         mono_mb_emit_ldarg (mb, 0);
10053         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
10054         mono_mb_emit_byte (mb, CEE_LDIND_I);
10055         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
10056         mono_mb_emit_byte (mb, CEE_LDIND_I);
10057         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
10058         mono_mb_emit_byte (mb, CEE_LDIND_I);
10059         mono_mb_emit_stloc (mb, aklass);
10060         
10061         /* vklass = value->vtable->klass */
10062         mono_mb_emit_ldarg (mb, 2);
10063         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
10064         mono_mb_emit_byte (mb, CEE_LDIND_I);
10065         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
10066         mono_mb_emit_byte (mb, CEE_LDIND_I);
10067         mono_mb_emit_stloc (mb, vklass);
10068         
10069         /* if (vklass->idepth < aklass->idepth) goto failue */
10070         mono_mb_emit_ldloc (mb, vklass);
10071         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10072         mono_mb_emit_byte (mb, CEE_LDIND_U2);
10073         
10074         mono_mb_emit_ldloc (mb, aklass);
10075         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10076         mono_mb_emit_byte (mb, CEE_LDIND_U2);
10077         
10078         b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
10079         
10080         /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10081         mono_mb_emit_ldloc (mb, vklass);
10082         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
10083         mono_mb_emit_byte (mb, CEE_LDIND_I);
10084         
10085         mono_mb_emit_ldloc (mb, aklass);
10086         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
10087         mono_mb_emit_byte (mb, CEE_LDIND_U2);
10088         mono_mb_emit_icon (mb, 1);
10089         mono_mb_emit_byte (mb, CEE_SUB);
10090         mono_mb_emit_icon (mb, sizeof (void*));
10091         mono_mb_emit_byte (mb, CEE_MUL);
10092         mono_mb_emit_byte (mb, CEE_ADD);
10093         mono_mb_emit_byte (mb, CEE_LDIND_I);
10094         
10095         mono_mb_emit_ldloc (mb, aklass);
10096         
10097         b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10098         
10099         copy_pos = mono_mb_get_label (mb);
10100         /* do_store */
10101         mono_mb_patch_branch (mb, b1);
10102         mono_mb_emit_ldloc (mb, array_slot_addr);
10103         mono_mb_emit_ldarg (mb, 2);
10104         mono_mb_emit_byte (mb, CEE_STIND_REF);
10105         
10106         mono_mb_emit_byte (mb, CEE_RET);
10107         
10108         /* the hard way */
10109         mono_mb_patch_branch (mb, b2);
10110         mono_mb_patch_branch (mb, b3);
10111         
10112         mono_mb_emit_ldarg (mb, 2);
10113         mono_mb_emit_ldloc (mb, aklass);
10114         mono_mb_emit_icall (mb, mono_object_isinst);
10115         
10116         b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
10117         mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
10118         mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10119         
10120         mono_mb_emit_byte (mb, CEE_RET);
10121         ret = mono_mb_create_method (mb, sig, 4);
10122         mono_mb_free (mb);
10123         return ret;
10124 }
10125
10126 typedef struct {
10127         int rank;
10128         int elem_size;
10129         MonoMethod *method;
10130 } ArrayElemAddr;
10131
10132 /* LOCKING: vars accessed under the marshal lock */
10133 static ArrayElemAddr *elem_addr_cache = NULL;
10134 static int elem_addr_cache_size = 0;
10135 static int elem_addr_cache_next = 0;
10136
10137 /**
10138  * mono_marshal_get_array_address:
10139  * @rank: rank of the array type
10140  * @elem_size: size in bytes of an element of an array.
10141  *
10142  * Returns a MonoMethd that implements the code to get the address
10143  * of an element in a multi-dimenasional array of @rank dimensions.
10144  * The returned method takes an array as the first argument and then
10145  * @rank indexes for the @rank dimensions.
10146  */
10147 MonoMethod*
10148 mono_marshal_get_array_address (int rank, int elem_size)
10149 {
10150         MonoMethod *ret;
10151         MonoMethodBuilder *mb;
10152         MonoMethodSignature *sig;
10153         int i, bounds, ind, realidx;
10154         int branch_pos, *branch_positions;
10155         int cached;
10156
10157         ret = NULL;
10158         mono_marshal_lock ();
10159         for (i = 0; i < elem_addr_cache_next; ++i) {
10160                 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
10161                         ret = elem_addr_cache [i].method;
10162                         break;
10163                 }
10164         }
10165         mono_marshal_unlock ();
10166         if (ret)
10167                 return ret;
10168
10169         branch_positions = g_new0 (int, rank);
10170
10171         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank);
10172
10173         /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
10174         sig->ret = &mono_defaults.int_class->byval_arg;
10175         sig->params [0] = &mono_defaults.object_class->byval_arg;
10176         for (i = 0; i < rank; ++i) {
10177                 sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
10178         }
10179
10180         mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED);
10181         
10182         bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10183         ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10184         realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10185
10186         /* bounds = array->bounds; */
10187         mono_mb_emit_ldarg (mb, 0);
10188         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, bounds));
10189         mono_mb_emit_byte (mb, CEE_LDIND_I);
10190         mono_mb_emit_stloc (mb, bounds);
10191
10192         /* ind is the overall element index, realidx is the partial index in a single dimension */
10193         /* ind = idx0 - bounds [0].lower_bound */
10194         mono_mb_emit_ldarg (mb, 1);
10195         mono_mb_emit_ldloc (mb, bounds);
10196         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
10197         mono_mb_emit_byte (mb, CEE_ADD);
10198         mono_mb_emit_byte (mb, CEE_LDIND_I4);
10199         mono_mb_emit_byte (mb, CEE_SUB);
10200         mono_mb_emit_stloc (mb, ind);
10201         /* if (ind >= bounds [0].length) goto exeception; */
10202         mono_mb_emit_ldloc (mb, ind);
10203         mono_mb_emit_ldloc (mb, bounds);
10204         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, length));
10205         mono_mb_emit_byte (mb, CEE_ADD);
10206         mono_mb_emit_byte (mb, CEE_LDIND_I4);
10207         /* note that we use unsigned comparison */
10208         branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
10209
10210         /* For large ranks (> 4?) use a loop n IL later to reduce code size.
10211          * We could also decide to ignore the passed elem_size and get it
10212          * from the array object, to reduce the number of methods we generate:
10213          * the additional cost is 3 memory loads and a non-immediate mul.
10214          */
10215         for (i = 1; i < rank; ++i) {
10216                 /* realidx = idxi - bounds [i].lower_bound */
10217                 mono_mb_emit_ldarg (mb, 1 + i);
10218                 mono_mb_emit_ldloc (mb, bounds);
10219                 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
10220                 mono_mb_emit_byte (mb, CEE_ADD);
10221                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10222                 mono_mb_emit_byte (mb, CEE_SUB);
10223                 mono_mb_emit_stloc (mb, realidx);
10224                 /* if (realidx >= bounds [i].length) goto exeception; */
10225                 mono_mb_emit_ldloc (mb, realidx);
10226                 mono_mb_emit_ldloc (mb, bounds);
10227                 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
10228                 mono_mb_emit_byte (mb, CEE_ADD);
10229                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10230                 branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
10231                 /* ind = ind * bounds [i].length + realidx */
10232                 mono_mb_emit_ldloc (mb, ind);
10233                 mono_mb_emit_ldloc (mb, bounds);
10234                 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
10235                 mono_mb_emit_byte (mb, CEE_ADD);
10236                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10237                 mono_mb_emit_byte (mb, CEE_MUL);
10238                 mono_mb_emit_ldloc (mb, realidx);
10239                 mono_mb_emit_byte (mb, CEE_ADD);
10240                 mono_mb_emit_stloc (mb, ind);
10241         }
10242
10243         /* return array->vector + ind * element_size */
10244         mono_mb_emit_ldarg (mb, 0);
10245         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
10246         mono_mb_emit_ldloc (mb, ind);
10247         mono_mb_emit_icon (mb, elem_size);
10248         mono_mb_emit_byte (mb, CEE_MUL);
10249         mono_mb_emit_byte (mb, CEE_ADD);
10250         mono_mb_emit_byte (mb, CEE_RET);
10251
10252         /* patch the branches to get here and throw */
10253         for (i = 1; i < rank; ++i) {
10254                 mono_mb_patch_branch (mb, branch_positions [i]);
10255         }
10256         mono_mb_patch_branch (mb, branch_pos);
10257         /* throw exception */
10258         mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
10259
10260         g_free (branch_positions);
10261         ret = mono_mb_create_method (mb, sig, 4);
10262         mono_mb_free (mb);
10263
10264         /* cache the result */
10265         cached = 0;
10266         mono_marshal_lock ();
10267         for (i = 0; i < elem_addr_cache_next; ++i) {
10268                 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
10269                         /* FIXME: free ret */
10270                         ret = elem_addr_cache [i].method;
10271                         cached = TRUE;
10272                         break;
10273                 }
10274         }
10275         if (!cached) {
10276                 if (elem_addr_cache_next >= elem_addr_cache_size) {
10277                         int new_size = elem_addr_cache_size + 4;
10278                         ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size);
10279                         memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr));
10280                         g_free (elem_addr_cache);
10281                         elem_addr_cache = new_array;
10282                         elem_addr_cache_size = new_size;
10283                 }
10284                 elem_addr_cache [elem_addr_cache_next].rank = rank;
10285                 elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
10286                 elem_addr_cache [elem_addr_cache_next].method = ret;
10287         }
10288         mono_marshal_unlock ();
10289         return ret;
10290 }
10291
10292 void*
10293 mono_marshal_alloc (gulong size)
10294 {
10295         gpointer res;
10296
10297 #ifdef PLATFORM_WIN32
10298         res = CoTaskMemAlloc (size);
10299 #else
10300         res = g_try_malloc ((gulong)size);
10301         if (!res)
10302                 mono_gc_out_of_memory ((gulong)size);
10303 #endif
10304         return res;
10305 }
10306
10307 void
10308 mono_marshal_free (gpointer ptr)
10309 {
10310 #ifdef PLATFORM_WIN32
10311         CoTaskMemFree (ptr);
10312 #else
10313         g_free (ptr);
10314 #endif
10315 }
10316
10317 void
10318 mono_marshal_free_array (gpointer *ptr, int size) 
10319 {
10320         int i;
10321
10322         if (!ptr)
10323                 return;
10324
10325         for (i = 0; i < size; i++)
10326                 if (ptr [i])
10327                         g_free (ptr [i]);
10328 }
10329
10330 void *
10331 mono_marshal_string_to_utf16 (MonoString *s)
10332 {
10333         return s ? mono_string_chars (s) : NULL;
10334 }
10335
10336 static void *
10337 mono_marshal_string_to_utf16_copy (MonoString *s)
10338 {
10339         if (s == NULL) {
10340                 return NULL;
10341         } else {
10342                 gunichar2 *res = mono_marshal_alloc ((mono_string_length (s) * 2) + 2);
10343                 memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
10344                 res [mono_string_length (s)] = 0;
10345                 return res;
10346         }
10347 }
10348
10349 /**
10350  * mono_marshal_set_last_error:
10351  *
10352  * This function is invoked to set the last error value from a P/Invoke call
10353  * which has SetLastError set.
10354  */
10355 void
10356 mono_marshal_set_last_error (void)
10357 {
10358 #ifdef WIN32
10359         TlsSetValue (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
10360 #else
10361         TlsSetValue (last_error_tls_id, GINT_TO_POINTER (errno));
10362 #endif
10363 }
10364
10365 static void
10366 mono_marshal_set_last_error_windows (int error)
10367 {
10368 #ifdef WIN32
10369         TlsSetValue (last_error_tls_id, GINT_TO_POINTER (error));
10370 #endif
10371 }
10372
10373 void
10374 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
10375                                                                     gpointer dest, gint32 length)
10376 {
10377         int element_size;
10378         void *source_addr;
10379
10380         MONO_ARCH_SAVE_REGS;
10381
10382         MONO_CHECK_ARG_NULL (src);
10383         MONO_CHECK_ARG_NULL (dest);
10384
10385         if (src->obj.vtable->klass->rank != 1)
10386                 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10387         if (start_index < 0)
10388                 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10389         if (length < 0)
10390                 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10391         if (start_index + length > mono_array_length (src))
10392                 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10393
10394         element_size = mono_array_element_size (src->obj.vtable->klass);
10395
10396         /* no references should be involved */
10397         source_addr = mono_array_addr_with_size (src, element_size, start_index);
10398
10399         memcpy (dest, source_addr, length * element_size);
10400 }
10401
10402 void
10403 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
10404                                                                       MonoArray *dest, gint32 length)
10405 {
10406         int element_size;
10407         void *dest_addr;
10408
10409         MONO_ARCH_SAVE_REGS;
10410
10411         MONO_CHECK_ARG_NULL (src);
10412         MONO_CHECK_ARG_NULL (dest);
10413
10414         if (dest->obj.vtable->klass->rank != 1)
10415                 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10416         if (start_index < 0)
10417                 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10418         if (length < 0)
10419                 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10420         if (start_index + length > mono_array_length (dest))
10421                 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10422
10423         element_size = mono_array_element_size (dest->obj.vtable->klass);
10424           
10425         /* no references should be involved */
10426         dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
10427
10428         memcpy (dest_addr, src, length * element_size);
10429 }
10430
10431 #if NO_UNALIGNED_ACCESS
10432 #define RETURN_UNALIGNED(type, addr) \
10433         { \
10434                 type val; \
10435                 memcpy(&val, p + offset, sizeof(val)); \
10436                 return val; \
10437         }
10438 #define WRITE_UNALIGNED(type, addr, val) \
10439         memcpy(addr, &val, sizeof(type))
10440 #else
10441 #define RETURN_UNALIGNED(type, addr) \
10442         return *(type*)(p + offset);
10443 #define WRITE_UNALIGNED(type, addr, val) \
10444         (*(type *)(addr) = (val))
10445 #endif
10446
10447 gpointer
10448 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
10449 {
10450         char *p = ptr;
10451
10452         MONO_ARCH_SAVE_REGS;
10453
10454         RETURN_UNALIGNED(gpointer, p + offset);
10455 }
10456
10457 unsigned char
10458 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
10459 {
10460         char *p = ptr;
10461
10462         MONO_ARCH_SAVE_REGS;
10463
10464         return *(unsigned char*)(p + offset);
10465 }
10466
10467 gint16
10468 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
10469 {
10470         char *p = ptr;
10471
10472         MONO_ARCH_SAVE_REGS;
10473
10474         RETURN_UNALIGNED(gint16, p + offset);
10475 }
10476
10477 gint32
10478 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
10479 {
10480         char *p = ptr;
10481
10482         MONO_ARCH_SAVE_REGS;
10483
10484         RETURN_UNALIGNED(gint32, p + offset);
10485 }
10486
10487 gint64
10488 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
10489 {
10490         char *p = ptr;
10491
10492         MONO_ARCH_SAVE_REGS;
10493
10494         RETURN_UNALIGNED(gint64, p + offset);
10495 }
10496
10497 void
10498 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
10499 {
10500         char *p = ptr;
10501
10502         MONO_ARCH_SAVE_REGS;
10503
10504         *(unsigned char*)(p + offset) = val;
10505 }
10506
10507 void
10508 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
10509 {
10510         char *p = ptr;
10511
10512         MONO_ARCH_SAVE_REGS;
10513
10514         WRITE_UNALIGNED(gpointer, p + offset, val);
10515 }
10516
10517 void
10518 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
10519 {
10520         char *p = ptr;
10521
10522         MONO_ARCH_SAVE_REGS;
10523
10524         WRITE_UNALIGNED(gint16, p + offset, val);
10525 }
10526
10527 void
10528 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
10529 {
10530         char *p = ptr;
10531
10532         MONO_ARCH_SAVE_REGS;
10533
10534         WRITE_UNALIGNED(gint32, p + offset, val);
10535 }
10536
10537 void
10538 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
10539 {
10540         char *p = ptr;
10541
10542         MONO_ARCH_SAVE_REGS;
10543
10544         WRITE_UNALIGNED(gint64, p + offset, val);
10545 }
10546
10547 MonoString *
10548 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
10549 {
10550         MONO_ARCH_SAVE_REGS;
10551
10552         if (ptr == NULL)
10553                 return NULL;
10554         else
10555                 return mono_string_new (mono_domain_get (), ptr);
10556 }
10557
10558 MonoString *
10559 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
10560 {
10561         MONO_ARCH_SAVE_REGS;
10562
10563         if (ptr == NULL) {
10564                 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10565                 g_assert_not_reached ();
10566                 return NULL;
10567         } else {
10568                 return mono_string_new_len (mono_domain_get (), ptr, len);
10569         }
10570 }
10571
10572 MonoString *
10573 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
10574 {
10575         MonoDomain *domain = mono_domain_get (); 
10576         int len = 0;
10577         guint16 *t = ptr;
10578
10579         MONO_ARCH_SAVE_REGS;
10580
10581         if (ptr == NULL)
10582                 return NULL;
10583
10584         while (*t++)
10585                 len++;
10586
10587         return mono_string_new_utf16 (domain, ptr, len);
10588 }
10589
10590 MonoString *
10591 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
10592 {
10593         MonoDomain *domain = mono_domain_get (); 
10594
10595         MONO_ARCH_SAVE_REGS;
10596
10597         if (ptr == NULL) {
10598                 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10599                 g_assert_not_reached ();
10600                 return NULL;
10601         } else {
10602                 return mono_string_new_utf16 (domain, ptr, len);
10603         }
10604 }
10605
10606 MonoString *
10607 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
10608 {
10609         MONO_ARCH_SAVE_REGS;
10610
10611         return mono_string_from_bstr(ptr);
10612 }
10613
10614 gpointer
10615 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
10616 {
10617         MONO_ARCH_SAVE_REGS;
10618
10619         return mono_string_to_bstr(ptr);
10620 }
10621
10622 typedef struct
10623 {
10624         int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
10625         int (STDCALL *AddRef)(gpointer pUnk);
10626         int (STDCALL *Release)(gpointer pUnk);
10627 } MonoIUnknown;
10628
10629 void
10630 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
10631 {
10632         MONO_ARCH_SAVE_REGS;
10633
10634         mono_free_bstr (ptr);
10635 }
10636
10637 int
10638 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
10639 {
10640         g_assert (pUnk);
10641         return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
10642 }
10643
10644 int
10645 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
10646 {
10647         g_assert (pUnk);
10648         return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
10649 }
10650
10651 int
10652 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
10653 {
10654         g_assert (pUnk);
10655         return (*(MonoIUnknown**)pUnk)->Release(pUnk);
10656 }
10657
10658 #ifndef DISABLE_COM
10659
10660 #define MONO_S_OK 0x00000000L
10661 #define MONO_E_NOINTERFACE 0x80004002L
10662 #define MONO_E_NOTIMPL 0x80004001L
10663
10664 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
10665 {
10666         if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
10667                 return FALSE;
10668
10669         if (!cominterop_com_visible (klass))
10670                 return FALSE;
10671
10672         return TRUE;
10673 }
10674
10675 static void*
10676 cominterop_get_idispatch_for_object (MonoObject* object)
10677 {
10678         if (!object)
10679                 return NULL;
10680
10681         if (cominterop_object_is_rcw (object)) {
10682                 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object, 
10683                         mono_defaults.idispatch_class, TRUE);
10684         }
10685         else {
10686                 MonoClass* klass = mono_object_class (object);
10687                 if (!cominterop_can_support_dispatch (klass) )
10688                         cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
10689                 return cominterop_get_ccw (object, mono_defaults.idispatch_class);
10690         }
10691 }
10692
10693 #endif
10694
10695 void*
10696 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
10697 {
10698 #ifndef DISABLE_COM
10699         if (!object)
10700                 return NULL;
10701
10702         mono_init_com_types ();
10703
10704         if (cominterop_object_is_rcw (object)) {
10705                 MonoClass *klass = NULL;
10706                 MonoRealProxy* real_proxy = NULL;
10707                 if (!object)
10708                         return NULL;
10709                 klass = mono_object_class (object);
10710                 if (klass != mono_defaults.transparent_proxy_class) {
10711                         g_assert_not_reached ();
10712                         return NULL;
10713                 }
10714
10715                 real_proxy = ((MonoTransparentProxy*)object)->rp;
10716                 if (!real_proxy) {
10717                         g_assert_not_reached ();
10718                         return NULL;
10719                 }
10720
10721                 klass = mono_object_class (real_proxy);
10722                 if (klass != mono_defaults.com_interop_proxy_class) {
10723                         g_assert_not_reached ();
10724                         return NULL;
10725                 }
10726
10727                 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
10728                         g_assert_not_reached ();
10729                         return NULL;
10730                 }
10731
10732                 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
10733         }
10734         else {
10735                 return cominterop_get_ccw (object, mono_defaults.iunknown_class);
10736         }
10737 #else
10738         g_assert_not_reached ();
10739 #endif
10740 }
10741
10742 MonoObject*
10743 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
10744 {
10745 #ifndef DISABLE_COM
10746         MonoObject* object = NULL;
10747
10748         if (!pUnk)
10749                 return NULL;
10750
10751         /* see if it is a CCW */
10752         object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
10753
10754         return object;
10755 #else
10756         g_assert_not_reached ();
10757 #endif
10758 }
10759
10760 void*
10761 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
10762 {
10763 #ifndef DISABLE_COM
10764         mono_init_com_types ();
10765
10766         return cominterop_get_idispatch_for_object (object);
10767 #else
10768         g_assert_not_reached ();
10769 #endif
10770 }
10771
10772 void*
10773 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
10774 {
10775 #ifndef DISABLE_COM
10776         MonoClass* klass = NULL;
10777         void* itf = NULL;
10778         g_assert (type);
10779         g_assert (type->type);
10780         klass = mono_type_get_class (type->type);
10781         g_assert (klass);
10782         itf = cominterop_get_ccw (object, klass);
10783         g_assert (itf);
10784         return itf;
10785 #else
10786         g_assert_not_reached ();
10787 #endif
10788 }
10789
10790
10791 MonoBoolean
10792 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
10793 {
10794 #ifndef DISABLE_COM
10795         return (MonoBoolean)cominterop_object_is_rcw (object);
10796 #else
10797         g_assert_not_reached ();
10798 #endif
10799 }
10800
10801 gint32
10802 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
10803 {
10804 #ifndef DISABLE_COM
10805         MonoComInteropProxy* proxy = NULL;
10806         gint32 ref_count = 0;
10807
10808         g_assert (object);
10809         g_assert (cominterop_object_is_rcw (object));
10810
10811         proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
10812         g_assert (proxy);
10813
10814         ref_count = InterlockedDecrement (&proxy->ref_count);
10815         g_assert (ref_count >= 0);
10816
10817         if (ref_count == 0)
10818                 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
10819
10820         return ref_count;
10821 #else
10822         g_assert_not_reached ();
10823 #endif
10824 }
10825
10826 guint32
10827 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
10828 {
10829         MONO_ARCH_SAVE_REGS;
10830
10831 #ifndef DISABLE_COM
10832         return cominterop_get_com_slot_for_method (m->method);
10833 #else
10834         g_assert_not_reached ();
10835 #endif
10836 }
10837
10838 guint32 
10839 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10840 {
10841         MONO_ARCH_SAVE_REGS;
10842
10843         return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id)));
10844 }
10845
10846 guint32 
10847 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
10848 {
10849         MonoClass *klass;
10850         MonoType *type;
10851         guint32 layout;
10852
10853         MONO_ARCH_SAVE_REGS;
10854
10855         MONO_CHECK_ARG_NULL (rtype);
10856
10857         type = rtype->type;
10858         klass = mono_class_from_mono_type (type);
10859         layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
10860
10861         if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
10862                 gchar *msg;
10863                 MonoException *exc;
10864
10865                 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
10866                 exc = mono_get_exception_argument ("t", msg);
10867                 g_free (msg);
10868                 mono_raise_exception (exc);
10869         }
10870
10871
10872         return mono_class_native_size (klass, NULL);
10873 }
10874
10875 void
10876 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
10877 {
10878         MonoMethod *method;
10879         gpointer pa [3];
10880
10881         MONO_ARCH_SAVE_REGS;
10882
10883         MONO_CHECK_ARG_NULL (obj);
10884         MONO_CHECK_ARG_NULL (dst);
10885
10886         method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
10887
10888         pa [0] = obj;
10889         pa [1] = &dst;
10890         pa [2] = &delete_old;
10891
10892         mono_runtime_invoke (method, NULL, pa, NULL);
10893 }
10894
10895 static void
10896 ptr_to_structure (gpointer src, MonoObject *dst)
10897 {
10898         MonoMethod *method;
10899         gpointer pa [2];
10900
10901         method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
10902
10903         pa [0] = &src;
10904         pa [1] = dst;
10905
10906         mono_runtime_invoke (method, NULL, pa, NULL);
10907 }
10908
10909 void
10910 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
10911 {
10912         MonoType *t;
10913
10914         MONO_ARCH_SAVE_REGS;
10915
10916         MONO_CHECK_ARG_NULL (src);
10917         MONO_CHECK_ARG_NULL (dst);
10918         
10919         t = mono_type_get_underlying_type (mono_class_get_type (dst->vtable->klass));
10920
10921         if (t->type == MONO_TYPE_VALUETYPE) {
10922                 MonoException *exc;
10923                 gchar *tmp;
10924
10925                 tmp = g_strdup_printf ("Destination is a boxed value type.");
10926                 exc = mono_get_exception_argument ("dst", tmp);
10927                 g_free (tmp);  
10928
10929                 mono_raise_exception (exc);
10930                 return;
10931         }
10932
10933         ptr_to_structure (src, dst);
10934 }
10935
10936 MonoObject *
10937 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
10938 {
10939         MonoDomain *domain = mono_domain_get (); 
10940         MonoObject *res;
10941
10942         MONO_ARCH_SAVE_REGS;
10943
10944         MONO_CHECK_ARG_NULL (src);
10945         MONO_CHECK_ARG_NULL (type);
10946
10947         res = mono_object_new (domain, mono_class_from_mono_type (type->type));
10948
10949         ptr_to_structure (src, res);
10950
10951         return res;
10952 }
10953
10954 int
10955 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
10956 {
10957         MonoMarshalType *info;
10958         MonoClass *klass;
10959         char *fname;
10960         int match_index = -1;
10961         
10962         MONO_ARCH_SAVE_REGS;
10963
10964         MONO_CHECK_ARG_NULL (type);
10965         MONO_CHECK_ARG_NULL (field_name);
10966
10967         fname = mono_string_to_utf8 (field_name);
10968         klass = mono_class_from_mono_type (type->type);
10969
10970         while (klass && match_index == -1) {
10971                 MonoClassField* field;
10972                 int i = 0;
10973                 gpointer iter = NULL;
10974                 while ((field = mono_class_get_fields (klass, &iter))) {
10975                         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
10976                                 continue;
10977                         if (!strcmp (fname, mono_field_get_name (field))) {
10978                                 match_index = i;
10979                                 break;
10980                         }
10981                         i ++;
10982                 }
10983
10984                 if (match_index == -1)
10985                         klass = klass->parent;
10986         }
10987
10988         g_free (fname);
10989
10990         if(match_index == -1) {
10991                 MonoException* exc;
10992                 gchar *tmp;
10993
10994                 /* Get back original class instance */
10995                 klass = mono_class_from_mono_type (type->type);
10996
10997                 tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
10998                 exc = mono_get_exception_argument ("fieldName", tmp);
10999                 g_free (tmp);
11000  
11001                 mono_raise_exception ((MonoException*)exc);
11002         }
11003
11004         info = mono_marshal_load_type_info (klass);     
11005         return info->fields [match_index].offset;
11006 }
11007
11008 gpointer
11009 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
11010 {
11011 #ifdef PLATFORM_WIN32
11012         char* tres, *ret;
11013         size_t len;
11014         tres = mono_string_to_utf8 (string);
11015         if (!tres)
11016                 return tres;
11017
11018         len = strlen (tres) + 1;
11019         ret = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len);
11020         memcpy (ret, tres, len);
11021         g_free (tres);
11022         return ret;
11023
11024 #else
11025         return mono_string_to_utf8 (string);
11026 #endif
11027 }
11028
11029 gpointer
11030 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
11031 {
11032         MONO_ARCH_SAVE_REGS;
11033
11034         if (string == NULL)
11035                 return NULL;
11036         else {
11037 #ifdef PLATFORM_WIN32
11038                 gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal 
11039                         ((mono_string_length (string) + 1) * 2);
11040 #else
11041                 gunichar2 *res = g_malloc ((mono_string_length (string) + 1) * 2);              
11042 #endif
11043                 memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
11044                 res [mono_string_length (string)] = 0;
11045                 return res;
11046         }
11047 }
11048
11049 static void
11050 mono_struct_delete_old (MonoClass *klass, char *ptr)
11051 {
11052         MonoMarshalType *info;
11053         int i;
11054
11055         info = mono_marshal_load_type_info (klass);
11056
11057         for (i = 0; i < info->num_fields; i++) {
11058                 MonoMarshalNative ntype;
11059                 MonoMarshalConv conv;
11060                 MonoType *ftype = info->fields [i].field->type;
11061                 char *cpos;
11062
11063                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
11064                         continue;
11065
11066                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, 
11067                                                 klass->unicode, &conv);
11068                         
11069                 cpos = ptr + info->fields [i].offset;
11070
11071                 switch (conv) {
11072                 case MONO_MARSHAL_CONV_NONE:
11073                         if (MONO_TYPE_ISSTRUCT (ftype)) {
11074                                 mono_struct_delete_old (ftype->data.klass, cpos);
11075                                 continue;
11076                         }
11077                         break;
11078                 case MONO_MARSHAL_CONV_STR_LPWSTR:
11079                         /* We assume this field points inside a MonoString */
11080                         break;
11081                 case MONO_MARSHAL_CONV_STR_LPTSTR:
11082 #ifdef PLATFORM_WIN32
11083                         /* We assume this field points inside a MonoString 
11084                          * on Win32 */
11085                         break;
11086 #endif
11087                 case MONO_MARSHAL_CONV_STR_LPSTR:
11088                 case MONO_MARSHAL_CONV_STR_BSTR:
11089                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
11090                 case MONO_MARSHAL_CONV_STR_TBSTR:
11091                         mono_marshal_free (*(gpointer *)cpos);
11092                         break;
11093
11094                 default:
11095                         continue;
11096                 }
11097         }
11098 }
11099
11100 void
11101 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
11102 {
11103         MonoClass *klass;
11104
11105         MONO_ARCH_SAVE_REGS;
11106
11107         MONO_CHECK_ARG_NULL (src);
11108         MONO_CHECK_ARG_NULL (type);
11109
11110         klass = mono_class_from_mono_type (type->type);
11111
11112         mono_struct_delete_old (klass, (char *)src);
11113 }
11114
11115 void*
11116 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
11117 {
11118         gpointer res;
11119
11120         MONO_ARCH_SAVE_REGS;
11121
11122         if ((gulong)size == 0)
11123                 /* This returns a valid pointer for size 0 on MS.NET */
11124                 size = 4;
11125
11126 #ifdef PLATFORM_WIN32
11127         res = GlobalAlloc (GMEM_FIXED, (gulong)size);
11128 #else
11129         res = g_try_malloc ((gulong)size);
11130 #endif
11131         if (!res)
11132                 mono_gc_out_of_memory ((gulong)size);
11133
11134         return res;
11135 }
11136
11137 gpointer
11138 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, int size)
11139 {
11140         gpointer res;
11141
11142         if (ptr == NULL) {
11143                 mono_gc_out_of_memory ((gulong)size);
11144                 return NULL;
11145         }
11146
11147 #ifdef PLATFORM_WIN32
11148         res = GlobalReAlloc (ptr, (gulong)size, GMEM_MOVEABLE);
11149 #else
11150         res = g_try_realloc (ptr, (gulong)size);
11151 #endif
11152         if (!res)
11153                 mono_gc_out_of_memory ((gulong)size);
11154
11155         return res;
11156 }
11157
11158 void
11159 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
11160 {
11161         MONO_ARCH_SAVE_REGS;
11162
11163 #ifdef PLATFORM_WIN32
11164         GlobalFree (ptr);
11165 #else
11166         g_free (ptr);
11167 #endif
11168 }
11169
11170 void*
11171 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
11172 {
11173         MONO_ARCH_SAVE_REGS;
11174
11175 #ifdef PLATFORM_WIN32
11176         return CoTaskMemAlloc (size);
11177 #else
11178         return g_try_malloc ((gulong)size);
11179 #endif
11180 }
11181
11182 void
11183 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
11184 {
11185         MONO_ARCH_SAVE_REGS;
11186
11187 #ifdef PLATFORM_WIN32
11188         CoTaskMemFree (ptr);
11189 #else
11190         g_free (ptr);
11191 #endif
11192 }
11193
11194 gpointer
11195 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
11196 {
11197         MONO_ARCH_SAVE_REGS;
11198
11199 #ifdef PLATFORM_WIN32
11200         return CoTaskMemRealloc (ptr, size);
11201 #else
11202         return g_try_realloc (ptr, (gulong)size);
11203 #endif
11204 }
11205
11206 void*
11207 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
11208 {
11209         return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
11210 }
11211
11212 MonoDelegate*
11213 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type)
11214 {
11215         return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn);
11216 }
11217
11218 /* Only used for COM RCWs */
11219 MonoObject *
11220 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
11221 {
11222         MonoClass *klass;
11223         MonoDomain *domain;
11224         MonoObject *obj;
11225         
11226         MONO_ARCH_SAVE_REGS;
11227
11228         domain = mono_object_domain (type);
11229         klass = mono_class_from_mono_type (type->type);
11230
11231         /* call mono_object_new_alloc_specific instead of mono_object_new
11232          * because we want to actually create object. mono_object_new checks
11233          * to see if type is import and creates transparent proxy. this method
11234          * is called by the corresponding real proxy to create the real RCW.
11235          * Constructor does not need to be called. Will be called later.
11236         */
11237         obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
11238         return obj;
11239 }
11240
11241 static gboolean    
11242 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
11243 {
11244         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
11245         return TRUE;
11246 }
11247
11248 void
11249 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
11250 {
11251         g_assert(obj);
11252         if (obj->itf_hash) {
11253                 guint32 gchandle = 0;
11254                 mono_cominterop_lock ();
11255                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
11256                 if (gchandle) {
11257                         mono_gchandle_free (gchandle);
11258                         g_hash_table_remove (rcw_hash, obj->iunknown);
11259                 }
11260
11261                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
11262                 g_hash_table_destroy (obj->itf_hash);
11263                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
11264                 obj->itf_hash = obj->iunknown = NULL;
11265                 mono_cominterop_unlock ();
11266         }
11267 }
11268
11269 #ifndef DISABLE_COM
11270
11271 static gboolean    
11272 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
11273 {
11274         guint32 gchandle = 0;
11275
11276         gchandle = GPOINTER_TO_UINT (value);
11277         if (gchandle) {
11278                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
11279                 
11280                 if (proxy) {
11281                         if (proxy->com_object->itf_hash) {
11282                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
11283                                 g_hash_table_destroy (proxy->com_object->itf_hash);
11284                         }
11285                         if (proxy->com_object->iunknown)
11286                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
11287                         proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
11288                 }
11289                 
11290                 mono_gchandle_free (gchandle);
11291         }
11292
11293         return TRUE;
11294 }
11295
11296 void
11297 cominterop_release_all_rcws ()
11298 {
11299         if (!rcw_hash)
11300                 return;
11301
11302         mono_cominterop_lock ();
11303
11304         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
11305         g_hash_table_destroy (rcw_hash);
11306         rcw_hash = NULL;
11307
11308         mono_cominterop_unlock ();
11309 }
11310
11311 #endif
11312
11313 gpointer
11314 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
11315 {
11316 #ifndef DISABLE_COM
11317         return cominterop_get_interface (obj, mono_type_get_class (type->type), (gboolean)throw_exception);
11318 #else
11319         g_assert_not_reached ();
11320 #endif
11321 }
11322
11323 void
11324 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
11325 {
11326 #ifndef DISABLE_COM
11327         guint32 gchandle = 0;
11328         if (!rcw_hash) {
11329                 mono_cominterop_lock ();
11330                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
11331                 mono_cominterop_unlock ();
11332         }
11333
11334         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
11335
11336         mono_cominterop_lock ();
11337         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
11338         mono_cominterop_unlock ();
11339 #else
11340         g_assert_not_reached ();
11341 #endif
11342 }
11343
11344 MonoComInteropProxy*
11345 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
11346 {
11347 #ifndef DISABLE_COM
11348         MonoComInteropProxy* proxy = NULL;
11349         guint32 gchandle = 0;
11350
11351         mono_cominterop_lock ();
11352         if (rcw_hash)
11353                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
11354         mono_cominterop_unlock ();
11355         if (gchandle) {
11356                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
11357                 /* proxy is null means we need to free up old RCW */
11358                 if (!proxy) {
11359                         mono_gchandle_free (gchandle);
11360                         g_hash_table_remove (rcw_hash, pUnk);
11361                 }
11362         }
11363         return proxy;
11364 #else
11365         g_assert_not_reached ();
11366 #endif
11367 }
11368
11369 /**
11370  * mono_marshal_is_loading_type_info:
11371  *
11372  *  Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
11373  * thread.
11374  */
11375 static gboolean
11376 mono_marshal_is_loading_type_info (MonoClass *klass)
11377 {
11378         GSList *loads_list = TlsGetValue (load_type_info_tls_id);
11379
11380         return g_slist_find (loads_list, klass) != NULL;
11381 }
11382
11383 /**
11384  * mono_marshal_load_type_info:
11385  *
11386  *  Initialize klass->marshal_info using information from metadata. This function can
11387  * recursively call itself, and the caller is responsible to avoid that by calling 
11388  * mono_marshal_is_loading_type_info () beforehand.
11389  *
11390  * LOCKING: Acquires the loader lock.
11391  */
11392 MonoMarshalType *
11393 mono_marshal_load_type_info (MonoClass* klass)
11394 {
11395         int j, count = 0;
11396         guint32 native_size = 0, min_align = 1;
11397         MonoMarshalType *info;
11398         MonoClassField* field;
11399         gpointer iter;
11400         guint32 layout;
11401         GSList *loads_list;
11402
11403         g_assert (klass != NULL);
11404
11405         if (klass->marshal_info)
11406                 return klass->marshal_info;
11407
11408         if (!klass->inited)
11409                 mono_class_init (klass);
11410
11411         mono_loader_lock ();
11412
11413         if (klass->marshal_info) {
11414                 mono_loader_unlock ();
11415                 return klass->marshal_info;
11416         }
11417
11418         /*
11419          * This function can recursively call itself, so we keep the list of classes which are
11420          * under initialization in a TLS list.
11421          */
11422         g_assert (!mono_marshal_is_loading_type_info (klass));
11423         loads_list = TlsGetValue (load_type_info_tls_id);
11424         loads_list = g_slist_prepend (loads_list, klass);
11425         TlsSetValue (load_type_info_tls_id, loads_list);
11426         
11427         iter = NULL;
11428         while ((field = mono_class_get_fields (klass, &iter))) {
11429                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11430                         continue;
11431                 if (mono_field_is_deleted (field))
11432                         continue;
11433                 count++;
11434         }
11435
11436         layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
11437
11438         /* The mempool is protected by the loader lock */
11439         info = mono_image_alloc0 (klass->image, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
11440         info->num_fields = count;
11441         
11442         /* Try to find a size for this type in metadata */
11443         mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
11444
11445         if (klass->parent) {
11446                 int parent_size = mono_class_native_size (klass->parent, NULL);
11447
11448                 /* Add parent size to real size */
11449                 native_size += parent_size;
11450                 info->native_size = parent_size;
11451         }
11452
11453         iter = NULL;
11454         j = 0;
11455         while ((field = mono_class_get_fields (klass, &iter))) {
11456                 int size;
11457                 guint32 align;
11458                 
11459                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11460                         continue;
11461
11462                 if (mono_field_is_deleted (field))
11463                         continue;
11464                 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
11465                         mono_metadata_field_info_with_mempool (klass->image->mempool, klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1, 
11466                                                   NULL, NULL, &info->fields [j].mspec);
11467
11468                 info->fields [j].field = field;
11469
11470                 if ((mono_class_num_fields (klass) == 1) && (klass->instance_size == sizeof (MonoObject)) &&
11471                         (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
11472                         /* This field is a hack inserted by MCS to empty structures */
11473                         continue;
11474                 }
11475
11476                 switch (layout) {
11477                 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
11478                 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
11479                         size = mono_marshal_type_size (field->type, info->fields [j].mspec, 
11480                                                        &align, TRUE, klass->unicode);
11481                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
11482                         min_align = MAX (align, min_align);
11483                         info->fields [j].offset = info->native_size;
11484                         info->fields [j].offset += align - 1;
11485                         info->fields [j].offset &= ~(align - 1);
11486                         info->native_size = info->fields [j].offset + size;
11487                         break;
11488                 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
11489                         size = mono_marshal_type_size (field->type, info->fields [j].mspec, 
11490                                                        &align, TRUE, klass->unicode);
11491                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
11492                         min_align = MAX (align, min_align);
11493                         info->fields [j].offset = field->offset - sizeof (MonoObject);
11494                         info->native_size = MAX (info->native_size, info->fields [j].offset + size);
11495                         break;
11496                 }       
11497                 j++;
11498         }
11499
11500         if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
11501                 info->native_size = MAX (native_size, info->native_size);
11502         }
11503
11504         if (info->native_size & (min_align - 1)) {
11505                 info->native_size += min_align - 1;
11506                 info->native_size &= ~(min_align - 1);
11507         }
11508
11509         info->min_align = min_align;
11510
11511         /* Update the class's blittable info, if the layouts don't match */
11512         if (info->native_size != mono_class_value_size (klass, NULL))
11513                 klass->blittable = FALSE;
11514
11515         /* If this is an array type, ensure that we have element info */
11516         if (klass->element_class && !mono_marshal_is_loading_type_info (klass->element_class)) {
11517                 mono_marshal_load_type_info (klass->element_class);
11518         }
11519
11520         loads_list = TlsGetValue (load_type_info_tls_id);
11521         loads_list = g_slist_remove (loads_list, klass);
11522         TlsSetValue (load_type_info_tls_id, loads_list);
11523
11524         /*We do double-checking locking on marshal_info */
11525         mono_memory_barrier ();
11526
11527         klass->marshal_info = info;
11528
11529         mono_loader_unlock ();
11530
11531         return klass->marshal_info;
11532 }
11533
11534 /**
11535  * mono_class_native_size:
11536  * @klass: a class 
11537  * 
11538  * Returns: the native size of an object instance (when marshaled 
11539  * to unmanaged code) 
11540  */
11541 gint32
11542 mono_class_native_size (MonoClass *klass, guint32 *align)
11543 {       
11544         if (!klass->marshal_info) {
11545                 if (mono_marshal_is_loading_type_info (klass)) {
11546                         if (align)
11547                                 *align = 0;
11548                         return 0;
11549                 } else {
11550                         mono_marshal_load_type_info (klass);
11551                 }
11552         }
11553
11554         if (align)
11555                 *align = klass->marshal_info->min_align;
11556
11557         return klass->marshal_info->native_size;
11558 }
11559
11560 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
11561    the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
11562    but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
11563 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
11564
11565 /*
11566  * mono_type_native_stack_size:
11567  * @t: the type to return the size it uses on the stack
11568  *
11569  * Returns: the number of bytes required to hold an instance of this
11570  * type on the native stack
11571  */
11572 int
11573 mono_type_native_stack_size (MonoType *t, guint32 *align)
11574 {
11575         guint32 tmp;
11576
11577         g_assert (t != NULL);
11578
11579         if (!align)
11580                 align = &tmp;
11581
11582         if (t->byref) {
11583                 *align = sizeof (gpointer);
11584                 return sizeof (gpointer);
11585         }
11586
11587         switch (t->type){
11588         case MONO_TYPE_BOOLEAN:
11589         case MONO_TYPE_CHAR:
11590         case MONO_TYPE_I1:
11591         case MONO_TYPE_U1:
11592         case MONO_TYPE_I2:
11593         case MONO_TYPE_U2:
11594         case MONO_TYPE_I4:
11595         case MONO_TYPE_U4:
11596                 *align = 4;
11597                 return 4;
11598         case MONO_TYPE_I:
11599         case MONO_TYPE_U:
11600         case MONO_TYPE_STRING:
11601         case MONO_TYPE_OBJECT:
11602         case MONO_TYPE_CLASS:
11603         case MONO_TYPE_SZARRAY:
11604         case MONO_TYPE_PTR:
11605         case MONO_TYPE_FNPTR:
11606         case MONO_TYPE_ARRAY:
11607                 *align = sizeof (gpointer);
11608                 return sizeof (gpointer);
11609         case MONO_TYPE_R4:
11610                 *align = 4;
11611                 return 4;
11612         case MONO_TYPE_R8:
11613                 *align = ALIGNMENT (gdouble);
11614                 return 8;
11615         case MONO_TYPE_I8:
11616         case MONO_TYPE_U8:
11617                 *align = ALIGNMENT (glong);
11618                 return 8;
11619         case MONO_TYPE_GENERICINST:
11620                 if (!mono_type_generic_inst_is_valuetype (t)) {
11621                         *align = sizeof (gpointer);
11622                         return sizeof (gpointer);
11623                 } 
11624                 /* Fall through */
11625         case MONO_TYPE_TYPEDBYREF:
11626         case MONO_TYPE_VALUETYPE: {
11627                 guint32 size;
11628                 MonoClass *klass = mono_class_from_mono_type (t);
11629
11630                 if (klass->enumtype)
11631                         return mono_type_native_stack_size (klass->enum_basetype, align);
11632                 else {
11633                         size = mono_class_native_size (klass, align);
11634                         *align = *align + 3;
11635                         *align &= ~3;
11636                         
11637                         size +=  3;
11638                         size &= ~3;
11639
11640                         return size;
11641                 }
11642         }
11643         default:
11644                 g_error ("type 0x%02x unknown", t->type);
11645         }
11646         return 0;
11647 }
11648
11649 gint32
11650 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
11651                         gboolean as_field, gboolean unicode)
11652 {
11653         MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
11654         MonoClass *klass;
11655
11656         switch (native_type) {
11657         case MONO_NATIVE_BOOLEAN:
11658                 *align = 4;
11659                 return 4;
11660         case MONO_NATIVE_I1:
11661         case MONO_NATIVE_U1:
11662                 *align = 1;
11663                 return 1;
11664         case MONO_NATIVE_I2:
11665         case MONO_NATIVE_U2:
11666         case MONO_NATIVE_VARIANTBOOL:
11667                 *align = 2;
11668                 return 2;
11669         case MONO_NATIVE_I4:
11670         case MONO_NATIVE_U4:
11671         case MONO_NATIVE_ERROR:
11672                 *align = 4;
11673                 return 4;
11674         case MONO_NATIVE_I8:
11675         case MONO_NATIVE_U8:
11676                 *align = ALIGNMENT(guint64);
11677                 return 8;
11678         case MONO_NATIVE_R4:
11679                 *align = 4;
11680                 return 4;
11681         case MONO_NATIVE_R8:
11682                 *align = ALIGNMENT(double);
11683                 return 8;
11684         case MONO_NATIVE_INT:
11685         case MONO_NATIVE_UINT:
11686         case MONO_NATIVE_LPSTR:
11687         case MONO_NATIVE_LPWSTR:
11688         case MONO_NATIVE_LPTSTR:
11689         case MONO_NATIVE_BSTR:
11690         case MONO_NATIVE_ANSIBSTR:
11691         case MONO_NATIVE_TBSTR:
11692         case MONO_NATIVE_LPARRAY:
11693         case MONO_NATIVE_SAFEARRAY:
11694         case MONO_NATIVE_IUNKNOWN:
11695         case MONO_NATIVE_IDISPATCH:
11696         case MONO_NATIVE_INTERFACE:
11697         case MONO_NATIVE_ASANY:
11698         case MONO_NATIVE_FUNC:
11699         case MONO_NATIVE_LPSTRUCT:
11700                 *align = ALIGNMENT(gpointer);
11701                 return sizeof (gpointer);
11702         case MONO_NATIVE_STRUCT: 
11703                 klass = mono_class_from_mono_type (type);
11704                 if (klass == mono_defaults.object_class &&
11705                         (mspec && mspec->native == MONO_NATIVE_STRUCT)) {
11706                 *align = 16;
11707                 return 16;
11708                 }
11709                 return mono_class_native_size (klass, align);
11710         case MONO_NATIVE_BYVALTSTR: {
11711                 int esize = unicode ? 2: 1;
11712                 g_assert (mspec);
11713                 *align = esize;
11714                 return mspec->data.array_data.num_elem * esize;
11715         }
11716         case MONO_NATIVE_BYVALARRAY: {
11717                 // FIXME: Have to consider ArraySubType
11718                 int esize;
11719                 klass = mono_class_from_mono_type (type);
11720                 if (klass->element_class == mono_defaults.char_class) {
11721                         esize = unicode ? 2 : 1;
11722                         *align = esize;
11723                 } else {
11724                         esize = mono_class_native_size (klass->element_class, align);
11725                 }
11726                 g_assert (mspec);
11727                 return mspec->data.array_data.num_elem * esize;
11728         }
11729         case MONO_NATIVE_CUSTOM:
11730                 *align = sizeof (gpointer);
11731                 return sizeof (gpointer);
11732                 break;
11733         case MONO_NATIVE_CURRENCY:
11734         case MONO_NATIVE_VBBYREFSTR:
11735         default:
11736                 g_error ("native type %02x not implemented", native_type); 
11737                 break;
11738         }
11739         g_assert_not_reached ();
11740         return 0;
11741 }
11742
11743 gpointer
11744 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
11745 {
11746         MonoType *t;
11747         MonoClass *klass;
11748
11749         if (o == NULL)
11750                 return NULL;
11751
11752         t = &o->vtable->klass->byval_arg;
11753         switch (t->type) {
11754         case MONO_TYPE_I4:
11755         case MONO_TYPE_U4:
11756         case MONO_TYPE_PTR:
11757         case MONO_TYPE_I1:
11758         case MONO_TYPE_U1:
11759         case MONO_TYPE_BOOLEAN:
11760         case MONO_TYPE_I2:
11761         case MONO_TYPE_U2:
11762         case MONO_TYPE_CHAR:
11763         case MONO_TYPE_I8:
11764         case MONO_TYPE_U8:
11765         case MONO_TYPE_R4:
11766         case MONO_TYPE_R8:
11767                 return mono_object_unbox (o);
11768                 break;
11769         case MONO_TYPE_STRING:
11770                 switch (string_encoding) {
11771                 case MONO_NATIVE_LPWSTR:
11772                         return mono_string_to_utf16 ((MonoString*)o);
11773                         break;
11774                 case MONO_NATIVE_LPSTR:
11775                         return mono_string_to_lpstr ((MonoString*)o);
11776                         break;
11777                 default:
11778                         g_warning ("marshaling conversion %d not implemented", string_encoding);
11779                         g_assert_not_reached ();
11780                 }
11781                 break;
11782         case MONO_TYPE_CLASS:
11783         case MONO_TYPE_VALUETYPE: {
11784                 MonoMethod *method;
11785                 gpointer pa [3];
11786                 gpointer res;
11787                 MonoBoolean delete_old = FALSE;
11788
11789                 klass = t->data.klass;
11790
11791                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
11792                         break;
11793
11794                 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
11795                         klass->blittable || klass->enumtype))
11796                         return mono_object_unbox (o);
11797
11798                 res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
11799
11800                 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
11801                         method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
11802
11803                         pa [0] = o;
11804                         pa [1] = &res;
11805                         pa [2] = &delete_old;
11806
11807                         mono_runtime_invoke (method, NULL, pa, NULL);
11808                 }
11809
11810                 return res;
11811         }
11812         }
11813
11814         mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
11815
11816         return NULL;
11817 }
11818
11819 void
11820 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
11821 {
11822         MonoType *t;
11823         MonoClass *klass;
11824
11825         if (o == NULL)
11826                 return;
11827
11828         t = &o->vtable->klass->byval_arg;
11829         switch (t->type) {
11830         case MONO_TYPE_STRING:
11831                 switch (string_encoding) {
11832                 case MONO_NATIVE_LPWSTR:
11833                 case MONO_NATIVE_LPSTR:
11834                         mono_marshal_free (ptr);
11835                         break;
11836                 default:
11837                         g_warning ("marshaling conversion %d not implemented", string_encoding);
11838                         g_assert_not_reached ();
11839                 }
11840                 break;
11841         case MONO_TYPE_CLASS:
11842         case MONO_TYPE_VALUETYPE: {
11843                 klass = t->data.klass;
11844
11845                 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
11846                                                                  klass->blittable || klass->enumtype))
11847                         break;
11848
11849                 if (param_attrs & PARAM_ATTRIBUTE_OUT) {
11850                         MonoMethod *method = mono_marshal_get_ptr_to_struct (o->vtable->klass);
11851                         gpointer pa [2];
11852
11853                         pa [0] = &ptr;
11854                         pa [1] = o;
11855
11856                         mono_runtime_invoke (method, NULL, pa, NULL);
11857                 }
11858
11859                 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
11860                         mono_struct_delete_old (klass, ptr);
11861                 }
11862
11863                 mono_marshal_free (ptr);
11864                 break;
11865         }
11866         default:
11867                 break;
11868         }
11869 }
11870
11871 MonoMethod *
11872 mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar *name, MonoMethod *method)
11873 {
11874         MonoMethodSignature *sig, *csig;
11875         MonoMethodBuilder *mb;
11876         MonoMethod *res;
11877         int i;
11878
11879         mb = mono_mb_new_no_dup_name (class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
11880         mb->method->slot = -1;
11881
11882         mb->method->flags = METHOD_ATTRIBUTE_PRIVATE | METHOD_ATTRIBUTE_VIRTUAL |
11883                 METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
11884
11885         sig = mono_method_signature (method);
11886         csig = signature_dup (method->klass->image, sig);
11887         csig->generic_param_count = 0;
11888
11889         mono_mb_emit_ldarg (mb, 0);
11890         for (i = 0; i < csig->param_count; i++)
11891                 mono_mb_emit_ldarg (mb, i + 1);
11892         mono_mb_emit_managed_call (mb, method, NULL);
11893         mono_mb_emit_byte (mb, CEE_RET);
11894
11895         res = mono_mb_create_method (mb, csig, csig->param_count + 16);
11896
11897         /* We can corlib internal methods */
11898         res->skip_visibility = TRUE;
11899
11900         mono_mb_free (mb);
11901
11902         return res;
11903 }
11904
11905 /*
11906  * The mono_win32_compat_* functions are implementations of inline
11907  * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11908  * although not exported by kernel32.
11909  *
11910  * We map the appropiate kernel32 entries to these functions using
11911  * dllmaps declared in the global etc/mono/config.
11912  */
11913
11914 void
11915 mono_win32_compat_CopyMemory (gpointer dest, gconstpointer source, gsize length)
11916 {
11917         if (!dest || !source)
11918                 return;
11919
11920         memcpy (dest, source, length);
11921 }
11922
11923 void
11924 mono_win32_compat_FillMemory (gpointer dest, gsize length, guchar fill)
11925 {
11926         memset (dest, fill, length);
11927 }
11928
11929 void
11930 mono_win32_compat_MoveMemory (gpointer dest, gconstpointer source, gsize length)
11931 {
11932         if (!dest || !source)
11933                 return;
11934
11935         memmove (dest, source, length);
11936 }
11937
11938 void
11939 mono_win32_compat_ZeroMemory (gpointer dest, gsize length)
11940 {
11941         memset (dest, 0, length);
11942 }
11943
11944 /* Put COM Interop related stuff here */
11945
11946 #ifndef DISABLE_COM
11947
11948 /**
11949  * cominterop_get_ccw_object:
11950  * @ccw_entry: a pointer to the CCWEntry
11951  * @verify: verify ccw_entry is in fact a ccw
11952  *
11953  * Returns: the corresponding object for the CCW
11954  */
11955 static MonoObject*
11956 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
11957 {
11958         MonoCCW *ccw = NULL;
11959
11960         /* no CCW's exist yet */
11961         if (!ccw_interface_hash)
11962                 return NULL;
11963
11964         if (verify) {
11965                 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
11966         }
11967         else {
11968                 ccw = ccw_entry->ccw;
11969                 g_assert (ccw);
11970         }
11971         if (ccw)
11972                 return mono_gchandle_get_target (ccw->gc_handle);
11973         else
11974                 return NULL;
11975 }
11976
11977 static void
11978 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
11979 {
11980         MonoMethodSignature *sig, *csig;
11981         sig = mono_method_signature (method);
11982         /* we copy the signature, so that we can modify it */
11983         /* FIXME: which to use? */
11984         csig = signature_dup (method->klass->image, sig);
11985         /* csig = mono_metadata_signature_dup (sig); */
11986         
11987         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
11988 #ifdef PLATFORM_WIN32
11989         csig->call_convention = MONO_CALL_STDCALL;
11990 #else
11991         csig->call_convention = MONO_CALL_C;
11992 #endif
11993         csig->hasthis = 0;
11994         csig->pinvoke = 1;
11995
11996         m->image = method->klass->image;
11997         m->piinfo = NULL;
11998         m->retobj_var = 0;
11999         m->sig = sig;
12000         m->csig = csig;
12001 }
12002
12003 /**
12004  * cominterop_get_ccw:
12005  * @object: a pointer to the object
12006  * @itf: interface type needed
12007  *
12008  * Returns: a value indicating if the object is a
12009  * Runtime Callable Wrapper (RCW) for a COM object
12010  */
12011 static gpointer
12012 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
12013 {
12014         int i;
12015         MonoCCW *ccw = NULL;
12016         MonoCCWInterface* ccw_entry = NULL;
12017         gpointer *vtable = NULL;
12018         static gpointer iunknown[3] = {NULL, NULL, NULL};
12019         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
12020         MonoClass* iface = NULL;
12021         MonoClass* klass = NULL;
12022         EmitMarshalContext m;
12023         int start_slot = 3;
12024         int method_count = 0;
12025         GList *ccw_list, *ccw_list_item;
12026         MonoCustomAttrInfo *cinfo = NULL;
12027
12028         if (!object)
12029                 return NULL;
12030
12031         klass = mono_object_get_class (object);
12032
12033         if (!ccw_hash)
12034                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
12035         if (!ccw_interface_hash)
12036                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
12037
12038         ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
12039
12040         ccw_list_item = ccw_list;
12041         while (ccw_list_item) {
12042                 MonoCCW* ccw_iter = ccw_list_item->data;
12043                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
12044                         ccw = ccw_iter;
12045                         break;
12046                 }
12047                 ccw_list_item = g_list_next(ccw_list_item);
12048         }
12049
12050         if (!iunknown [0]) {
12051                 iunknown [0] = cominterop_ccw_queryinterface;
12052                 iunknown [1] = cominterop_ccw_addref;
12053                 iunknown [2] = cominterop_ccw_release;
12054         }
12055
12056         if (!idispatch [0]) {
12057                 idispatch [0] = cominterop_ccw_get_type_info_count;
12058                 idispatch [1] = cominterop_ccw_get_type_info;
12059                 idispatch [2] = cominterop_ccw_get_ids_of_names;
12060                 idispatch [3] = cominterop_ccw_invoke;
12061         }
12062
12063         if (!ccw) {
12064                 ccw = g_new0 (MonoCCW, 1);
12065 #ifdef PLATFORM_WIN32
12066                 ccw->free_marshaler = 0;
12067 #endif
12068                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
12069                 ccw->ref_count = 0;
12070                 /* just alloc a weak handle until we are addref'd*/
12071                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
12072
12073                 if (!ccw_list) {
12074                         ccw_list = g_list_alloc ();
12075                         ccw_list->data = ccw;
12076                 }
12077                 else
12078                         ccw_list = g_list_append (ccw_list, ccw);
12079                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
12080                 /* register for finalization to clean up ccw */
12081                 mono_object_register_finalizer (object);
12082         }
12083
12084         cinfo = mono_custom_attrs_from_class (itf);
12085         if (cinfo) {
12086                 static MonoClass* coclass_attribute = NULL;
12087                 if (!coclass_attribute)
12088                         coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
12089                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
12090                         g_assert(itf->interface_count && itf->interfaces[0]);
12091                         itf = itf->interfaces[0];
12092                 }
12093                 if (!cinfo->cached)
12094                         mono_custom_attrs_free (cinfo);
12095         }
12096
12097         iface = itf;
12098         if (iface == mono_defaults.iunknown_class) {
12099                 start_slot = 3;
12100         }
12101         else if (iface == mono_defaults.idispatch_class) {
12102                 start_slot = 7;
12103         }
12104         else {
12105                 method_count += iface->method.count;
12106                 start_slot = cominterop_get_com_slot_begin (iface);
12107                 iface = NULL;
12108         }
12109
12110         ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
12111
12112         if (!ccw_entry) {
12113                 int vtable_index = method_count-1+start_slot;
12114                 mono_loader_lock ();
12115                 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
12116                 mono_loader_unlock ();
12117                 memcpy (vtable, iunknown, sizeof (iunknown));
12118                 if (start_slot == 7)
12119                         memcpy (vtable+3, idispatch, sizeof (idispatch));
12120
12121                 iface = itf;
12122                 for (i = iface->method.count-1; i >= 0;i--) {
12123                         int param_index = 0;
12124                         MonoMethodBuilder *mb;
12125                         MonoMarshalSpec ** mspecs;
12126                         MonoMethod *wrapper_method, *adjust_method;
12127                         MonoMethod *method = iface->methods [i];
12128                         MonoMethodSignature* sig_adjusted;
12129                         MonoMethodSignature* sig = mono_method_signature (method);
12130                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
12131
12132
12133                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
12134                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
12135                         sig_adjusted = mono_method_signature (adjust_method);
12136                         
12137                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
12138                         mono_method_get_marshal_info (method, mspecs);
12139
12140                         
12141                         /* move managed args up one */
12142                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
12143                                 int mspec_index = param_index+1;
12144                                 mspecs [mspec_index] = mspecs [param_index];
12145
12146                                 if (mspecs[mspec_index] == NULL) {
12147                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
12148                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
12149                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
12150                                         }
12151                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
12152                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
12153                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
12154                                         }
12155                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
12156                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
12157                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
12158                                         }
12159                                 }
12160                         }
12161
12162                         /* first arg is IntPtr for interface */
12163                         mspecs [1] = NULL;
12164
12165                         /* move return spec to last param */
12166                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
12167                                 if (mspecs [0] == NULL) {
12168                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
12169                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
12170                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
12171                                         }
12172                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
12173                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
12174                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
12175                                         }
12176                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
12177                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
12178                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
12179                                         }
12180                                 }
12181
12182                                 mspecs [sig_adjusted->param_count] = mspecs [0];
12183                                 mspecs [0] = NULL;
12184                         }
12185
12186                         cominterop_setup_marshal_context (&m, adjust_method);
12187                         m.mb = mb;
12188                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL);
12189                         mono_loader_lock ();
12190                         mono_marshal_lock ();
12191                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
12192                         mono_marshal_unlock ();
12193                         mono_loader_unlock ();
12194
12195                         /* skip visiblity since we call internal methods */
12196                         wrapper_method->skip_visibility = TRUE;
12197
12198                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
12199
12200                         
12201                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
12202                                 if (mspecs [param_index])
12203                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
12204                         g_free (mspecs);
12205                 }
12206
12207                 ccw_entry = g_new0 (MonoCCWInterface, 1);
12208                 ccw_entry->ccw = ccw;
12209                 ccw_entry->vtable = vtable;
12210                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
12211                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
12212         }
12213
12214         return ccw_entry;
12215 }
12216
12217 static gboolean    
12218 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
12219 {
12220         g_assert (value);
12221         g_free (value);
12222         return TRUE;
12223 }
12224
12225 /**
12226  * mono_marshal_free_ccw:
12227  * @object: the mono object
12228  *
12229  * Returns: whether the object had a CCW
12230  */
12231 gboolean
12232 mono_marshal_free_ccw (MonoObject* object)
12233 {
12234         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
12235         /* no ccw's were created */
12236         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
12237                 return FALSE;
12238
12239         /* need to cache orig list address to remove from hash_table if empty */
12240         mono_cominterop_lock ();
12241         ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
12242         mono_cominterop_unlock ();
12243
12244         if (!ccw_list)
12245                 return FALSE;
12246
12247         ccw_list_item = ccw_list;
12248         while (ccw_list_item) {
12249                 MonoCCW* ccw_iter = ccw_list_item->data;
12250                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
12251
12252                 /* Looks like the GC NULLs the weakref handle target before running the
12253                  * finalizer. So if we get a NULL target, destroy the CCW as well. */
12254                 if (!handle_target || handle_target == object) {
12255                         /* remove all interfaces */
12256                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
12257                         g_hash_table_destroy (ccw_iter->vtable_hash);
12258
12259                         /* get next before we delete */
12260                         ccw_list_item = g_list_next(ccw_list_item);
12261
12262                         /* remove ccw from list */
12263                         ccw_list = g_list_remove (ccw_list, ccw_iter);
12264                         g_free (ccw_iter);
12265                 }
12266                 else
12267                         ccw_list_item = g_list_next(ccw_list_item);
12268         }
12269
12270         /* if list is empty remove original address from hash */
12271         if (g_list_length (ccw_list) == 0)
12272                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
12273
12274
12275         return TRUE;
12276 }
12277
12278 /**
12279  * cominterop_get_managed_wrapper_adjusted:
12280  * @method: managed COM Interop method
12281  *
12282  * Returns: the generated method to call with signature matching
12283  * the unmanaged COM Method signature
12284  */
12285 static MonoMethod *
12286 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
12287 {
12288         static MonoMethod *get_hr_for_exception = NULL;
12289         MonoMethod *res = NULL;
12290         MonoMethodBuilder *mb;
12291         MonoMarshalSpec **mspecs;
12292         MonoMethodSignature *sig, *sig_native;
12293         MonoExceptionClause *main_clause = NULL;
12294         int pos_leave;
12295         int hr = 0;
12296         int i;
12297         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
12298
12299         if (!get_hr_for_exception)
12300                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
12301
12302         sig = mono_method_signature (method);
12303
12304         /* create unmanaged wrapper */
12305         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
12306
12307         sig_native = cominterop_method_signature (method);
12308
12309         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
12310
12311         mono_method_get_marshal_info (method, mspecs);
12312
12313         /* move managed args up one */
12314         for (i = sig->param_count; i >= 1; i--)
12315                 mspecs [i+1] = mspecs [i];
12316
12317         /* first arg is IntPtr for interface */
12318         mspecs [1] = NULL;
12319
12320         /* move return spec to last param */
12321         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
12322                 mspecs [sig_native->param_count] = mspecs [0];
12323
12324         mspecs [0] = NULL;
12325
12326         if (!preserve_sig) {
12327                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
12328
12329                 /* try */
12330                 main_clause = g_new0 (MonoExceptionClause, 1);
12331                 main_clause->try_offset = mono_mb_get_label (mb);
12332         }
12333
12334         /* load last param to store result if not preserve_sig and not void */
12335         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
12336                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
12337
12338         /* the CCW -> object conversion */
12339         mono_mb_emit_ldarg (mb, 0);
12340         mono_mb_emit_icon (mb, FALSE);
12341         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
12342
12343         for (i = 0; i < sig->param_count; i++)
12344                 mono_mb_emit_ldarg (mb, i+1);
12345
12346         mono_mb_emit_managed_call (mb, method, NULL);
12347
12348         if (!preserve_sig) {
12349                 /* store result if not preserve_sig and we have one */
12350                 if (!MONO_TYPE_IS_VOID (sig->ret))
12351                         mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
12352
12353                 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
12354
12355                 /* Main exception catch */
12356                 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
12357                 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
12358                 main_clause->data.catch_class = mono_defaults.object_class;
12359                 
12360                 /* handler code */
12361                 main_clause->handler_offset = mono_mb_get_label (mb);
12362                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
12363                 mono_mb_emit_stloc (mb, hr);
12364                 mono_mb_emit_branch (mb, CEE_LEAVE);
12365                 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
12366                 /* end catch */
12367
12368                 mono_mb_set_clauses (mb, 1, main_clause);
12369
12370                 mono_mb_patch_branch (mb, pos_leave);
12371
12372                 mono_mb_emit_ldloc (mb, hr);
12373         }
12374
12375         mono_mb_emit_byte (mb, CEE_RET);
12376
12377         mono_loader_lock ();
12378         mono_marshal_lock ();
12379         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
12380         mono_marshal_unlock ();
12381         mono_loader_unlock ();
12382
12383         mono_mb_free (mb);
12384
12385         for (i = sig_native->param_count; i >= 0; i--)
12386                 if (mspecs [i])
12387                         mono_metadata_free_marshal_spec (mspecs [i]);
12388         g_free (mspecs);
12389
12390         return res;
12391 }
12392
12393 /**
12394  * cominterop_mono_string_to_guid:
12395  *
12396  * Converts the standard string representation of a GUID 
12397  * to a 16 byte Microsoft GUID.
12398  */
12399 static void
12400 cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
12401         gunichar2 * chars = mono_string_chars (string);
12402         int i = 0;
12403         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
12404
12405         for (i = 0; i < sizeof(indexes); i++)
12406                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
12407 }
12408
12409 static gboolean
12410 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
12411 {
12412         guint8 klass_guid [16];
12413         if (cominterop_class_guid (klass, klass_guid))
12414                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
12415         return FALSE;
12416 }
12417
12418 static int STDCALL 
12419 cominterop_ccw_addref (MonoCCWInterface* ccwe)
12420 {
12421         gint32 ref_count = 0;
12422         MonoCCW* ccw = ccwe->ccw;
12423         g_assert (ccw);
12424         g_assert (ccw->gc_handle);
12425         g_assert (ccw->ref_count >= 0);
12426         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
12427         if (ref_count == 1) {
12428                 guint32 oldhandle = ccw->gc_handle;
12429                 g_assert (oldhandle);
12430                 /* since we now have a ref count, alloc a strong handle*/
12431                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
12432                 mono_gchandle_free (oldhandle);
12433         }
12434         return ref_count;
12435 }
12436
12437 static int STDCALL 
12438 cominterop_ccw_release (MonoCCWInterface* ccwe)
12439 {
12440         gint32 ref_count = 0;
12441         MonoCCW* ccw = ccwe->ccw;
12442         g_assert (ccw);
12443         g_assert (ccw->ref_count > 0);
12444         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
12445         if (ref_count == 0) {
12446                 /* allow gc of object */
12447                 guint32 oldhandle = ccw->gc_handle;
12448                 g_assert (oldhandle);
12449 #ifdef PLATFORM_WIN32
12450                 if (ccw->free_marshaler)
12451                         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
12452 #endif
12453                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
12454                 mono_gchandle_free (oldhandle);
12455         }
12456         return ref_count;
12457 }
12458
12459 #ifdef PLATFORM_WIN32
12460 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
12461 #endif
12462
12463 #ifdef PLATFORM_WIN32
12464 /* All ccw objects are free threaded */
12465 static int
12466 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
12467 {
12468 #ifdef PLATFORM_WIN32
12469         if (!ccw->free_marshaler) {
12470                 int ret = 0;
12471                 gpointer tunk;
12472                 tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
12473                 /* remember to addref on QI */
12474                 cominterop_ccw_addref (tunk);
12475                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
12476                 cominterop_ccw_release(tunk);
12477         }
12478                 
12479         if (!ccw->free_marshaler)
12480                 return MONO_E_NOINTERFACE;
12481
12482         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
12483 #else
12484         return MONO_E_NOINTERFACE;
12485 #endif
12486 }
12487 #endif
12488
12489 static int STDCALL 
12490 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
12491 {
12492         GPtrArray *ifaces;
12493         MonoClass *itf = NULL;
12494         int i;
12495         MonoCCW* ccw = ccwe->ccw;
12496         MonoClass* klass = NULL;
12497         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
12498         
12499         g_assert (object);
12500         klass = mono_object_class (object);
12501
12502         if (ppv)
12503                 *ppv = NULL;
12504
12505         if (!mono_domain_get ())
12506                 mono_thread_attach (mono_get_root_domain ());
12507
12508         /* handle IUnknown special */
12509         if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
12510                 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
12511                 /* remember to addref on QI */
12512                 cominterop_ccw_addref (*ppv);
12513                 return MONO_S_OK;
12514         }
12515
12516         /* handle IDispatch special */
12517         if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
12518                 if (!cominterop_can_support_dispatch (klass))
12519                         return MONO_E_NOINTERFACE;
12520                 
12521                 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
12522                 /* remember to addref on QI */
12523                 cominterop_ccw_addref (*ppv);
12524                 return MONO_S_OK;
12525         }
12526
12527 #ifdef PLATFORM_WIN32
12528         /* handle IMarshal special */
12529         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
12530                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
12531         }
12532 #endif
12533
12534         ifaces = mono_class_get_implemented_interfaces (klass);
12535         if (ifaces) {
12536                 for (i = 0; i < ifaces->len; ++i) {
12537                         MonoClass *ic = NULL;
12538                         ic = g_ptr_array_index (ifaces, i);
12539                         if (cominterop_class_guid_equal (riid, ic)) {
12540                                 itf = ic;
12541                                 break;
12542                         }
12543                 }
12544                 g_ptr_array_free (ifaces, TRUE);
12545         }
12546         if (itf) {
12547                 *ppv = cominterop_get_ccw (object, itf);
12548                 /* remember to addref on QI */
12549                 cominterop_ccw_addref (*ppv);
12550                 return MONO_S_OK;
12551         }
12552
12553         return MONO_E_NOINTERFACE;
12554 }
12555
12556 static int STDCALL 
12557 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
12558 {
12559         return MONO_E_NOTIMPL;
12560 }
12561
12562 static int STDCALL 
12563 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
12564 {
12565         return MONO_E_NOTIMPL;
12566 }
12567
12568 static int STDCALL 
12569 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
12570                                                                                          gunichar2** rgszNames, guint32 cNames,
12571                                                                                          guint32 lcid, gint32 *rgDispId)
12572 {
12573         return MONO_E_NOTIMPL;
12574 }
12575
12576 static int STDCALL 
12577 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
12578                                                                    gpointer riid, guint32 lcid,
12579                                                                    guint16 wFlags, gpointer pDispParams,
12580                                                                    gpointer pVarResult, gpointer pExcepInfo,
12581                                                                    guint32 *puArgErr)
12582 {
12583         return MONO_E_NOTIMPL;
12584 }
12585
12586 #else /* DISABLE_COM */
12587
12588 gboolean
12589 mono_marshal_free_ccw (MonoObject* object)
12590 {
12591         return FALSE;
12592 }
12593
12594 #endif /* DISABLE_COM */
12595
12596 void
12597 mono_marshal_find_nonzero_bit_offset (guint8 *buf, int len, int *byte_offset, guint8 *bitmask)
12598 {
12599         int i;
12600         guint8 byte;
12601
12602         for (i = 0; i < len; ++i)
12603                 if (buf [i])
12604                         break;
12605
12606         g_assert (i < len);
12607
12608         byte = buf [i];
12609         while (byte && !(byte & 1))
12610                 byte >>= 1;
12611         g_assert (byte == 1);
12612
12613         *byte_offset = i;
12614         *bitmask = buf [i];
12615 }
12616
12617 MonoMethod *
12618 mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
12619 {
12620         MonoMethodBuilder *mb;
12621         MonoMethodSignature *sig, *csig;
12622         MonoExceptionClause *clause;
12623         MonoImage *image;
12624         MonoClass *klass;
12625         GHashTable *cache;
12626         MonoMethod *res;
12627         int i, param_count, sig_size, pos_leave;
12628
12629         g_assert (method);
12630
12631         klass = method->klass;
12632         image = method->klass->image;
12633         cache = get_cache (&image->thunk_invoke_cache, mono_aligned_addr_hash, NULL);
12634
12635         if ((res = mono_marshal_find_in_cache (cache, method)))
12636                 return res;
12637
12638         sig = mono_method_signature (method);
12639         mb = mono_mb_new (klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
12640
12641         /* add "this" and exception param */
12642         param_count = sig->param_count + sig->hasthis + 1;
12643
12644         /* dup & extend signature */
12645         csig = mono_metadata_signature_alloc (image, param_count);
12646         sig_size = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
12647         memcpy (csig, sig, sig_size);
12648         csig->param_count = param_count;
12649         csig->hasthis = 0;
12650         csig->pinvoke = 1;
12651         csig->call_convention = MONO_CALL_DEFAULT;
12652
12653         if (sig->hasthis) {
12654                 /* add "this" */
12655                 csig->params [0] = &klass->byval_arg;
12656                 /* move params up by one */
12657                 for (i = 0; i < sig->param_count; i++)
12658                         csig->params [i + 1] = sig->params [i];
12659         }
12660
12661         /* setup exception param as byref+[out] */
12662         csig->params [param_count - 1] = mono_metadata_type_dup (image->mempool,
12663                  &mono_defaults.exception_class->byval_arg);
12664         csig->params [param_count - 1]->byref = 1;
12665         csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT;
12666
12667         /* convert struct return to object */
12668         if (MONO_TYPE_ISSTRUCT (sig->ret))
12669                 csig->ret = &mono_defaults.object_class->byval_arg;
12670
12671         /* local 0 (temp for exception object) */
12672         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
12673
12674         /* local 1 (temp for result) */
12675         if (!MONO_TYPE_IS_VOID (sig->ret))
12676                 mono_mb_add_local (mb, sig->ret);
12677
12678         /* clear exception arg */
12679         mono_mb_emit_ldarg (mb, param_count - 1);
12680         mono_mb_emit_byte (mb, CEE_LDNULL);
12681         mono_mb_emit_byte (mb, CEE_STIND_REF);
12682
12683         /* try */
12684         mono_loader_lock ();
12685         clause = mono_image_alloc0 (image, sizeof (MonoExceptionClause));
12686         mono_loader_unlock ();
12687         clause->try_offset = mono_mb_get_label (mb);
12688
12689         /* push method's args */
12690         for (i = 0; i < param_count - 1; i++) {
12691                 MonoType *type;
12692                 MonoClass *klass;
12693
12694                 mono_mb_emit_ldarg (mb, i);
12695
12696                 /* get the byval type of the param */
12697                 klass = mono_class_from_mono_type (csig->params [i]);
12698                 type = &klass->byval_arg;
12699
12700                 /* unbox struct args */
12701                 if (MONO_TYPE_ISSTRUCT (type)) {
12702                         mono_mb_emit_op (mb, CEE_UNBOX, klass);
12703
12704                         /* byref args & and the "this" arg must remain a ptr.
12705                            Otherwise make a copy of the value type */
12706                         if (!(csig->params [i]->byref || (i == 0 && sig->hasthis)))
12707                                 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
12708
12709                         csig->params [i] = &mono_defaults.object_class->byval_arg;
12710                 }
12711         }
12712
12713         /* call */
12714         if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
12715                 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
12716         else
12717                 mono_mb_emit_op (mb, CEE_CALL, method);
12718
12719         /* save result at local 1 */
12720         if (!MONO_TYPE_IS_VOID (sig->ret))
12721                 mono_mb_emit_stloc (mb, 1);
12722
12723         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
12724
12725         /* catch */
12726         clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
12727         clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
12728         clause->data.catch_class = mono_defaults.object_class;
12729
12730         clause->handler_offset = mono_mb_get_label (mb);
12731
12732         /* store exception at local 0 */
12733         mono_mb_emit_stloc (mb, 0);
12734         mono_mb_emit_ldarg (mb, param_count - 1);
12735         mono_mb_emit_ldloc (mb, 0);
12736         mono_mb_emit_byte (mb, CEE_STIND_REF);
12737         mono_mb_emit_branch (mb, CEE_LEAVE);
12738
12739         clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
12740
12741         mono_mb_set_clauses (mb, 1, clause);
12742
12743         mono_mb_patch_branch (mb, pos_leave);
12744         /* end-try */
12745
12746         if (!MONO_TYPE_IS_VOID (sig->ret)) {
12747                 mono_mb_emit_ldloc (mb, 1);
12748
12749                 /* box the return value */
12750                 if (MONO_TYPE_ISSTRUCT (sig->ret))
12751                         mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
12752         }
12753
12754         mono_mb_emit_byte (mb, CEE_RET);
12755
12756         res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16);
12757         mono_mb_free (mb);
12758
12759         return res;
12760 }