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