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