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