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