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