2008-01-10 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / marshal.c
1 /*
2  * marshal.c: Routines for marshaling complex types in P/Invoke methods.
3  * 
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (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);
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);
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 *dealy_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 (!dealy_abort_sig) {
4551                 dealy_abort_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4552                 dealy_abort_sig->ret = &mono_defaults.void_class->byval_arg;
4553                 dealy_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, dealy_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)
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         emit_thread_interrupt_checkpoint (mb);
5325         mono_mb_emit_byte (mb, CEE_RET);
5326
5327         csig = signature_dup (mono_defaults.corlib, sig);
5328         csig->pinvoke = 0;
5329         if (csig->call_convention == MONO_CALL_VARARG)
5330                 csig->call_convention = 0;
5331
5332         res = mono_mb_create_method (mb, csig, csig->param_count + 16);
5333         mono_mb_free (mb);
5334         
5335         return res;
5336 }
5337
5338 typedef struct {
5339         MonoMethodBuilder *mb;
5340         MonoMethodSignature *sig;
5341         MonoMethodPInvoke *piinfo;
5342         int *orig_conv_args; /* Locals containing the original values of byref args */
5343         int retobj_var;
5344         MonoClass *retobj_class;
5345         MonoMethodSignature *csig; /* Might need to be changed due to MarshalAs directives */
5346         MonoImage *image; /* The image to use for looking up custom marshallers */
5347 } EmitMarshalContext;
5348
5349 typedef enum {
5350         /*
5351          * This is invoked to convert arguments from the current types to
5352          * the underlying types expected by the platform routine.  If required,
5353          * the methods create a temporary variable with the proper type, and return
5354          * the location for it (either the passed argument, or the newly allocated
5355          * local slot).
5356          */
5357         MARSHAL_ACTION_CONV_IN,
5358
5359         /*
5360          * This operation is called to push the actual value that was optionally
5361          * converted on the first stage
5362          */
5363         MARSHAL_ACTION_PUSH,
5364
5365         /*
5366          * Convert byref arguments back or free resources allocated during the
5367          * CONV_IN stage
5368          */
5369         MARSHAL_ACTION_CONV_OUT,
5370
5371         /*
5372          * The result from the unmanaged call is at the top of the stack when
5373          * this action is invoked.    The result should be stored in the
5374          * third local variable slot. 
5375          */
5376         MARSHAL_ACTION_CONV_RESULT,
5377
5378         MARSHAL_ACTION_MANAGED_CONV_IN,
5379         MARSHAL_ACTION_MANAGED_CONV_OUT,
5380         MARSHAL_ACTION_MANAGED_CONV_RESULT
5381 } MarshalAction;
5382
5383 static int
5384 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
5385                                          MonoMarshalSpec *spec, 
5386                                          int conv_arg, MonoType **conv_arg_type, 
5387                                          MarshalAction action)
5388 {
5389         MonoType *mtype;
5390         MonoClass *mklass;
5391         static MonoClass *ICustomMarshaler = NULL;
5392         static MonoMethod *cleanup_native, *cleanup_managed;
5393         static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
5394         MonoMethod *get_instance;
5395         MonoMethodBuilder *mb = m->mb;
5396         char *exception_msg = NULL;
5397         guint32 loc1;
5398         int pos2;
5399
5400         if (!ICustomMarshaler) {
5401                 ICustomMarshaler = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
5402                 g_assert (ICustomMarshaler);
5403
5404                 cleanup_native = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpNativeData", 1);
5405                 g_assert (cleanup_native);
5406                 cleanup_managed = mono_class_get_method_from_name (ICustomMarshaler, "CleanUpManagedData", 1);
5407                 g_assert (cleanup_managed);
5408                 marshal_managed_to_native = mono_class_get_method_from_name (ICustomMarshaler, "MarshalManagedToNative", 1);
5409                 g_assert (marshal_managed_to_native);
5410                 marshal_native_to_managed = mono_class_get_method_from_name (ICustomMarshaler, "MarshalNativeToManaged", 1);
5411                 g_assert (marshal_native_to_managed);
5412         }
5413
5414         mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
5415         g_assert (mtype != NULL);
5416         mklass = mono_class_from_mono_type (mtype);
5417         g_assert (mklass != NULL);
5418
5419         if (!mono_class_is_assignable_from (ICustomMarshaler, mklass))
5420                 exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass->name);
5421
5422         get_instance = mono_class_get_method_from_name_flags (mklass, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC);
5423         if (get_instance) {
5424                 MonoMethodSignature *get_sig = mono_method_signature (get_instance);
5425                 if ((get_sig->ret->type != MONO_TYPE_CLASS) ||
5426                         (mono_class_from_mono_type (get_sig->ret) != ICustomMarshaler) ||
5427                         (get_sig->params [0]->type != MONO_TYPE_STRING))
5428                         get_instance = NULL;
5429         }
5430
5431         if (!get_instance)
5432                 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);
5433
5434         /* Throw exception and emit compensation code if neccesary */
5435         if (exception_msg) {
5436                 switch (action) {
5437                 case MARSHAL_ACTION_CONV_IN:
5438                 case MARSHAL_ACTION_CONV_RESULT:
5439                 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5440                         if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT))
5441                                 mono_mb_emit_byte (mb, CEE_POP);
5442
5443                         mono_mb_emit_exception_full (mb, "System", "ApplicationException", exception_msg);
5444                         g_free (exception_msg);
5445
5446                         break;
5447                 case MARSHAL_ACTION_PUSH:
5448                         mono_mb_emit_byte (mb, CEE_LDNULL);
5449                         break;
5450                 default:
5451                         break;
5452                 }
5453                 return 0;
5454         }
5455
5456         /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
5457         /* FIXME: MS.NET throws an exception if GetInstance returns null */
5458
5459         switch (action) {
5460         case MARSHAL_ACTION_CONV_IN:
5461                 switch (t->type) {
5462                 case MONO_TYPE_CLASS:
5463                 case MONO_TYPE_OBJECT:
5464                 case MONO_TYPE_STRING:
5465                 case MONO_TYPE_ARRAY:
5466                 case MONO_TYPE_SZARRAY:
5467                 case MONO_TYPE_VALUETYPE:
5468                         break;
5469
5470                 default:
5471                         g_warning ("custom marshalling of type %x is currently not supported", t->type);
5472                         g_assert_not_reached ();
5473                         break;
5474                 }
5475
5476                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5477
5478                 mono_mb_emit_byte (mb, CEE_LDNULL);
5479                 mono_mb_emit_stloc (mb, conv_arg);
5480
5481                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
5482                         break;
5483
5484                 /* Minic MS.NET behavior */
5485                 if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
5486                         break;
5487
5488                 /* Check for null */
5489                 mono_mb_emit_ldarg (mb, argnum);
5490                 if (t->byref)
5491                         mono_mb_emit_byte (mb, CEE_LDIND_I);
5492                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5493
5494                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5495
5496                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5497                                 
5498                 mono_mb_emit_ldarg (mb, argnum);
5499                 if (t->byref)
5500                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
5501
5502                 if (t->type == MONO_TYPE_VALUETYPE) {
5503                         /*
5504                          * Since we can't determine the type of the argument, we
5505                          * will assume the unmanaged function takes a pointer.
5506                          */
5507                         *conv_arg_type = &mono_defaults.int_class->byval_arg;
5508
5509                         mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
5510                 }
5511
5512                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5513                 mono_mb_emit_stloc (mb, conv_arg);
5514
5515                 mono_mb_patch_branch (mb, pos2);
5516                 break;
5517
5518         case MARSHAL_ACTION_CONV_OUT:
5519                 /* Check for null */
5520                 mono_mb_emit_ldloc (mb, conv_arg);
5521                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5522
5523                 if (t->byref) {
5524                         mono_mb_emit_ldarg (mb, argnum);
5525
5526                         mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5527
5528                         mono_mb_emit_op (mb, CEE_CALL, get_instance);
5529
5530                         mono_mb_emit_ldloc (mb, conv_arg);
5531                         mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5532                         mono_mb_emit_byte (mb, CEE_STIND_REF);
5533                 } else if (t->attrs &PARAM_ATTRIBUTE_OUT) {
5534                         mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5535
5536                         mono_mb_emit_op (mb, CEE_CALL, get_instance);
5537
5538                         mono_mb_emit_ldloc (mb, conv_arg);
5539                         mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5540
5541                         /* We have nowhere to store the result */
5542                         mono_mb_emit_byte (mb, CEE_POP);
5543                 }
5544
5545                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5546
5547                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5548
5549                 mono_mb_emit_ldloc (mb, conv_arg);
5550
5551                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
5552
5553                 mono_mb_patch_branch (mb, pos2);
5554                 break;
5555
5556         case MARSHAL_ACTION_PUSH:
5557                 if (t->byref)
5558                         mono_mb_emit_ldloc_addr (mb, conv_arg);
5559                 else
5560                         mono_mb_emit_ldloc (mb, conv_arg);
5561                 break;
5562
5563         case MARSHAL_ACTION_CONV_RESULT:
5564                 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5565                         
5566                 mono_mb_emit_stloc (mb, 3);
5567
5568                 mono_mb_emit_ldloc (mb, 3);
5569                 mono_mb_emit_stloc (mb, loc1);
5570
5571                 /* Check for null */
5572                 mono_mb_emit_ldloc (mb, 3);
5573                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5574
5575                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5576
5577                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5578                 mono_mb_emit_byte (mb, CEE_DUP);
5579
5580                 mono_mb_emit_ldloc (mb, 3);
5581                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5582                 mono_mb_emit_stloc (mb, 3);
5583
5584                 mono_mb_emit_ldloc (mb, loc1);
5585                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
5586
5587                 mono_mb_patch_branch (mb, pos2);
5588                 break;
5589
5590         case MARSHAL_ACTION_MANAGED_CONV_IN:
5591                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5592
5593                 mono_mb_emit_byte (mb, CEE_LDNULL);
5594                 mono_mb_emit_stloc (mb, conv_arg);
5595
5596                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
5597                         break;
5598
5599                 /* Check for null */
5600                 mono_mb_emit_ldarg (mb, argnum);
5601                 if (t->byref)
5602                         mono_mb_emit_byte (mb, CEE_LDIND_I);
5603                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5604
5605                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5606                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5607                                 
5608                 mono_mb_emit_ldarg (mb, argnum);
5609                 if (t->byref)
5610                         mono_mb_emit_byte (mb, CEE_LDIND_I);
5611                                 
5612                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5613                 mono_mb_emit_stloc (mb, conv_arg);
5614
5615                 mono_mb_patch_branch (mb, pos2);
5616                 break;
5617
5618         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5619                 g_assert (!t->byref);
5620
5621                 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5622                         
5623                 mono_mb_emit_stloc (mb, 3);
5624                         
5625                 mono_mb_emit_ldloc (mb, 3);
5626                 mono_mb_emit_stloc (mb, loc1);
5627
5628                 /* Check for null */
5629                 mono_mb_emit_ldloc (mb, 3);
5630                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5631
5632                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5633                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5634                 mono_mb_emit_byte (mb, CEE_DUP);
5635
5636                 mono_mb_emit_ldloc (mb, 3);
5637                 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5638                 mono_mb_emit_stloc (mb, 3);
5639
5640                 mono_mb_emit_ldloc (mb, loc1);
5641                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
5642
5643                 mono_mb_patch_branch (mb, pos2);
5644                 break;
5645
5646         case MARSHAL_ACTION_MANAGED_CONV_OUT:
5647
5648                 /* Check for null */
5649                 mono_mb_emit_ldloc (mb, conv_arg);
5650                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5651
5652                 if (t->byref) {
5653                         mono_mb_emit_ldarg (mb, argnum);
5654
5655                         mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5656
5657                         mono_mb_emit_op (mb, CEE_CALL, get_instance);
5658
5659                         mono_mb_emit_ldloc (mb, conv_arg);
5660                         mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5661                         mono_mb_emit_byte (mb, CEE_STIND_I);
5662                 }
5663
5664                 /* Call CleanUpManagedData */
5665                 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5666
5667                 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5668                                 
5669                 mono_mb_emit_ldloc (mb, conv_arg);
5670                 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
5671
5672                 mono_mb_patch_branch (mb, pos2);
5673                 break;
5674
5675         default:
5676                 g_assert_not_reached ();
5677         }
5678                 
5679         return conv_arg;
5680 }
5681
5682 static int
5683 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
5684                                         MonoMarshalSpec *spec, 
5685                                         int conv_arg, MonoType **conv_arg_type, 
5686                                         MarshalAction action)
5687 {
5688         MonoMethodBuilder *mb = m->mb;
5689
5690         switch (action) {
5691         case MARSHAL_ACTION_CONV_IN: {
5692                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
5693
5694                 g_assert (t->type == MONO_TYPE_OBJECT);
5695                 g_assert (!t->byref);
5696
5697                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5698                 mono_mb_emit_ldarg (mb, argnum);
5699                 mono_mb_emit_icon (mb, encoding);
5700                 mono_mb_emit_icon (mb, t->attrs);
5701                 mono_mb_emit_icall (mb, mono_marshal_asany);
5702                 mono_mb_emit_stloc (mb, conv_arg);
5703                 break;
5704         }
5705
5706         case MARSHAL_ACTION_PUSH:
5707                 mono_mb_emit_ldloc (mb, conv_arg);
5708                 break;
5709
5710         case MARSHAL_ACTION_CONV_OUT: {
5711                 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
5712
5713                 mono_mb_emit_ldarg (mb, argnum);
5714                 mono_mb_emit_ldloc (mb, conv_arg);
5715                 mono_mb_emit_icon (mb, encoding);
5716                 mono_mb_emit_icon (mb, t->attrs);
5717                 mono_mb_emit_icall (mb, mono_marshal_free_asany);
5718                 break;
5719         }
5720
5721         default:
5722                 g_assert_not_reached ();
5723         }
5724
5725         return conv_arg;
5726 }
5727
5728 static int
5729 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
5730                                         MonoMarshalSpec *spec, 
5731                                         int conv_arg, MonoType **conv_arg_type, 
5732                                         MarshalAction action)
5733 {
5734         MonoMethodBuilder *mb = m->mb;
5735         MonoClass *klass;
5736         int pos = 0, pos2;
5737
5738         klass = t->data.klass;
5739
5740         switch (action) {
5741         case MARSHAL_ACTION_CONV_IN:
5742                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5743                         klass->blittable || klass->enumtype)
5744                         break;
5745
5746                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5747                         
5748                 /* store the address of the source into local variable 0 */
5749                 if (t->byref)
5750                         mono_mb_emit_ldarg (mb, argnum);
5751                 else
5752                         mono_mb_emit_ldarg_addr (mb, argnum);
5753                 
5754                 mono_mb_emit_stloc (mb, 0);
5755                         
5756                 /* allocate space for the native struct and
5757                  * store the address into local variable 1 (dest) */
5758                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5759                 mono_mb_emit_byte (mb, CEE_PREFIX1);
5760                 mono_mb_emit_byte (mb, CEE_LOCALLOC);
5761                 mono_mb_emit_stloc (mb, conv_arg);
5762
5763                 if (t->byref) {
5764                         mono_mb_emit_ldloc (mb, 0);
5765                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5766                 }
5767
5768                 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
5769                         /* set dst_ptr */
5770                         mono_mb_emit_ldloc (mb, conv_arg);
5771                         mono_mb_emit_stloc (mb, 1);
5772
5773                         /* emit valuetype conversion code */
5774                         emit_struct_conv (mb, klass, FALSE);
5775                 }
5776
5777                 if (t->byref)
5778                         mono_mb_patch_branch (mb, pos);
5779                 break;
5780
5781         case MARSHAL_ACTION_PUSH:
5782                 if (spec && spec->native == MONO_NATIVE_LPSTRUCT) {
5783                         /* FIXME: */
5784                         g_assert (!t->byref);
5785
5786                         /* Have to change the signature since the vtype is passed byref */
5787                         m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
5788
5789                         if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5790                                 klass->blittable || klass->enumtype)
5791                                 mono_mb_emit_ldarg_addr (mb, argnum);
5792                         else
5793                                 mono_mb_emit_ldloc (mb, conv_arg);
5794                         break;
5795                 }
5796
5797                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5798                         klass->blittable || klass->enumtype) {
5799                         mono_mb_emit_ldarg (mb, argnum);
5800                         break;
5801                 }                       
5802                 mono_mb_emit_ldloc (mb, conv_arg);
5803                 if (!t->byref) {
5804                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5805                         mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass);
5806                 }
5807                 break;
5808
5809         case MARSHAL_ACTION_CONV_OUT:
5810                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5811                         klass->blittable || klass->enumtype)
5812                         break;
5813
5814                 if (t->byref) {
5815                         /* dst = argument */
5816                         mono_mb_emit_ldarg (mb, argnum);
5817                         mono_mb_emit_stloc (mb, 1);
5818
5819                         mono_mb_emit_ldloc (mb, 1);
5820                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5821
5822                         if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
5823                                 /* src = tmp_locals [i] */
5824                                 mono_mb_emit_ldloc (mb, conv_arg);
5825                                 mono_mb_emit_stloc (mb, 0);
5826
5827                                 /* emit valuetype conversion code */
5828                                 emit_struct_conv (mb, klass, TRUE);
5829                         }
5830                 }
5831
5832                 emit_struct_free (mb, klass, conv_arg);
5833                 
5834                 if (t->byref)
5835                         mono_mb_patch_branch (mb, pos);
5836                 break;
5837
5838         case MARSHAL_ACTION_CONV_RESULT:
5839                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5840                         klass->blittable) {
5841                         mono_mb_emit_stloc (mb, 3);
5842                         break;
5843                 }
5844                 /* load pointer to returned value type */
5845                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5846                 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
5847                 /* store the address of the source into local variable 0 */
5848                 mono_mb_emit_stloc (mb, 0);
5849                 /* set dst_ptr */
5850                 mono_mb_emit_ldloc_addr (mb, 3);
5851                 mono_mb_emit_stloc (mb, 1);
5852                                 
5853                 /* emit valuetype conversion code */
5854                 emit_struct_conv (mb, klass, TRUE);
5855                 break;
5856
5857         case MARSHAL_ACTION_MANAGED_CONV_IN:
5858                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5859                         klass->blittable || klass->enumtype) {
5860                         conv_arg = 0;
5861                         break;
5862                 }
5863
5864                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
5865
5866                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5867                         break;
5868
5869                 if (t->byref) 
5870                         mono_mb_emit_ldarg (mb, argnum);
5871                 else
5872                         mono_mb_emit_ldarg_addr (mb, argnum);
5873                 mono_mb_emit_stloc (mb, 0);
5874
5875                 if (t->byref) {
5876                         mono_mb_emit_ldloc (mb, 0);
5877                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5878                 }                       
5879
5880                 mono_mb_emit_ldloc_addr (mb, conv_arg);
5881                 mono_mb_emit_stloc (mb, 1);
5882
5883                 /* emit valuetype conversion code */
5884                 emit_struct_conv (mb, klass, TRUE);
5885
5886                 if (t->byref)
5887                         mono_mb_patch_branch (mb, pos);
5888                 break;
5889
5890         case MARSHAL_ACTION_MANAGED_CONV_OUT:
5891                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5892                         klass->blittable || klass->enumtype) {
5893                         break;
5894                 }
5895
5896                 /* Check for null */
5897                 mono_mb_emit_ldarg (mb, argnum);
5898                 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5899
5900                 /* Set src */
5901                 mono_mb_emit_ldloc_addr (mb, conv_arg);
5902                 mono_mb_emit_stloc (mb, 0);
5903
5904                 /* Set dest */
5905                 mono_mb_emit_ldarg (mb, argnum);
5906                 mono_mb_emit_stloc (mb, 1);
5907
5908                 /* emit valuetype conversion code */
5909                 emit_struct_conv (mb, klass, FALSE);
5910
5911                 mono_mb_patch_branch (mb, pos2);
5912                 break;
5913
5914         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5915                 if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
5916                         klass->blittable || klass->enumtype) {
5917                         mono_mb_emit_stloc (mb, 3);
5918                         m->retobj_var = 0;
5919                         break;
5920                 }
5921                         
5922                 /* load pointer to returned value type */
5923                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5924                 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
5925                         
5926                 /* store the address of the source into local variable 0 */
5927                 mono_mb_emit_stloc (mb, 0);
5928                 /* allocate space for the native struct and
5929                  * store the address into dst_ptr */
5930                 m->retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5931                 m->retobj_class = klass;
5932                 g_assert (m->retobj_var);
5933                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5934                 mono_mb_emit_byte (mb, CEE_CONV_I);
5935                 mono_mb_emit_icall (mb, mono_marshal_alloc);
5936                 mono_mb_emit_stloc (mb, 1);
5937                 mono_mb_emit_ldloc (mb, 1);
5938                 mono_mb_emit_stloc (mb, m->retobj_var);
5939
5940                 /* emit valuetype conversion code */
5941                 emit_struct_conv (mb, klass, FALSE);
5942                 break;
5943
5944         default:
5945                 g_assert_not_reached ();
5946         }
5947
5948         return conv_arg;
5949 }
5950
5951 static int
5952 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
5953                                          MonoMarshalSpec *spec, 
5954                                          int conv_arg, MonoType **conv_arg_type, 
5955                                          MarshalAction action)
5956 {
5957         MonoMethodBuilder *mb = m->mb;
5958         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5959         MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
5960         gboolean need_free;
5961
5962         switch (action) {
5963         case MARSHAL_ACTION_CONV_IN:
5964                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5965                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5966
5967                 if (t->byref) {
5968                         if (t->attrs & PARAM_ATTRIBUTE_OUT)
5969                                 break;
5970
5971                         mono_mb_emit_ldarg (mb, argnum);
5972                         mono_mb_emit_byte (mb, CEE_LDIND_I);                            
5973                 } else {
5974                         mono_mb_emit_ldarg (mb, argnum);
5975                 }
5976
5977                 if (conv == -1) {
5978                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5979                         MonoException *exc = mono_get_exception_not_implemented (msg);
5980                         g_warning (msg);
5981                         g_free (msg);
5982                         mono_raise_exception (exc);
5983                 }
5984                 else
5985                         mono_mb_emit_icall (mb, conv_to_icall (conv));
5986
5987                 mono_mb_emit_stloc (mb, conv_arg);
5988                 break;
5989
5990         case MARSHAL_ACTION_CONV_OUT:
5991                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
5992                         mono_mb_emit_ldarg (mb, argnum);
5993                         mono_mb_emit_ldloc (mb, conv_arg);
5994                         if (conv == MONO_MARSHAL_CONV_STR_BSTR) {
5995                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_BSTR_STR));
5996                                 // BSTRs always need freed
5997                                 mono_mb_emit_ldloc (mb, conv_arg);
5998                                 mono_mb_emit_icall (mb, mono_free_bstr);
5999                         }
6000                         else
6001                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR));
6002                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6003                 } else {
6004                         if (mono_marshal_need_free (t, m->piinfo, spec)) {
6005                                 mono_mb_emit_ldloc (mb, conv_arg);
6006                                 if (conv == MONO_MARSHAL_CONV_STR_BSTR)
6007                                         mono_mb_emit_icall (mb, mono_free_bstr);
6008                                 else
6009                                         mono_mb_emit_icall (mb, mono_marshal_free);
6010                         }
6011                 }
6012                 break;
6013
6014         case MARSHAL_ACTION_PUSH:
6015                 if (t->byref)
6016                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6017                 else
6018                         mono_mb_emit_ldloc (mb, conv_arg);
6019                 break;
6020
6021         case MARSHAL_ACTION_CONV_RESULT:
6022                 mono_mb_emit_stloc (mb, 0);
6023                                 
6024                 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6025                 if (conv == -1) {
6026                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6027                         mono_mb_emit_exception_marshal_directive (mb, msg);
6028                         break;
6029                 }
6030
6031                 mono_mb_emit_ldloc (mb, 0);
6032                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6033                 mono_mb_emit_stloc (mb, 3);
6034
6035                 /* free the string */
6036                 mono_mb_emit_ldloc (mb, 0);
6037                 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
6038                         mono_mb_emit_icall (mb, mono_free_bstr);
6039                 else
6040                         mono_mb_emit_icall (mb, g_free);
6041                 break;
6042
6043         case MARSHAL_ACTION_MANAGED_CONV_IN:
6044                 if (t->byref) {
6045                         conv_arg = 0;
6046                         break;
6047                 }
6048
6049                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6050                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6051
6052                 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6053                 if (conv == -1) {
6054                         char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
6055                         mono_mb_emit_exception_marshal_directive (mb, msg);
6056                         break;
6057                 }
6058
6059                 mono_mb_emit_ldarg (mb, argnum);
6060                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6061                 mono_mb_emit_stloc (mb, conv_arg);
6062                 break;  
6063
6064         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6065                 if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
6066                         /* We need to make a copy so the caller is able to free it */
6067                         mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
6068                 else
6069                         mono_mb_emit_icall (mb, conv_to_icall (conv));
6070                 mono_mb_emit_stloc (mb, 3);
6071                 break;
6072
6073         default:
6074                 g_assert_not_reached ();
6075         }
6076
6077         return conv_arg;
6078 }
6079
6080 static int
6081 emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t, 
6082                          MonoMarshalSpec *spec, int conv_arg, 
6083                          MonoType **conv_arg_type, MarshalAction action)
6084 {
6085         MonoMethodBuilder *mb = m->mb;
6086
6087         switch (action){
6088         case MARSHAL_ACTION_CONV_IN: {
6089                 MonoType *intptr_type;
6090                 int dar_release_slot, pos;
6091
6092                 intptr_type = &mono_defaults.int_class->byval_arg;
6093                 conv_arg = mono_mb_add_local (mb, intptr_type);
6094                 *conv_arg_type = intptr_type;
6095
6096                 if (!sh_dangerous_add_ref)
6097                         init_safe_handle ();
6098
6099                 mono_mb_emit_ldarg (mb, argnum);
6100                 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6101                 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
6102                 
6103                 mono_mb_patch_branch (mb, pos);
6104                 if (t->byref){
6105                         /*
6106                          * My tests in show that ref SafeHandles are not really
6107                          * passed as ref objects.  Instead a NULL is passed as the
6108                          * value of the ref
6109                          */
6110                         mono_mb_emit_icon (mb, 0);
6111                         mono_mb_emit_stloc (mb, conv_arg);
6112                         break;
6113                 } 
6114
6115                 /* Create local to hold the ref parameter to DangerousAddRef */
6116                 dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
6117
6118                 /* set release = false; */
6119                 mono_mb_emit_icon (mb, 0);
6120                 mono_mb_emit_stloc (mb, dar_release_slot);
6121
6122                 /* safehandle.DangerousAddRef (ref release) */
6123                 mono_mb_emit_ldarg (mb, argnum);
6124                 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
6125                 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
6126
6127                 /* Pull the handle field from SafeHandle */
6128                 mono_mb_emit_ldarg (mb, argnum);
6129                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6130                 mono_mb_emit_byte (mb, CEE_LDIND_I);
6131                 mono_mb_emit_stloc (mb, conv_arg);
6132
6133                 break;
6134         }
6135
6136         case MARSHAL_ACTION_PUSH:
6137                 if (t->byref)
6138                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6139                 else 
6140                         mono_mb_emit_ldloc (mb, conv_arg);
6141                 break;
6142
6143         case MARSHAL_ACTION_CONV_OUT: {
6144                 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
6145                 int dar_release_slot = conv_arg + 1;
6146                 int label_next;
6147
6148                 if (!sh_dangerous_release)
6149                         init_safe_handle ();
6150
6151                 if (t->byref){
6152                         MonoMethod *ctor;
6153                         
6154                         /*
6155                          * My tests indicate that ref SafeHandles parameters are not actually
6156                          * passed by ref, but instead a new Handle is created regardless of
6157                          * whether a change happens in the unmanaged side.
6158                          *
6159                          * Also, the Handle is created before calling into unmanaged code,
6160                          * but we do not support that mechanism (getting to the original
6161                          * handle) and it makes no difference where we create this
6162                          */
6163                         ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
6164                         if (ctor == NULL){
6165                                 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
6166                                 break;
6167                         }
6168                         /* refval = new SafeHandleDerived ()*/
6169                         mono_mb_emit_ldarg (mb, argnum);
6170                         mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
6171                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6172
6173                         /* refval.handle = returned_handle */
6174                         mono_mb_emit_ldarg (mb, argnum);
6175                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6176                         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6177                         mono_mb_emit_ldloc (mb, conv_arg);
6178                         mono_mb_emit_byte (mb, CEE_STIND_I);
6179                 } else {
6180                         mono_mb_emit_ldloc (mb, dar_release_slot);
6181                         label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
6182                         mono_mb_emit_ldarg (mb, argnum);
6183                         mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
6184                         mono_mb_patch_branch (mb, label_next);
6185                 }
6186                 break;
6187         }
6188                 
6189         case MARSHAL_ACTION_CONV_RESULT: {
6190                 MonoMethod *ctor = NULL;
6191                 int intptr_handle_slot;
6192                 
6193                 if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
6194                         mono_mb_emit_byte (mb, CEE_POP);
6195                         mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract");
6196                         break;
6197                 }
6198
6199                 ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
6200                 if (ctor == NULL){
6201                         mono_mb_emit_byte (mb, CEE_POP);
6202                         mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
6203                         break;
6204                 }
6205                 /* Store the IntPtr results into a local */
6206                 intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6207                 mono_mb_emit_stloc (mb, intptr_handle_slot);
6208
6209                 /* Create return value */
6210                 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
6211                 mono_mb_emit_stloc (mb, 3);
6212
6213                 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
6214                 mono_mb_emit_ldloc (mb, 3);
6215                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
6216                 mono_mb_emit_ldloc (mb, intptr_handle_slot);
6217                 mono_mb_emit_byte (mb, CEE_STIND_I);
6218                 break;
6219         }
6220                 
6221         case MARSHAL_ACTION_MANAGED_CONV_IN:
6222                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6223                 break;
6224                 
6225         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6226                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6227                 break;
6228
6229         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6230                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6231                 break;
6232         default:
6233                 printf ("Unhandled case for MarshalAction: %d\n", action);
6234         }
6235
6236         return conv_arg;
6237 }
6238
6239 static int
6240 emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t, 
6241                         MonoMarshalSpec *spec, int conv_arg, 
6242                         MonoType **conv_arg_type, MarshalAction action)
6243 {
6244         MonoMethodBuilder *mb = m->mb;
6245
6246         switch (action){
6247         case MARSHAL_ACTION_CONV_IN: {
6248                 MonoType *intptr_type;
6249
6250                 intptr_type = &mono_defaults.int_class->byval_arg;
6251                 conv_arg = mono_mb_add_local (mb, intptr_type);
6252                 *conv_arg_type = intptr_type;
6253
6254                 if (t->byref){
6255                         mono_mb_emit_exception_marshal_directive (mb,
6256                                 "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6257                         break;
6258                 } 
6259                 mono_mb_emit_ldarg_addr (mb, argnum);
6260                 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
6261                 mono_mb_emit_byte (mb, CEE_ADD);
6262                 mono_mb_emit_byte (mb, CEE_LDIND_I);
6263                 mono_mb_emit_stloc (mb, conv_arg);
6264                 break;
6265         }
6266
6267         case MARSHAL_ACTION_PUSH:
6268                 mono_mb_emit_ldloc (mb, conv_arg);
6269                 break;
6270
6271         case MARSHAL_ACTION_CONV_OUT: {
6272                 /* no resource release required */
6273                 break;
6274         }
6275                 
6276         case MARSHAL_ACTION_CONV_RESULT: {
6277                 mono_mb_emit_exception_marshal_directive (mb,
6278                         "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6279                 break;
6280         }
6281                 
6282         case MARSHAL_ACTION_MANAGED_CONV_IN:
6283                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6284                 break;
6285                 
6286         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6287                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6288                 break;
6289
6290         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6291                 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6292                 break;
6293         default:
6294                 fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
6295         }
6296
6297         return conv_arg;
6298 }
6299
6300 static int
6301 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
6302                      MonoMarshalSpec *spec, 
6303                      int conv_arg, MonoType **conv_arg_type, 
6304                      MarshalAction action)
6305 {
6306         MonoMethodBuilder *mb = m->mb;
6307         MonoClass *klass = t->data.klass;
6308         int pos, pos2, loc;
6309
6310         if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
6311                 mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
6312         }
6313
6314         switch (action) {
6315         case MARSHAL_ACTION_CONV_IN:
6316                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6317                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6318
6319                 m->orig_conv_args [argnum] = 0;
6320                 
6321                 if (klass->delegate) {
6322                         if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6323                                 char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented.");
6324                                 mono_mb_emit_exception_marshal_directive (mb, msg);
6325                         } else {
6326                                 mono_mb_emit_ldarg (mb, argnum);
6327                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
6328                                 mono_mb_emit_stloc (mb, conv_arg);
6329                         }
6330                 } else if (klass == mono_defaults.stringbuilder_class) {
6331                         MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6332                         MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
6333                         
6334                         g_assert (!t->byref);
6335                         mono_mb_emit_ldarg (mb, argnum);
6336
6337                         if (conv != -1)
6338                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
6339                         else {
6340                                 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
6341                                 MonoException *exc = mono_get_exception_not_implemented (msg);
6342                                 g_warning (msg);
6343                                 g_free (msg);
6344                                 mono_raise_exception (exc);
6345                         }
6346
6347                         mono_mb_emit_stloc (mb, conv_arg);
6348                 } else if (klass->blittable) {
6349                         mono_mb_emit_byte (mb, CEE_LDNULL);
6350                         mono_mb_emit_stloc (mb, conv_arg);
6351
6352                         mono_mb_emit_ldarg (mb, argnum);
6353                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6354
6355                         mono_mb_emit_ldarg (mb, argnum);
6356                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6357                         mono_mb_emit_stloc (mb, conv_arg);
6358
6359                         mono_mb_patch_branch (mb, pos);
6360                         break;
6361                 } else {
6362                         mono_mb_emit_byte (mb, CEE_LDNULL);
6363                         mono_mb_emit_stloc (mb, conv_arg);
6364
6365                         if (t->byref) {
6366                                 /* we dont need any conversions for out parameters */
6367                                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6368                                         break;
6369
6370                                 mono_mb_emit_ldarg (mb, argnum);                                
6371                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
6372
6373                         } else {
6374                                 mono_mb_emit_ldarg (mb, argnum);
6375                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6376                                 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
6377                         }
6378                                 
6379                         /* store the address of the source into local variable 0 */
6380                         mono_mb_emit_stloc (mb, 0);
6381                         mono_mb_emit_ldloc (mb, 0);
6382                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6383
6384                         /* allocate space for the native struct and store the address */
6385                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6386                         mono_mb_emit_byte (mb, CEE_PREFIX1);
6387                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
6388                         mono_mb_emit_stloc (mb, conv_arg);
6389
6390                         if (t->byref) {
6391                                 /* Need to store the original buffer so we can free it later */
6392                                 m->orig_conv_args [argnum] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6393                                 mono_mb_emit_ldloc (mb, conv_arg);
6394                                 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
6395                         }
6396
6397                         /* set the src_ptr */
6398                         mono_mb_emit_ldloc (mb, 0);
6399                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6400                         mono_mb_emit_stloc (mb, 0);
6401
6402                         /* set dst_ptr */
6403                         mono_mb_emit_ldloc (mb, conv_arg);
6404                         mono_mb_emit_stloc (mb, 1);
6405
6406                         /* emit valuetype conversion code */
6407                         emit_struct_conv (mb, klass, FALSE);
6408
6409                         mono_mb_patch_branch (mb, pos);
6410                 }
6411                 break;
6412
6413         case MARSHAL_ACTION_CONV_OUT:
6414                 if (klass == mono_defaults.stringbuilder_class) {
6415                         gboolean need_free;
6416                         MonoMarshalNative encoding;
6417                         MonoMarshalConv conv;
6418
6419                         encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6420                         conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
6421
6422                         g_assert (!t->byref);
6423                         g_assert (encoding != -1);
6424
6425                         mono_mb_emit_ldarg (mb, argnum);
6426                         mono_mb_emit_ldloc (mb, conv_arg);
6427
6428                         mono_mb_emit_icall (mb, conv_to_icall (conv));
6429
6430                         if (need_free) {
6431                                 mono_mb_emit_ldloc (mb, conv_arg);
6432                                 mono_mb_emit_icall (mb, mono_marshal_free);
6433                         }
6434                         break;
6435                 }
6436
6437                 if (klass->delegate) {
6438                         if (t->byref) {
6439                                 mono_mb_emit_ldarg (mb, argnum);
6440                                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6441                                 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6442                                 mono_mb_emit_ldloc (mb, conv_arg);
6443                                 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6444                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
6445                         }
6446                         break;
6447                 }
6448
6449                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6450                         /* allocate a new object */
6451                         mono_mb_emit_ldarg (mb, argnum);
6452                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6453                         mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, t->data.klass);
6454                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6455                 }
6456
6457                 /* dst = *argument */
6458                 mono_mb_emit_ldarg (mb, argnum);
6459
6460                 if (t->byref)
6461                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6462
6463                 mono_mb_emit_stloc (mb, 1);
6464
6465                 mono_mb_emit_ldloc (mb, 1);
6466                 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6467
6468                 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6469                         mono_mb_emit_ldloc (mb, 1);
6470                         mono_mb_emit_icon (mb, sizeof (MonoObject));
6471                         mono_mb_emit_byte (mb, CEE_ADD);
6472                         mono_mb_emit_stloc (mb, 1);
6473                         
6474                         /* src = tmp_locals [i] */
6475                         mono_mb_emit_ldloc (mb, conv_arg);
6476                         mono_mb_emit_stloc (mb, 0);
6477
6478                         /* emit valuetype conversion code */
6479                         emit_struct_conv (mb, t->data.klass, TRUE);
6480
6481                         /* Free the structure returned by the native code */
6482                         emit_struct_free (mb, klass, conv_arg);
6483
6484                         if (m->orig_conv_args [argnum]) {
6485                                 /* 
6486                                  * If the native function changed the pointer, then free
6487                                  * the original structure plus the new pointer.
6488                                  */
6489                                 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
6490                                 mono_mb_emit_ldloc (mb, conv_arg);
6491                                 pos2 = mono_mb_emit_branch (mb, CEE_BEQ);
6492
6493                                 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6494                                         g_assert (m->orig_conv_args [argnum]);
6495
6496                                         emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
6497                                 }
6498
6499                                 mono_mb_emit_ldloc (mb, conv_arg);
6500                                 mono_mb_emit_icall (mb, g_free);
6501
6502                                 mono_mb_patch_branch (mb, pos2);
6503                         }
6504                 }
6505                 else
6506                         /* Free the original structure passed to native code */
6507                         emit_struct_free (mb, klass, conv_arg);
6508
6509                 mono_mb_patch_branch (mb, pos);
6510                 break;
6511
6512         case MARSHAL_ACTION_PUSH:
6513                 if (t->byref)
6514                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6515                 else
6516                         mono_mb_emit_ldloc (mb, conv_arg);
6517                 break;
6518
6519         case MARSHAL_ACTION_CONV_RESULT:
6520                 if (klass->delegate) {
6521                         g_assert (!t->byref);
6522                         mono_mb_emit_stloc (mb, 0);
6523                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6524                         mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6525                         mono_mb_emit_ldloc (mb, 0);
6526                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6527                         mono_mb_emit_stloc (mb, 3);
6528                 } else {
6529                         /* set src */
6530                         mono_mb_emit_stloc (mb, 0);
6531         
6532                         /* Make a copy since emit_conv modifies local 0 */
6533                         loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6534                         mono_mb_emit_ldloc (mb, 0);
6535                         mono_mb_emit_stloc (mb, loc);
6536         
6537                         mono_mb_emit_byte (mb, CEE_LDNULL);
6538                         mono_mb_emit_stloc (mb, 3);
6539         
6540                         mono_mb_emit_ldloc (mb, 0);
6541                         pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6542         
6543                         /* allocate result object */
6544         
6545                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6546                         mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);   
6547                         mono_mb_emit_stloc (mb, 3);
6548                                         
6549                         /* set dst  */
6550         
6551                         mono_mb_emit_ldloc (mb, 3);
6552                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6553                         mono_mb_emit_stloc (mb, 1);
6554                                                                 
6555                         /* emit conversion code */
6556                         emit_struct_conv (mb, klass, TRUE);
6557         
6558                         emit_struct_free (mb, klass, loc);
6559         
6560                         /* Free the pointer allocated by unmanaged code */
6561                         mono_mb_emit_ldloc (mb, loc);
6562                         mono_mb_emit_icall (mb, g_free);
6563                         mono_mb_patch_branch (mb, pos);
6564                 }
6565                 break;
6566
6567         case MARSHAL_ACTION_MANAGED_CONV_IN:
6568                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
6569
6570                 if (klass->delegate) {
6571                         g_assert (!t->byref);
6572                         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6573                         mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6574                         mono_mb_emit_ldarg (mb, argnum);
6575                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
6576                         mono_mb_emit_stloc (mb, conv_arg);
6577                         break;
6578                 }
6579
6580                 /* The class can not have an automatic layout */
6581                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
6582                         mono_mb_emit_auto_layout_exception (mb, klass);
6583                         break;
6584                 }
6585
6586                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
6587                         mono_mb_emit_byte (mb, CEE_LDNULL);
6588                         mono_mb_emit_stloc (mb, conv_arg);
6589                         break;
6590                 }
6591
6592                 /* Set src */
6593                 mono_mb_emit_ldarg (mb, argnum);
6594                 if (t->byref) {
6595                         int pos2;
6596
6597                         /* Check for NULL and raise an exception */
6598                         pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
6599
6600                         mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
6601
6602                         mono_mb_patch_branch (mb, pos2);
6603                         mono_mb_emit_ldarg (mb, argnum);
6604                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6605                 }                               
6606
6607                 mono_mb_emit_stloc (mb, 0);
6608
6609                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6610                 mono_mb_emit_stloc (mb, conv_arg);
6611
6612                 mono_mb_emit_ldloc (mb, 0);
6613                 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6614
6615                 /* Create and set dst */
6616                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6617                 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);   
6618                 mono_mb_emit_stloc (mb, conv_arg);
6619                 mono_mb_emit_ldloc (mb, conv_arg);
6620                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6621                 mono_mb_emit_stloc (mb, 1); 
6622
6623                 /* emit valuetype conversion code */
6624                 emit_struct_conv (mb, klass, TRUE);
6625
6626                 mono_mb_patch_branch (mb, pos);
6627                 break;
6628
6629         case MARSHAL_ACTION_MANAGED_CONV_OUT:
6630                 if (t->byref) {
6631                         /* Check for null */
6632                         mono_mb_emit_ldloc (mb, conv_arg);
6633                         pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6634                         mono_mb_emit_ldarg (mb, argnum);
6635                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6636                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6637                         pos2 = mono_mb_emit_branch (mb, CEE_BR);
6638
6639                         mono_mb_patch_branch (mb, pos);                 
6640                         
6641                         /* Set src */
6642                         mono_mb_emit_ldloc (mb, conv_arg);
6643                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6644                         mono_mb_emit_stloc (mb, 0);
6645
6646                         /* Allocate and set dest */
6647                         mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6648                         mono_mb_emit_byte (mb, CEE_CONV_I);
6649                         mono_mb_emit_icall (mb, mono_marshal_alloc);
6650                         mono_mb_emit_stloc (mb, 1);
6651                         
6652                         /* Update argument pointer */
6653                         mono_mb_emit_ldarg (mb, argnum);
6654                         mono_mb_emit_ldloc (mb, 1);
6655                         mono_mb_emit_byte (mb, CEE_STIND_I);
6656                 
6657                         /* emit valuetype conversion code */
6658                         emit_struct_conv (mb, klass, FALSE);
6659
6660                         mono_mb_patch_branch (mb, pos2);
6661                 } else {
6662                         /* byval [Out] marshalling */
6663
6664                         /* FIXME: Handle null */
6665
6666                         /* Set src */
6667                         mono_mb_emit_ldloc (mb, conv_arg);
6668                         mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6669                         mono_mb_emit_stloc (mb, 0);
6670
6671                         /* Set dest */
6672                         mono_mb_emit_ldarg (mb, argnum);
6673                         mono_mb_emit_stloc (mb, 1);
6674                         
6675                         /* emit valuetype conversion code */
6676                         emit_struct_conv (mb, klass, FALSE);
6677                 }                       
6678                 break;
6679
6680         case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6681                 if (klass->delegate) {
6682                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
6683                         mono_mb_emit_stloc (mb, 3);
6684                         break;
6685                 }
6686
6687                 /* The class can not have an automatic layout */
6688                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
6689                         mono_mb_emit_auto_layout_exception (mb, klass);
6690                         break;
6691                 }
6692
6693                 mono_mb_emit_stloc (mb, 0);
6694                 /* Check for null */
6695                 mono_mb_emit_ldloc (mb, 0);
6696                 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6697                 mono_mb_emit_byte (mb, CEE_LDNULL);
6698                 mono_mb_emit_stloc (mb, 3);
6699                 pos2 = mono_mb_emit_branch (mb, CEE_BR);
6700
6701                 mono_mb_patch_branch (mb, pos);
6702
6703                 /* Set src */
6704                 mono_mb_emit_ldloc (mb, 0);
6705                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6706                 mono_mb_emit_stloc (mb, 0);
6707
6708                 /* Allocate and set dest */
6709                 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6710                 mono_mb_emit_byte (mb, CEE_CONV_I);
6711                 mono_mb_emit_icall (mb, mono_marshal_alloc);
6712                 mono_mb_emit_byte (mb, CEE_DUP);
6713                 mono_mb_emit_stloc (mb, 1);
6714                 mono_mb_emit_stloc (mb, 3);
6715
6716                 emit_struct_conv (mb, klass, FALSE);
6717
6718                 mono_mb_patch_branch (mb, pos2);
6719                 break;
6720
6721         default:
6722                 g_assert_not_reached ();
6723         }
6724
6725         return conv_arg;
6726 }
6727
6728 static int
6729 emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t,
6730                      MonoMarshalSpec *spec, 
6731                      int conv_arg, MonoType **conv_arg_type, 
6732                      MarshalAction action)
6733 {
6734         MonoMethodBuilder *mb = m->mb;
6735         MonoClass *klass = t->data.klass;
6736         static MonoMethod* get_object_for_iunknown = NULL;
6737         static MonoMethod* get_iunknown_for_object_internal = NULL;
6738         static MonoMethod* get_com_interface_for_object_internal = NULL;
6739         static MonoMethod* get_idispatch_for_object_internal = NULL;
6740         static MonoMethod* marshal_release = NULL;
6741         static MonoMethod* AddRef = NULL;
6742         if (!get_object_for_iunknown)
6743                 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
6744         if (!get_iunknown_for_object_internal)
6745                 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
6746         if (!get_idispatch_for_object_internal)
6747                 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
6748         if (!get_com_interface_for_object_internal)
6749                 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
6750         if (!marshal_release)
6751                 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
6752
6753         /* COM types are initialized lazily */
6754         mono_init_com_types ();
6755
6756         switch (action) {
6757         case MARSHAL_ACTION_CONV_IN: {
6758                 guint32 pos_null = 0;
6759
6760                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6761                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6762
6763                 mono_mb_emit_ptr (mb, NULL);
6764                 mono_mb_emit_stloc (mb, conv_arg);      
6765
6766                 /* we dont need any conversions for out parameters */
6767                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
6768                         break;
6769
6770                 mono_mb_emit_ldarg (mb, argnum);        
6771                 if (t->byref)
6772                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6773                 /* if null just break, conv arg was already inited to 0 */
6774                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
6775
6776                 mono_mb_emit_ldarg (mb, argnum);
6777                 if (t->byref)
6778                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6779
6780                 if (klass && klass != mono_defaults.object_class) {
6781                         mono_mb_emit_ptr (mb, t);
6782                         mono_mb_emit_icall (mb, type_from_handle);
6783                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
6784                 }
6785                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
6786                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
6787                 else if (spec->native == MONO_NATIVE_IDISPATCH)
6788                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
6789                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
6790                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
6791                 else
6792                         g_assert_not_reached ();
6793                 mono_mb_emit_stloc (mb, conv_arg);
6794                 mono_mb_patch_short_branch (mb, pos_null);
6795                 break;
6796         }
6797
6798         case MARSHAL_ACTION_CONV_OUT: {
6799                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6800                         int ccw_obj;
6801                         guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
6802                         ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6803
6804                         mono_mb_emit_ldarg (mb, argnum);
6805                         mono_mb_emit_byte (mb, CEE_LDNULL);
6806                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6807
6808                         mono_mb_emit_ldloc (mb, conv_arg);
6809                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
6810
6811                         mono_mb_emit_ldloc (mb, conv_arg);
6812                         mono_mb_emit_icon (mb, TRUE);
6813                         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
6814                         mono_mb_emit_stloc (mb, ccw_obj);
6815                         mono_mb_emit_ldloc (mb, ccw_obj);
6816                         pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
6817
6818                         mono_mb_emit_ldarg (mb, argnum);
6819                         mono_mb_emit_ldloc (mb, conv_arg);
6820                         mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
6821
6822                         if (klass && klass != mono_defaults.object_class)
6823                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
6824                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6825
6826                         pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
6827
6828                         /* is already managed object */
6829                         mono_mb_patch_short_branch (mb, pos_ccw);
6830                         mono_mb_emit_ldarg (mb, argnum);
6831                         mono_mb_emit_ldloc (mb, ccw_obj);
6832
6833                         if (klass && klass != mono_defaults.object_class)
6834                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
6835                         mono_mb_emit_byte (mb, CEE_STIND_REF);
6836
6837                         mono_mb_patch_short_branch (mb, pos_end);
6838
6839                         /* need to call Release to follow COM rules of ownership */
6840                         mono_mb_emit_ldloc (mb, conv_arg);
6841                         mono_mb_emit_managed_call (mb, marshal_release, NULL);
6842                         mono_mb_emit_byte (mb, CEE_POP);
6843
6844                         /* case if null */
6845                         mono_mb_patch_short_branch (mb, pos_null);
6846                 }
6847                 break;
6848         }
6849         case MARSHAL_ACTION_PUSH:
6850                 if (t->byref)
6851                         mono_mb_emit_ldloc_addr (mb, conv_arg);
6852                 else
6853                         mono_mb_emit_ldloc (mb, conv_arg);
6854                 break;
6855
6856         case MARSHAL_ACTION_CONV_RESULT: {
6857                 int ccw_obj, ret_ptr;
6858                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
6859                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6860                 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6861
6862                 /* store return value */
6863                 mono_mb_emit_stloc (mb, ret_ptr);
6864
6865                 mono_mb_emit_ldloc (mb, ret_ptr);
6866                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
6867
6868                 mono_mb_emit_ldloc (mb, ret_ptr);
6869                 mono_mb_emit_icon (mb, TRUE);
6870                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
6871                 mono_mb_emit_stloc (mb, ccw_obj);
6872                 mono_mb_emit_ldloc (mb, ccw_obj);
6873                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
6874
6875                 mono_mb_emit_ldloc (mb, ret_ptr);
6876                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
6877
6878                 if (klass && klass != mono_defaults.object_class)
6879                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
6880                 mono_mb_emit_stloc (mb, 3);
6881
6882                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
6883
6884                 /* is already managed object */
6885                 mono_mb_patch_short_branch (mb, pos_ccw);
6886                 mono_mb_emit_ldloc (mb, ccw_obj);
6887
6888                 if (klass && klass != mono_defaults.object_class)
6889                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
6890                 mono_mb_emit_stloc (mb, 3);
6891
6892                 mono_mb_patch_short_branch (mb, pos_end);
6893
6894                 /* need to call Release to follow COM rules of ownership */
6895                 mono_mb_emit_ldloc (mb, ret_ptr);
6896                 mono_mb_emit_managed_call (mb, marshal_release, NULL);
6897                 mono_mb_emit_byte (mb, CEE_POP);
6898
6899                 /* case if null */
6900                 mono_mb_patch_short_branch (mb, pos_null);
6901                 break;
6902         } 
6903
6904         case MARSHAL_ACTION_MANAGED_CONV_IN: {
6905                 int ccw_obj;
6906                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
6907                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6908
6909                 klass = mono_class_from_mono_type (t);
6910                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
6911                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6912
6913                 mono_mb_emit_byte (mb, CEE_LDNULL);
6914                 mono_mb_emit_stloc (mb, conv_arg);
6915                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
6916                         break;
6917
6918                 mono_mb_emit_ldarg (mb, argnum);
6919                 if (t->byref)
6920                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6921                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
6922
6923                 mono_mb_emit_ldarg (mb, argnum);
6924                 if (t->byref)
6925                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6926                 mono_mb_emit_icon (mb, TRUE);
6927                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
6928                 mono_mb_emit_stloc (mb, ccw_obj);
6929                 mono_mb_emit_ldloc (mb, ccw_obj);
6930                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
6931
6932
6933                 mono_mb_emit_ldarg (mb, argnum);
6934                 if (t->byref)
6935                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
6936                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
6937
6938                 if (klass && klass != mono_defaults.object_class)
6939                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
6940                 mono_mb_emit_stloc (mb, conv_arg);
6941                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
6942
6943                 /* is already managed object */
6944                 mono_mb_patch_short_branch (mb, pos_ccw);
6945                 mono_mb_emit_ldloc (mb, ccw_obj);
6946                 if (klass && klass != mono_defaults.object_class)
6947                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
6948                 mono_mb_emit_stloc (mb, conv_arg);
6949
6950                 mono_mb_patch_short_branch (mb, pos_end);
6951                 /* case if null */
6952                 mono_mb_patch_short_branch (mb, pos_null);
6953                 break;
6954         }
6955
6956         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
6957                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
6958                         guint32 pos_null = 0;
6959
6960                         if (!AddRef)
6961                                 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
6962
6963                         mono_mb_emit_ldloc (mb, conv_arg);      
6964                         /* if null just break, conv arg was already inited to 0 */
6965                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
6966
6967                         /* to store later */
6968                         mono_mb_emit_ldarg (mb, argnum);        
6969                         mono_mb_emit_ldloc (mb, conv_arg);
6970                         if (klass && klass != mono_defaults.object_class) {
6971                                 mono_mb_emit_ptr (mb, t);
6972                                 mono_mb_emit_icall (mb, type_from_handle);
6973                                 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
6974                         }
6975                         else if (spec->native == MONO_NATIVE_IUNKNOWN)
6976                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
6977                         else if (spec->native == MONO_NATIVE_IDISPATCH)
6978                                 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
6979                         else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
6980                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
6981                         else
6982                                 g_assert_not_reached ();
6983                         mono_mb_emit_byte (mb, CEE_STIND_I);
6984
6985                         mono_mb_emit_ldarg (mb, argnum);
6986                         mono_mb_emit_byte (mb, CEE_LDIND_I);
6987                         mono_mb_emit_managed_call (mb, AddRef, NULL);
6988                         mono_mb_emit_byte (mb, CEE_POP);
6989
6990                         mono_mb_patch_short_branch (mb, pos_null);
6991                 }
6992                 break;
6993         }
6994
6995         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
6996                 guint32 pos_null = 0;
6997                 int ccw_obj;
6998                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6999
7000                 if (!AddRef)
7001                         AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
7002
7003                 /* store return value */
7004                 mono_mb_emit_stloc (mb, ccw_obj);
7005
7006                 mono_mb_emit_ldloc (mb, ccw_obj);
7007
7008                 /* if null just break, conv arg was already inited to 0 */
7009                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
7010
7011                 /* to store later */
7012                 mono_mb_emit_ldloc (mb, ccw_obj);
7013                 if (klass && klass != mono_defaults.object_class) {
7014                         mono_mb_emit_ptr (mb, t);
7015                         mono_mb_emit_icall (mb, type_from_handle);
7016                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
7017                 }
7018                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
7019                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7020                 else if (spec->native == MONO_NATIVE_IDISPATCH)
7021                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
7022                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
7023                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
7024                 else
7025                         g_assert_not_reached ();
7026                 mono_mb_emit_stloc (mb, 3);
7027                 mono_mb_emit_ldloc (mb, 3);
7028                 
7029                 mono_mb_emit_managed_call (mb, AddRef, NULL);
7030                 mono_mb_emit_byte (mb, CEE_POP);
7031
7032                 mono_mb_patch_short_branch (mb, pos_null);
7033                 break;
7034         }
7035
7036         default:
7037                 g_assert_not_reached ();
7038         }
7039
7040         return conv_arg;
7041 }
7042
7043 static int
7044 emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
7045                      MonoMarshalSpec *spec, 
7046                      int conv_arg, MonoType **conv_arg_type, 
7047                      MarshalAction action)
7048 {
7049         MonoMethodBuilder *mb = m->mb;
7050         static MonoMethod *get_object_for_native_variant = NULL;
7051         static MonoMethod *get_native_variant_for_object = NULL;
7052
7053         mono_init_com_types ();
7054         
7055         if (!get_object_for_native_variant)
7056                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
7057         g_assert (get_object_for_native_variant);
7058
7059         if (!get_native_variant_for_object)
7060                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
7061         g_assert (get_native_variant_for_object);
7062
7063         switch (action) {
7064         case MARSHAL_ACTION_CONV_IN: {
7065                 conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
7066                 
7067                 if (t->byref)
7068                         *conv_arg_type = &mono_defaults.variant_class->this_arg;
7069                 else
7070                         *conv_arg_type = &mono_defaults.variant_class->byval_arg;
7071
7072                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
7073                         break;
7074
7075                 mono_mb_emit_ldarg (mb, argnum);
7076                 if (t->byref)
7077                         mono_mb_emit_byte(mb, CEE_LDIND_REF);
7078                 mono_mb_emit_ldloc_addr (mb, conv_arg);
7079                 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
7080                 break;
7081         }
7082
7083         case MARSHAL_ACTION_CONV_OUT: {
7084                 static MonoMethod *variant_clear = NULL;
7085
7086                 if (!variant_clear)
7087                         variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
7088                 g_assert (variant_clear);
7089
7090
7091                 if (t->byref) {
7092                         mono_mb_emit_ldarg (mb, argnum);
7093                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7094                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
7095                         mono_mb_emit_byte (mb, CEE_STIND_REF);
7096                 }
7097
7098                 mono_mb_emit_ldloc_addr (mb, conv_arg);
7099                 mono_mb_emit_managed_call (mb, variant_clear, NULL);
7100                 break;
7101         }
7102
7103         case MARSHAL_ACTION_PUSH:
7104                 if (t->byref)
7105                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7106                 else
7107                         mono_mb_emit_ldloc (mb, conv_arg);
7108                 break;
7109
7110         case MARSHAL_ACTION_CONV_RESULT: {
7111                 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
7112                 mono_mb_emit_exception_marshal_directive (mb, msg);
7113                 break;
7114         }
7115
7116         case MARSHAL_ACTION_MANAGED_CONV_IN: {
7117                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7118
7119                 if (t->byref)
7120                         *conv_arg_type = &mono_defaults.variant_class->this_arg;
7121                 else
7122                         *conv_arg_type = &mono_defaults.variant_class->byval_arg;
7123
7124                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
7125                         break;
7126
7127                 if (t->byref)
7128                         mono_mb_emit_ldarg (mb, argnum);
7129                 else
7130                         mono_mb_emit_ldarg_addr (mb, argnum);
7131                 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
7132                 mono_mb_emit_stloc (mb, conv_arg);
7133                 break;
7134         }
7135
7136         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7137                 if (t->byref) {
7138                         mono_mb_emit_ldloc (mb, conv_arg);
7139                         mono_mb_emit_ldarg (mb, argnum);
7140                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
7141                 }
7142                 break;
7143         }
7144
7145         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7146                 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
7147                 mono_mb_emit_exception_marshal_directive (mb, msg);
7148                 break;
7149         }
7150
7151         default:
7152                 g_assert_not_reached ();
7153         }
7154
7155         return conv_arg;
7156 }
7157
7158 static int
7159 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
7160                                         MonoMarshalSpec *spec, 
7161                                         int conv_arg, MonoType **conv_arg_type, 
7162                                         MarshalAction action)
7163 {
7164         MonoMethodBuilder *mb = m->mb;
7165         MonoClass *klass = mono_class_from_mono_type (t);
7166         gboolean need_convert, need_free;
7167         MonoMarshalNative encoding;
7168
7169         encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
7170
7171         switch (action) {
7172         case MARSHAL_ACTION_CONV_IN:
7173                 *conv_arg_type = &mono_defaults.object_class->byval_arg;
7174                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7175
7176                 if (klass->element_class->blittable) {
7177                         mono_mb_emit_ldarg (mb, argnum);
7178                         if (t->byref)
7179                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7180                         mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
7181                         mono_mb_emit_stloc (mb, conv_arg);
7182                 } else {
7183                         MonoClass *eklass;
7184                         guint32 label1, label2, label3;
7185                         int index_var, src_var, dest_ptr, esize;
7186                         MonoMarshalConv conv;
7187                         gboolean is_string = FALSE;
7188
7189                         dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7190
7191                         eklass = klass->element_class;
7192
7193                         if (eklass == mono_defaults.string_class) {
7194                                 is_string = TRUE;
7195                                 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7196                         }
7197                         else if (eklass == mono_defaults.stringbuilder_class) {
7198                                 is_string = TRUE;
7199                                 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
7200                         }
7201                         else
7202                                 conv = -1;
7203
7204                         src_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7205                         mono_mb_emit_ldarg (mb, argnum);
7206                         if (t->byref)
7207                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7208                         mono_mb_emit_stloc (mb, src_var);
7209
7210                         /* Check null */
7211                         mono_mb_emit_ldloc (mb, src_var);
7212                         mono_mb_emit_stloc (mb, conv_arg);
7213                         mono_mb_emit_ldloc (mb, src_var);
7214                         label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7215
7216                         if (is_string) {
7217                                 if (conv == -1) {
7218                                         char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
7219                                         MonoException *exc = mono_get_exception_not_implemented (msg);
7220                                         g_warning (msg);
7221                                         g_free (msg);
7222                                         mono_raise_exception (exc);
7223                                 }
7224                         }
7225
7226                         if (is_string)
7227                                 esize = sizeof (gpointer);
7228                         else
7229                                 esize = mono_class_native_size (eklass, NULL);
7230
7231                         /* allocate space for the native struct and store the address */
7232                         mono_mb_emit_icon (mb, esize);
7233                         mono_mb_emit_ldloc (mb, src_var);
7234                         mono_mb_emit_byte (mb, CEE_LDLEN);
7235
7236                         if (eklass == mono_defaults.string_class) {
7237                                 /* Make the array bigger for the terminating null */
7238                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7239                                 mono_mb_emit_byte (mb, CEE_ADD);
7240                         }
7241                         mono_mb_emit_byte (mb, CEE_MUL);
7242                         mono_mb_emit_byte (mb, CEE_PREFIX1);
7243                         mono_mb_emit_byte (mb, CEE_LOCALLOC);
7244                         mono_mb_emit_stloc (mb, conv_arg);
7245
7246                         mono_mb_emit_ldloc (mb, conv_arg);
7247                         mono_mb_emit_stloc (mb, dest_ptr);
7248
7249                         /* Emit marshalling loop */
7250                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
7251                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7252                         mono_mb_emit_stloc (mb, index_var);
7253                         label2 = mono_mb_get_label (mb);
7254                         mono_mb_emit_ldloc (mb, index_var);
7255                         mono_mb_emit_ldloc (mb, src_var);
7256                         mono_mb_emit_byte (mb, CEE_LDLEN);
7257                         label3 = mono_mb_emit_branch (mb, CEE_BGE);
7258
7259                         /* Emit marshalling code */
7260
7261                         if (is_string) {
7262                                 mono_mb_emit_ldloc (mb, dest_ptr);
7263                                 mono_mb_emit_ldloc (mb, src_var);
7264                                 mono_mb_emit_ldloc (mb, index_var);
7265                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7266                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
7267                                 mono_mb_emit_byte (mb, CEE_STIND_I);
7268                         } else {
7269                                 /* set the src_ptr */
7270                                 mono_mb_emit_ldloc (mb, src_var);
7271                                 mono_mb_emit_ldloc (mb, index_var);
7272                                 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
7273                                 mono_mb_emit_stloc (mb, 0);
7274
7275                                 /* set dst_ptr */
7276                                 mono_mb_emit_ldloc (mb, dest_ptr);
7277                                 mono_mb_emit_stloc (mb, 1);
7278
7279                                 /* emit valuetype conversion code */
7280                                 emit_struct_conv (mb, eklass, FALSE);
7281                         }
7282
7283                         mono_mb_emit_add_to_local (mb, index_var, 1);
7284                         mono_mb_emit_add_to_local (mb, dest_ptr, esize);
7285                         
7286                         mono_mb_emit_branch_label (mb, CEE_BR, label2);
7287
7288                         mono_mb_patch_branch (mb, label3);
7289
7290                         if (eklass == mono_defaults.string_class) {
7291                                 /* Null terminate */
7292                                 mono_mb_emit_ldloc (mb, dest_ptr);
7293                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7294                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
7295                         }
7296
7297                         mono_mb_patch_branch (mb, label1);
7298                 }
7299
7300                 break;
7301
7302         case MARSHAL_ACTION_CONV_OUT:
7303                 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
7304                 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);
7305                 need_free = mono_marshal_need_free (&klass->element_class->byval_arg, 
7306                                                                                         m->piinfo, spec);
7307
7308                 if (need_convert || need_free) {
7309                         /* FIXME: Optimize blittable case */
7310                         MonoClass *eklass;
7311                         guint32 label1, label2, label3;
7312                         int index_var, src_ptr, loc, esize;
7313
7314                         eklass = klass->element_class;
7315                         if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
7316                                 esize = sizeof (gpointer);
7317                         else
7318                                 esize = mono_class_native_size (eklass, NULL);
7319                         src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7320                         loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7321
7322                         /* Check null */
7323                         mono_mb_emit_ldarg (mb, argnum);
7324                         if (t->byref)
7325                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7326                         label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7327
7328                         mono_mb_emit_ldloc (mb, conv_arg);
7329                         mono_mb_emit_stloc (mb, src_ptr);
7330
7331                         /* Emit marshalling loop */
7332                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
7333                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7334                         mono_mb_emit_stloc (mb, index_var);
7335                         label2 = mono_mb_get_label (mb);
7336                         mono_mb_emit_ldloc (mb, index_var);
7337                         mono_mb_emit_ldarg (mb, argnum);
7338                         if (t->byref)
7339                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
7340                         mono_mb_emit_byte (mb, CEE_LDLEN);
7341                         label3 = mono_mb_emit_branch (mb, CEE_BGE);
7342
7343                         /* Emit marshalling code */
7344
7345                         if (eklass == mono_defaults.stringbuilder_class) {
7346                                 gboolean need_free2;
7347                                 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
7348
7349                                 g_assert (conv != -1);
7350
7351                                 /* dest */
7352                                 mono_mb_emit_ldarg (mb, argnum);
7353                                 if (t->byref)
7354                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7355                                 mono_mb_emit_ldloc (mb, index_var);
7356                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7357
7358                                 /* src */
7359                                 mono_mb_emit_ldloc (mb, src_ptr);
7360                                 mono_mb_emit_byte (mb, CEE_LDIND_I);
7361
7362                                 mono_mb_emit_icall (mb, conv_to_icall (conv));
7363
7364                                 if (need_free) {
7365                                         /* src */
7366                                         mono_mb_emit_ldloc (mb, src_ptr);
7367                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7368
7369                                         mono_mb_emit_icall (mb, mono_marshal_free);
7370                                 }
7371                         }
7372                         else if (eklass == mono_defaults.string_class) {
7373                                 if (need_free) {
7374                                         /* src */
7375                                         mono_mb_emit_ldloc (mb, src_ptr);
7376                                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7377
7378                                         mono_mb_emit_icall (mb, mono_marshal_free);
7379                                 }
7380                         }
7381                         else {
7382                                 if (need_convert) {
7383                                         /* set the src_ptr */
7384                                         mono_mb_emit_ldloc (mb, src_ptr);
7385                                         mono_mb_emit_stloc (mb, 0);
7386
7387                                         /* set dst_ptr */
7388                                         mono_mb_emit_ldarg (mb, argnum);
7389                                         if (t->byref)
7390                                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
7391                                         mono_mb_emit_ldloc (mb, index_var);
7392                                         mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
7393                                         mono_mb_emit_stloc (mb, 1);
7394
7395                                         /* emit valuetype conversion code */
7396                                         emit_struct_conv (mb, eklass, TRUE);
7397                                 }
7398
7399                                 if (need_free) {
7400                                         mono_mb_emit_ldloc (mb, src_ptr);
7401                                         mono_mb_emit_stloc (mb, loc);
7402                                         mono_mb_emit_ldloc (mb, loc);
7403
7404                                         emit_struct_free (mb, eklass, loc);
7405                                 }
7406                         }
7407
7408                         mono_mb_emit_add_to_local (mb, index_var, 1);
7409                         mono_mb_emit_add_to_local (mb, src_ptr, esize);
7410
7411                         mono_mb_emit_branch_label (mb, CEE_BR, label2);
7412
7413                         mono_mb_patch_branch (mb, label1);
7414                         mono_mb_patch_branch (mb, label3);
7415                 }
7416                 break;
7417
7418         case MARSHAL_ACTION_PUSH:
7419                 if (t->byref)
7420                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7421                 else
7422                         mono_mb_emit_ldloc (mb, conv_arg);
7423                 break;
7424
7425         case MARSHAL_ACTION_CONV_RESULT:
7426                 /* fixme: we need conversions here */
7427                 mono_mb_emit_stloc (mb, 3);
7428                 break;
7429
7430         case MARSHAL_ACTION_MANAGED_CONV_IN: {
7431                 MonoClass *eklass;
7432                 guint32 label1, label2, label3;
7433                 int index_var, src_ptr, loc, esize, param_num, num_elem;
7434                 MonoMarshalConv conv;
7435                 gboolean is_string = FALSE;
7436                 
7437                 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7438                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7439
7440                 if (t->byref) {
7441                         char *msg = g_strdup ("Byref array marshalling to managed code is not implemented.");
7442                         mono_mb_emit_exception_marshal_directive (mb, msg);
7443                         return conv_arg;
7444                 }
7445                 if (!spec) {
7446                         char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
7447                         mono_mb_emit_exception_marshal_directive (mb, msg);
7448                         return conv_arg;
7449                 }                       
7450                 if (spec->native != MONO_NATIVE_LPARRAY) {
7451                         char *msg = g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
7452                         mono_mb_emit_exception_marshal_directive (mb, msg);
7453                         return conv_arg;                        
7454                 }
7455
7456                 /* FIXME: t is from the method which is wrapped, not the delegate type */
7457                 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
7458
7459                 param_num = spec->data.array_data.param_num;
7460                 num_elem = spec->data.array_data.num_elem;
7461                 if (spec->data.array_data.elem_mult == 0)
7462                         /* param_num is not specified */
7463                         param_num = -1;
7464
7465                 if (param_num == -1) {
7466                         if (num_elem <= 0) {
7467                                 char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
7468                                 mono_mb_emit_exception_marshal_directive (mb, msg);
7469                                 return conv_arg;
7470                         }
7471                 }
7472
7473                 /* FIXME: Optimize blittable case */
7474
7475                 eklass = klass->element_class;
7476                 if (eklass == mono_defaults.string_class) {
7477                         is_string = TRUE;
7478                         conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
7479                 }
7480                 else if (eklass == mono_defaults.stringbuilder_class) {
7481                         is_string = TRUE;
7482                         conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
7483                 }
7484                 else
7485                         conv = -1;
7486
7487                 mono_marshal_load_type_info (eklass);
7488
7489                 if (is_string)
7490                         esize = sizeof (gpointer);
7491                 else
7492                         esize = mono_class_native_size (eklass, NULL);
7493                 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7494                 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7495
7496                 mono_mb_emit_byte (mb, CEE_LDNULL);
7497                 mono_mb_emit_stloc (mb, conv_arg);
7498
7499                 /* Check param index */
7500                 if (param_num != -1) {
7501                         if (param_num >= m->sig->param_count) {
7502                                 char *msg = g_strdup ("Array size control parameter index is out of range.");
7503                                 mono_mb_emit_exception_marshal_directive (mb, msg);
7504                                 return conv_arg;
7505                         }
7506                         switch (m->sig->params [param_num]->type) {
7507                         case MONO_TYPE_I1:
7508                         case MONO_TYPE_U1:
7509                         case MONO_TYPE_I2:
7510                         case MONO_TYPE_U2:
7511                         case MONO_TYPE_I4:
7512                         case MONO_TYPE_U4:
7513                         case MONO_TYPE_I:
7514                         case MONO_TYPE_U:
7515                         case MONO_TYPE_I8:
7516                         case MONO_TYPE_U8:
7517                                 break;
7518                         default: {
7519                                 char *msg = g_strdup ("Array size control parameter must be an integral type.");
7520                                 mono_mb_emit_exception_marshal_directive (mb, msg);
7521                                 return conv_arg;
7522                         }
7523                         }
7524                 }
7525
7526                 /* Check null */
7527                 mono_mb_emit_ldarg (mb, argnum);
7528                 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7529
7530                 mono_mb_emit_ldarg (mb, argnum);
7531                 mono_mb_emit_stloc (mb, src_ptr);
7532
7533                 /* Create managed array */
7534                 /* 
7535                  * The LPArray marshalling spec says that sometimes param_num starts 
7536                  * from 1, sometimes it starts from 0. But MS seems to allways start
7537                  * from 0.
7538                  */
7539
7540                 if (param_num == -1)
7541                         mono_mb_emit_icon (mb, num_elem);
7542                 else {
7543                         /* FIXME: Add the two together */
7544                         mono_mb_emit_ldarg (mb, param_num);
7545                         if (num_elem > 0) {
7546                                 mono_mb_emit_icon (mb, num_elem);
7547                                 mono_mb_emit_byte (mb, CEE_ADD);
7548                         }
7549                 }
7550
7551                 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
7552                 mono_mb_emit_stloc (mb, conv_arg);
7553
7554                 if (eklass->blittable) {
7555                         mono_mb_emit_ldloc (mb, conv_arg);
7556                         mono_mb_emit_byte (mb, CEE_CONV_I);
7557                         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
7558                         mono_mb_emit_byte (mb, CEE_ADD);
7559                         mono_mb_emit_ldarg (mb, argnum);
7560                         mono_mb_emit_ldloc (mb, conv_arg);
7561                         mono_mb_emit_byte (mb, CEE_LDLEN);
7562                         mono_mb_emit_icon (mb, esize);
7563                         mono_mb_emit_byte (mb, CEE_MUL);
7564                         mono_mb_emit_byte (mb, CEE_PREFIX1);
7565                         mono_mb_emit_byte (mb, CEE_CPBLK);                      
7566                         break;
7567                 }
7568
7569                 /* Emit marshalling loop */
7570                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7571                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7572                 mono_mb_emit_stloc (mb, index_var);
7573                 label2 = mono_mb_get_label (mb);
7574                 mono_mb_emit_ldloc (mb, index_var);
7575                 mono_mb_emit_ldloc (mb, conv_arg);
7576                 mono_mb_emit_byte (mb, CEE_LDLEN);
7577                 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7578
7579                 /* Emit marshalling code */
7580                 if (is_string) {
7581                         g_assert (conv != -1);
7582
7583                         mono_mb_emit_ldloc (mb, conv_arg);
7584                         mono_mb_emit_ldloc (mb, index_var);
7585
7586                         mono_mb_emit_ldloc (mb, src_ptr);
7587                         mono_mb_emit_byte (mb, CEE_LDIND_I);
7588
7589                         mono_mb_emit_icall (mb, conv_to_icall (conv));
7590                         mono_mb_emit_byte (mb, CEE_STELEM_REF);
7591                 }
7592                 else {
7593                         char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7594                         mono_mb_emit_exception_marshal_directive (mb, msg);
7595                         return conv_arg;
7596                 }
7597
7598                 mono_mb_emit_add_to_local (mb, index_var, 1);
7599                 mono_mb_emit_add_to_local (mb, src_ptr, esize);
7600
7601                 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7602
7603                 mono_mb_patch_branch (mb, label1);
7604                 mono_mb_patch_branch (mb, label3);
7605                 
7606                 break;
7607         }
7608         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7609                 MonoClass *eklass;
7610                 guint32 label1, label2, label3;
7611                 int index_var, dest_ptr, loc, esize, param_num, num_elem;
7612                 MonoMarshalConv conv;
7613                 gboolean is_string = FALSE;
7614
7615                 if (!spec)
7616                         /* Already handled in CONV_IN */
7617                         break;
7618                 
7619                 /* These are already checked in CONV_IN */
7620                 g_assert (!t->byref);
7621                 g_assert (spec->native == MONO_NATIVE_LPARRAY);
7622                 g_assert (t->attrs & PARAM_ATTRIBUTE_OUT);
7623
7624                 param_num = spec->data.array_data.param_num;
7625                 num_elem = spec->data.array_data.num_elem;
7626
7627                 if (spec->data.array_data.elem_mult == 0)
7628                         /* param_num is not specified */
7629                         param_num = -1;
7630
7631                 if (param_num == -1) {
7632                         if (num_elem <= 0) {
7633                                 g_assert_not_reached ();
7634                         }
7635                 }
7636
7637                 /* FIXME: Optimize blittable case */
7638
7639                 eklass = klass->element_class;
7640                 if (eklass == mono_defaults.string_class) {
7641                         is_string = TRUE;
7642                         conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7643                 }
7644                 else if (eklass == mono_defaults.stringbuilder_class) {
7645                         is_string = TRUE;
7646                         conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
7647                 }
7648                 else
7649                         conv = -1;
7650
7651                 mono_marshal_load_type_info (eklass);
7652
7653                 if (is_string)
7654                         esize = sizeof (gpointer);
7655                 else
7656                         esize = mono_class_native_size (eklass, NULL);
7657
7658                 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7659                 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7660
7661                 /* Check null */
7662                 mono_mb_emit_ldloc (mb, conv_arg);
7663                 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7664
7665                 mono_mb_emit_ldarg (mb, argnum);
7666                 mono_mb_emit_stloc (mb, dest_ptr);
7667
7668                 if (eklass->blittable) {
7669                         /* dest */
7670                         mono_mb_emit_ldarg (mb, argnum);
7671                         /* src */
7672                         mono_mb_emit_ldloc (mb, conv_arg);
7673                         mono_mb_emit_byte (mb, CEE_CONV_I);
7674                         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
7675                         mono_mb_emit_byte (mb, CEE_ADD);
7676                         /* length */
7677                         mono_mb_emit_ldloc (mb, conv_arg);
7678                         mono_mb_emit_byte (mb, CEE_LDLEN);
7679                         mono_mb_emit_icon (mb, esize);
7680                         mono_mb_emit_byte (mb, CEE_MUL);
7681                         mono_mb_emit_byte (mb, CEE_PREFIX1);
7682                         mono_mb_emit_byte (mb, CEE_CPBLK);                      
7683                         break;
7684                 }
7685
7686                 /* Emit marshalling loop */
7687                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7688                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7689                 mono_mb_emit_stloc (mb, index_var);
7690                 label2 = mono_mb_get_label (mb);
7691                 mono_mb_emit_ldloc (mb, index_var);
7692                 mono_mb_emit_ldloc (mb, conv_arg);
7693                 mono_mb_emit_byte (mb, CEE_LDLEN);
7694                 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7695
7696                 /* Emit marshalling code */
7697                 if (is_string) {
7698                         g_assert (conv != -1);
7699
7700                         /* dest */
7701                         mono_mb_emit_ldloc (mb, dest_ptr);
7702
7703                         /* src */
7704                         mono_mb_emit_ldloc (mb, conv_arg);
7705                         mono_mb_emit_ldloc (mb, index_var);
7706
7707                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7708
7709                         mono_mb_emit_icall (mb, conv_to_icall (conv));
7710                         mono_mb_emit_byte (mb, CEE_STIND_I);
7711                 }
7712                 else {
7713                         char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7714                         mono_mb_emit_exception_marshal_directive (mb, msg);
7715                         return conv_arg;
7716                 }
7717
7718                 mono_mb_emit_add_to_local (mb, index_var, 1);
7719                 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
7720
7721                 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7722
7723                 mono_mb_patch_branch (mb, label1);
7724                 mono_mb_patch_branch (mb, label3);
7725
7726                 break;
7727         }
7728         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7729                 MonoClass *eklass;
7730                 guint32 label1, label2, label3;
7731                 int index_var, src, dest, esize;
7732                 MonoMarshalConv conv = -1;
7733                 gboolean is_string = FALSE;
7734                 
7735                 g_assert (!t->byref);
7736
7737                 eklass = klass->element_class;
7738
7739                 mono_marshal_load_type_info (eklass);
7740
7741                 if (eklass == mono_defaults.string_class) {
7742                         is_string = TRUE;
7743                         conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7744                 }
7745                 else {
7746                         g_assert_not_reached ();
7747                 }
7748
7749                 if (is_string)
7750                         esize = sizeof (gpointer);
7751                 else
7752                         esize = mono_class_native_size (eklass, NULL);
7753
7754                 src = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7755                 dest = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7756                         
7757                 mono_mb_emit_stloc (mb, src);
7758                 mono_mb_emit_ldloc (mb, src);
7759                 mono_mb_emit_stloc (mb, 3);
7760
7761                 /* Check for null */
7762                 mono_mb_emit_ldloc (mb, src);
7763                 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7764
7765                 /* Allocate native array */
7766                 mono_mb_emit_icon (mb, esize);
7767                 mono_mb_emit_ldloc (mb, src);
7768                 mono_mb_emit_byte (mb, CEE_LDLEN);
7769
7770                 if (eklass == mono_defaults.string_class) {
7771                         /* Make the array bigger for the terminating null */
7772                         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7773                         mono_mb_emit_byte (mb, CEE_ADD);
7774                 }
7775                 mono_mb_emit_byte (mb, CEE_MUL);
7776                 mono_mb_emit_icall (mb, mono_marshal_alloc);
7777                 mono_mb_emit_stloc (mb, dest);
7778                 mono_mb_emit_ldloc (mb, dest);
7779                 mono_mb_emit_stloc (mb, 3);
7780
7781                 /* Emit marshalling loop */
7782                 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7783                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7784                 mono_mb_emit_stloc (mb, index_var);
7785                 label2 = mono_mb_get_label (mb);
7786                 mono_mb_emit_ldloc (mb, index_var);
7787                 mono_mb_emit_ldloc (mb, src);
7788                 mono_mb_emit_byte (mb, CEE_LDLEN);
7789                 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7790
7791                 /* Emit marshalling code */
7792                 if (is_string) {
7793                         g_assert (conv != -1);
7794
7795                         /* dest */
7796                         mono_mb_emit_ldloc (mb, dest);
7797
7798                         /* src */
7799                         mono_mb_emit_ldloc (mb, src);
7800                         mono_mb_emit_ldloc (mb, index_var);
7801
7802                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7803
7804                         mono_mb_emit_icall (mb, conv_to_icall (conv));
7805                         mono_mb_emit_byte (mb, CEE_STIND_I);
7806                 }
7807                 else {
7808                         char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
7809                         mono_mb_emit_exception_marshal_directive (mb, msg);
7810                         return conv_arg;
7811                 }
7812
7813                 mono_mb_emit_add_to_local (mb, index_var, 1);
7814                 mono_mb_emit_add_to_local (mb, dest, esize);
7815
7816                 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7817
7818                 mono_mb_patch_branch (mb, label3);
7819                 mono_mb_patch_branch (mb, label1);
7820                 break;
7821         }
7822         default:
7823                 g_assert_not_reached ();
7824         }
7825
7826         return conv_arg;
7827 }
7828
7829 static int
7830 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
7831                       MonoMarshalSpec *spec, 
7832                       int conv_arg, MonoType **conv_arg_type, 
7833                       MarshalAction action)
7834 {
7835         MonoMethodBuilder *mb = m->mb;
7836
7837         switch (action) {
7838         case MARSHAL_ACTION_CONV_IN: {
7839                 MonoType *local_type;
7840                 int variant_bool = 0;
7841                 if (!t->byref)
7842                         break;
7843                 if (spec == NULL) {
7844                         local_type = &mono_defaults.int32_class->byval_arg;
7845                 } else {
7846                         switch (spec->native) {
7847                         case MONO_NATIVE_I1:
7848                         case MONO_NATIVE_U1:
7849                                 local_type = &mono_defaults.byte_class->byval_arg;
7850                                 break;
7851                         case MONO_NATIVE_VARIANTBOOL:
7852                                 local_type = &mono_defaults.int16_class->byval_arg;
7853                                 variant_bool = 1;
7854                                 break;
7855                         default:
7856                                 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
7857                                 local_type = &mono_defaults.int32_class->byval_arg;
7858                                 break;
7859                         }
7860                 }
7861                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7862                 conv_arg = mono_mb_add_local (mb, local_type);
7863                 mono_mb_emit_ldarg (mb, argnum);
7864                 mono_mb_emit_byte (mb, CEE_LDIND_I1);
7865                 if (variant_bool)
7866                         mono_mb_emit_byte (mb, CEE_NEG);
7867                 mono_mb_emit_stloc (mb, conv_arg);
7868                 break;
7869         }
7870
7871         case MARSHAL_ACTION_CONV_OUT:
7872                 if (!t->byref)
7873                         break;
7874                 mono_mb_emit_ldarg (mb, argnum);
7875                 mono_mb_emit_ldloc (mb, conv_arg);
7876                 if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL)
7877                         mono_mb_emit_byte (mb, CEE_NEG);
7878                 mono_mb_emit_byte (mb, CEE_STIND_I1);
7879                 break;
7880
7881         case MARSHAL_ACTION_PUSH:
7882                 if (t->byref)
7883                         mono_mb_emit_ldloc_addr (mb, conv_arg);
7884                 else
7885                         mono_mb_emit_ldarg (mb, argnum);
7886                 break;
7887
7888         case MARSHAL_ACTION_CONV_RESULT:
7889                 /* maybe we need to make sure that it fits within 8 bits */
7890                 mono_mb_emit_stloc (mb, 3);
7891                 break;
7892
7893         default:
7894                 g_assert_not_reached ();
7895         }
7896
7897         return conv_arg;
7898 }
7899
7900 static int
7901 emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t, 
7902                   MonoMarshalSpec *spec, int conv_arg, 
7903                   MonoType **conv_arg_type, MarshalAction action)
7904 {
7905         MonoMethodBuilder *mb = m->mb;
7906
7907         switch (action) {
7908         case MARSHAL_ACTION_CONV_IN:
7909                 if (MONO_TYPE_ISSTRUCT (t->data.type)) {
7910                         char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
7911                         mono_mb_emit_exception_marshal_directive (m->mb, msg);
7912                 }
7913                 break;
7914
7915         case MARSHAL_ACTION_PUSH:
7916                 mono_mb_emit_ldarg (mb, argnum);
7917                 break;
7918
7919         case MARSHAL_ACTION_CONV_RESULT:
7920                 /* no conversions necessary */
7921                 mono_mb_emit_stloc (mb, 3);
7922                 break;
7923
7924         default:
7925                 break;
7926         }
7927
7928         return conv_arg;
7929 }
7930
7931 static int
7932 emit_marshal_char (EmitMarshalContext *m, int argnum, MonoType *t, 
7933                    MonoMarshalSpec *spec, int conv_arg, 
7934                    MonoType **conv_arg_type, MarshalAction action)
7935 {
7936         MonoMethodBuilder *mb = m->mb;
7937
7938         switch (action) {
7939         case MARSHAL_ACTION_PUSH:
7940                 /* fixme: dont know how to marshal that. We cant simply
7941                  * convert it to a one byte UTF8 character, because an
7942                  * unicode character may need more that one byte in UTF8 */
7943                 mono_mb_emit_ldarg (mb, argnum);
7944                 break;
7945
7946         case MARSHAL_ACTION_CONV_RESULT:
7947                 /* fixme: we need conversions here */
7948                 mono_mb_emit_stloc (mb, 3);
7949                 break;
7950
7951         default:
7952                 break;
7953         }
7954
7955         return conv_arg;
7956 }
7957
7958 static int
7959 emit_marshal_scalar (EmitMarshalContext *m, int argnum, MonoType *t, 
7960                      MonoMarshalSpec *spec, int conv_arg, 
7961                      MonoType **conv_arg_type, MarshalAction action)
7962 {
7963         MonoMethodBuilder *mb = m->mb;
7964
7965         switch (action) {
7966         case MARSHAL_ACTION_PUSH:
7967                 mono_mb_emit_ldarg (mb, argnum);
7968                 break;
7969
7970         case MARSHAL_ACTION_CONV_RESULT:
7971                 /* no conversions necessary */
7972                 mono_mb_emit_stloc (mb, 3);
7973                 break;
7974
7975         default:
7976                 break;
7977         }
7978
7979         return conv_arg;
7980 }
7981
7982 static int
7983 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, 
7984               MonoMarshalSpec *spec, int conv_arg, 
7985               MonoType **conv_arg_type, MarshalAction action)
7986 {
7987         /* Ensure that we have marshalling info for this param */
7988         mono_marshal_load_type_info (mono_class_from_mono_type (t));
7989
7990         if (spec && spec->native == MONO_NATIVE_CUSTOM)
7991                 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7992
7993         if (spec && spec->native == MONO_NATIVE_ASANY)
7994                 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7995                         
7996         switch (t->type) {
7997         case MONO_TYPE_VALUETYPE:
7998                 if (t->data.klass == mono_defaults.handleref_class)
7999                         return emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8000                 
8001                 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8002         case MONO_TYPE_STRING:
8003                 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8004         case MONO_TYPE_CLASS:
8005         case MONO_TYPE_OBJECT:
8006                 if (spec && spec->native == MONO_NATIVE_STRUCT)
8007                         return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8008
8009                 if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
8010                         spec->native == MONO_NATIVE_IDISPATCH ||
8011                         spec->native == MONO_NATIVE_INTERFACE))
8012                         return emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8013
8014                 if (mono_defaults.safehandle_class != NULL &&
8015                     mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
8016                         return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8017                 
8018                 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8019         case MONO_TYPE_ARRAY:
8020         case MONO_TYPE_SZARRAY:
8021                 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8022         case MONO_TYPE_BOOLEAN:
8023                 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8024         case MONO_TYPE_PTR:
8025                 return emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8026         case MONO_TYPE_CHAR:
8027                 return emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8028         case MONO_TYPE_I1:
8029         case MONO_TYPE_U1:
8030         case MONO_TYPE_I2:
8031         case MONO_TYPE_U2:
8032         case MONO_TYPE_I4:
8033         case MONO_TYPE_U4:
8034         case MONO_TYPE_I:
8035         case MONO_TYPE_U:
8036         case MONO_TYPE_R4:
8037         case MONO_TYPE_R8:
8038         case MONO_TYPE_I8:
8039         case MONO_TYPE_U8:
8040         case MONO_TYPE_FNPTR:
8041                 return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action);
8042         }
8043
8044         return conv_arg;
8045 }
8046
8047 /**
8048  * mono_marshal_emit_native_wrapper:
8049  * @image: the image to use for looking up custom marshallers
8050  * @sig: The signature of the native function
8051  * @piinfo: Marshalling information
8052  * @mspecs: Marshalling information
8053  * @func: the native function to call
8054  *
8055  * generates IL code for the pinvoke wrapper, the generated code calls @func.
8056  */
8057 static void
8058 mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
8059 {
8060         EmitMarshalContext m;
8061         MonoMethodSignature *csig;
8062         MonoClass *klass;
8063         int i, argnum, *tmp_locals;
8064         int type;
8065         static MonoMethodSignature *get_last_error_sig = NULL;
8066
8067         m.mb = mb;
8068         m.piinfo = piinfo;
8069
8070         /* we copy the signature, so that we can set pinvoke to 0 */
8071         csig = signature_dup (mb->method->klass->image, sig);
8072         csig->pinvoke = 1;
8073         m.csig = csig;
8074         m.image = image;
8075
8076         /* we allocate local for use with emit_struct_conv() */
8077         /* allocate local 0 (pointer) src_ptr */
8078         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8079         /* allocate local 1 (pointer) dst_ptr */
8080         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8081         /* allocate local 2 (boolean) delete_old */
8082         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
8083
8084         /* delete_old = FALSE */
8085         mono_mb_emit_icon (mb, 0);
8086         mono_mb_emit_stloc (mb, 2);
8087
8088         if (!MONO_TYPE_IS_VOID(sig->ret)) {
8089                 /* allocate local 3 to store the return value */
8090                 mono_mb_add_local (mb, sig->ret);
8091         }
8092
8093         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
8094                 /* Return type custom marshaling */
8095                 /*
8096                  * Since we can't determine the return type of the unmanaged function,
8097                  * we assume it returns a pointer, and pass that pointer to
8098                  * MarshalNativeToManaged.
8099                  */
8100                 csig->ret = &mono_defaults.int_class->byval_arg;
8101         }
8102
8103         /* we first do all conversions */
8104         tmp_locals = alloca (sizeof (int) * sig->param_count);
8105         m.orig_conv_args = alloca (sizeof (int) * (sig->param_count + 1));
8106
8107         for (i = 0; i < sig->param_count; i ++) {
8108                 tmp_locals [i] = emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
8109         }
8110
8111         /* push all arguments */
8112
8113         if (sig->hasthis)
8114                 mono_mb_emit_byte (mb, CEE_LDARG_0);
8115
8116
8117         for (i = 0; i < sig->param_count; i++) {
8118                 emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
8119         }                       
8120
8121         /* call the native method */
8122         if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
8123                 mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
8124         }
8125         else {
8126                 mono_mb_emit_native_call (mb, csig, func);
8127         }
8128
8129         /* Set LastError if needed */
8130         if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
8131                 if (!get_last_error_sig) {
8132                         get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
8133                         get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
8134                         get_last_error_sig->pinvoke = 1;
8135                 }
8136
8137 #ifdef PLATFORM_WIN32
8138                 /* 
8139                  * Have to call GetLastError () early and without a wrapper, since various runtime components could
8140                  * clobber its value.
8141                  */
8142                 mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
8143                 mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
8144 #else
8145                 mono_mb_emit_icall (mb, mono_marshal_set_last_error);
8146 #endif
8147         }               
8148
8149         /* convert the result */
8150         if (!sig->ret->byref) {
8151                 MonoMarshalSpec *spec = mspecs [0];
8152                 type = sig->ret->type;
8153
8154                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
8155                         emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8156                 } else {
8157
8158                 handle_enum:
8159                         switch (type) {
8160                         case MONO_TYPE_VOID:
8161                                 break;
8162                         case MONO_TYPE_VALUETYPE:
8163                                 klass = sig->ret->data.klass;
8164                                 if (klass->enumtype) {
8165                                         type = sig->ret->data.klass->enum_basetype->type;
8166                                         goto handle_enum;
8167                                 }
8168                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8169                                 break;
8170                         case MONO_TYPE_I1:
8171                         case MONO_TYPE_U1:
8172                         case MONO_TYPE_I2:
8173                         case MONO_TYPE_U2:
8174                         case MONO_TYPE_I4:
8175                         case MONO_TYPE_U4:
8176                         case MONO_TYPE_I:
8177                         case MONO_TYPE_U:
8178                         case MONO_TYPE_R4:
8179                         case MONO_TYPE_R8:
8180                         case MONO_TYPE_I8:
8181                         case MONO_TYPE_U8:
8182                         case MONO_TYPE_FNPTR:
8183                         case MONO_TYPE_STRING:
8184                         case MONO_TYPE_CLASS:
8185                         case MONO_TYPE_OBJECT:
8186                         case MONO_TYPE_BOOLEAN:
8187                         case MONO_TYPE_ARRAY:
8188                         case MONO_TYPE_SZARRAY:
8189                         case MONO_TYPE_CHAR:
8190                         case MONO_TYPE_PTR:
8191                                 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
8192                                 break;
8193                         case MONO_TYPE_TYPEDBYREF:
8194                         default:
8195                                 g_warning ("return type 0x%02x unknown", sig->ret->type);       
8196                                 g_assert_not_reached ();
8197                         }
8198                 }
8199         } else {
8200                 mono_mb_emit_stloc (mb, 3);
8201         }
8202
8203         /* 
8204          * Need to call this after converting the result since MONO_VTADDR needs 
8205          * to be adjacent to the call instruction.
8206          */
8207         emit_thread_interrupt_checkpoint (mb);
8208
8209         /* we need to convert byref arguments back and free string arrays */
8210         for (i = 0; i < sig->param_count; i++) {
8211                 MonoType *t = sig->params [i];
8212                 MonoMarshalSpec *spec = mspecs [i + 1];
8213
8214                 argnum = i + sig->hasthis;
8215
8216                 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
8217                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
8218                         continue;
8219                 }
8220
8221                 switch (t->type) {
8222                 case MONO_TYPE_STRING:
8223                 case MONO_TYPE_VALUETYPE:
8224                 case MONO_TYPE_CLASS:
8225                 case MONO_TYPE_OBJECT:
8226                 case MONO_TYPE_SZARRAY:
8227                 case MONO_TYPE_BOOLEAN:
8228                         emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
8229                         break;
8230                 }
8231         }
8232
8233         if (!MONO_TYPE_IS_VOID(sig->ret))
8234                 mono_mb_emit_ldloc (mb, 3);
8235
8236         mono_mb_emit_byte (mb, CEE_RET);
8237 }
8238
8239 /**
8240  * mono_marshal_get_native_wrapper:
8241  * @method: The MonoMethod to wrap.
8242  *
8243  * generates IL code for the pinvoke wrapper (the generated method
8244  * calls the unmanaged code in piinfo->addr)
8245  */
8246 MonoMethod *
8247 mono_marshal_get_native_wrapper (MonoMethod *method)
8248 {
8249         MonoMethodSignature *sig, *csig;
8250         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
8251         MonoMethodBuilder *mb;
8252         MonoMarshalSpec **mspecs;
8253         MonoMethod *res;
8254         GHashTable *cache;
8255         gboolean pinvoke = FALSE;
8256         gpointer iter;
8257         int i;
8258         const char *exc_class = "MissingMethodException";
8259         const char *exc_arg = NULL;
8260
8261         g_assert (method != NULL);
8262         g_assert (mono_method_signature (method)->pinvoke);
8263
8264         cache = method->klass->image->native_wrapper_cache;
8265         if ((res = mono_marshal_find_in_cache (cache, method)))
8266                 return res;
8267
8268         if (MONO_CLASS_IS_IMPORT (method->klass))
8269                 return cominterop_get_native_wrapper (method);
8270
8271         sig = mono_method_signature (method);
8272
8273         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
8274             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
8275                 pinvoke = TRUE;
8276
8277         if (!piinfo->addr) {
8278                 if (pinvoke)
8279                         mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
8280                 else
8281                         piinfo->addr = mono_lookup_internal_call (method);
8282         }
8283
8284         /* hack - redirect certain string constructors to CreateString */
8285         if (piinfo->addr == ves_icall_System_String_ctor_RedirectToCreateString) {
8286                 g_assert (!pinvoke);
8287                 g_assert (method->string_ctor);
8288                 g_assert (sig->hasthis);
8289
8290                 /* CreateString returns a value */
8291                 csig = signature_dup (method->klass->image, sig);
8292                 csig->ret = &mono_defaults.string_class->byval_arg;
8293                 csig->pinvoke = 0;
8294
8295                 iter = NULL;
8296                 while ((res = mono_class_get_methods (mono_defaults.string_class, &iter))) {
8297                         if (!strcmp ("CreateString", res->name) &&
8298                                 mono_metadata_signature_equal (csig, mono_method_signature (res))) {
8299
8300                                 g_assert (!(res->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
8301                                 g_assert (!(res->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
8302
8303                                 /* create a wrapper to preserve .ctor in stack trace */
8304                                 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
8305
8306                                 mono_mb_emit_byte (mb, CEE_LDARG_0);
8307                                 for (i = 1; i <= csig->param_count; i++)
8308                                         mono_mb_emit_ldarg (mb, i);
8309                                 mono_mb_emit_managed_call (mb, res, NULL);
8310                                 mono_mb_emit_byte (mb, CEE_RET);
8311
8312                                 /* use native_wrapper_cache because internal calls are looked up there */
8313                                 res = mono_mb_create_and_cache (cache, method,
8314                                         mb, csig, csig->param_count + 1);
8315
8316                                 mono_mb_free (mb);
8317
8318                                 return res;
8319                         }
8320                 }
8321
8322                 /* exception will be thrown */
8323                 piinfo->addr = NULL;
8324                 g_warning ("cannot find CreateString for .ctor");
8325         }
8326
8327         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8328
8329         mb->method->save_lmf = 1;
8330         
8331         if (!piinfo->addr) {
8332                 mono_mb_emit_exception (mb, exc_class, exc_arg);
8333                 csig = signature_dup (method->klass->image, sig);
8334                 csig->pinvoke = 0;
8335                 res = mono_mb_create_and_cache (cache, method,
8336                                                                                 mb, csig, csig->param_count + 16);
8337                 mono_mb_free (mb);
8338                 return res;
8339         }
8340
8341         /* internal calls: we simply push all arguments and call the method (no conversions) */
8342         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
8343
8344                 /* hack - string constructors returns a value */
8345                 if (method->string_ctor) {
8346                         csig = signature_dup (method->klass->image, sig);
8347                         csig->ret = &mono_defaults.string_class->byval_arg;
8348                 } else
8349                         csig = sig;
8350
8351                 if (sig->hasthis)
8352                         mono_mb_emit_byte (mb, CEE_LDARG_0);
8353
8354                 for (i = 0; i < sig->param_count; i++)
8355                         mono_mb_emit_ldarg (mb, i + sig->hasthis);
8356
8357                 g_assert (piinfo->addr);
8358                 mono_mb_emit_native_call (mb, csig, piinfo->addr);
8359                 emit_thread_interrupt_checkpoint (mb);
8360                 mono_mb_emit_byte (mb, CEE_RET);
8361
8362                 csig = signature_dup (method->klass->image, csig);
8363                 csig->pinvoke = 0;
8364                 res = mono_mb_create_and_cache (cache, method,
8365                                                                                 mb, csig, csig->param_count + 16);
8366                 mono_mb_free (mb);
8367                 return res;
8368         }
8369
8370         g_assert (pinvoke);
8371
8372         mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
8373         mono_method_get_marshal_info (method, mspecs);
8374
8375         mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr);
8376
8377         csig = signature_dup (method->klass->image, sig);
8378         csig->pinvoke = 0;
8379         res = mono_mb_create_and_cache (cache, method,
8380                                                                         mb, csig, csig->param_count + 16);
8381         mono_mb_free (mb);
8382
8383         for (i = sig->param_count; i >= 0; i--)
8384                 if (mspecs [i])
8385                         mono_metadata_free_marshal_spec (mspecs [i]);
8386         g_free (mspecs);
8387
8388         /* 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)); */ 
8389
8390         return res;
8391 }
8392
8393 /**
8394  * mono_marshal_get_native_func_wrapper:
8395  * @image: The image to use for memory allocation and for looking up custom marshallers.
8396  * @sig: The signature of the function
8397  * @func: The native function to wrap
8398  *
8399  *   Returns a wrapper method around native functions, similar to the pinvoke
8400  * wrapper.
8401  */
8402 MonoMethod *
8403 mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig, 
8404                                                                           MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
8405 {
8406         MonoMethodSignature *csig;
8407
8408         MonoMethodBuilder *mb;
8409         MonoMethod *res;
8410         GHashTable *cache;
8411         char *name;
8412
8413         cache = image->native_wrapper_cache;
8414         if ((res = mono_marshal_find_in_cache (cache, func)))
8415                 return res;
8416
8417         name = g_strdup_printf ("wrapper_native_%p", func);
8418         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8419         mb->method->save_lmf = 1;
8420
8421         mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func);
8422
8423         csig = signature_dup (image, sig);
8424         csig->pinvoke = 0;
8425         res = mono_mb_create_and_cache (cache, func,
8426                                                                         mb, csig, csig->param_count + 16);
8427         mono_mb_free (mb);
8428
8429         /* 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)); */ 
8430
8431         return res;
8432 }
8433                             
8434 /* FIXME: moving GC */
8435 static void
8436 mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this)
8437 {
8438         MonoMethodSignature *sig, *csig;
8439         int i, *tmp_locals;
8440
8441         sig = m->sig;
8442         csig = m->csig;
8443
8444         /* allocate local 0 (pointer) src_ptr */
8445         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8446         /* allocate local 1 (pointer) dst_ptr */
8447         mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8448         /* allocate local 2 (boolean) delete_old */
8449         mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
8450
8451         if (!MONO_TYPE_IS_VOID(sig->ret)) {
8452                 /* allocate local 3 to store the return value */
8453                 mono_mb_add_local (mb, sig->ret);
8454         }
8455
8456         mono_mb_emit_icon (mb, 0);
8457         mono_mb_emit_stloc (mb, 2);
8458
8459         /* fixme: howto handle this ? */
8460         if (sig->hasthis) {
8461                 if (this) {
8462                         /* FIXME: need a solution for the moving GC here */
8463                         mono_mb_emit_ptr (mb, this);
8464                 } else {
8465                         /* fixme: */
8466                         g_assert_not_reached ();
8467                 }
8468         } 
8469
8470         /* we first do all conversions */
8471         tmp_locals = alloca (sizeof (int) * sig->param_count);
8472         for (i = 0; i < sig->param_count; i ++) {
8473                 MonoType *t = sig->params [i];
8474                 
8475                 switch (t->type) {
8476                 case MONO_TYPE_OBJECT:
8477                 case MONO_TYPE_CLASS:
8478                 case MONO_TYPE_VALUETYPE:
8479                 case MONO_TYPE_ARRAY:
8480                 case MONO_TYPE_SZARRAY:
8481                 case MONO_TYPE_STRING:
8482                         tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
8483
8484                         break;
8485                 default:
8486                         tmp_locals [i] = 0;
8487                         break;
8488                 }
8489         }
8490
8491         emit_thread_interrupt_checkpoint (mb);
8492
8493         for (i = 0; i < sig->param_count; i++) {
8494                 MonoType *t = sig->params [i];
8495
8496                 if (tmp_locals [i]) {
8497                         if (t->byref)
8498                                 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
8499                         else
8500                                 mono_mb_emit_ldloc (mb, tmp_locals [i]);
8501                 }
8502                 else
8503                         mono_mb_emit_ldarg (mb, i);
8504         }
8505
8506         mono_mb_emit_managed_call (mb, method, NULL);
8507
8508         if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
8509                 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8510         }
8511         else
8512         if (!sig->ret->byref) { 
8513                 switch (sig->ret->type) {
8514                 case MONO_TYPE_VOID:
8515                         break;
8516                 case MONO_TYPE_BOOLEAN:
8517                 case MONO_TYPE_I1:
8518                 case MONO_TYPE_U1:
8519                 case MONO_TYPE_I2:
8520                 case MONO_TYPE_U2:
8521                 case MONO_TYPE_I4:
8522                 case MONO_TYPE_U4:
8523                 case MONO_TYPE_I:
8524                 case MONO_TYPE_U:
8525                 case MONO_TYPE_PTR:
8526                 case MONO_TYPE_R4:
8527                 case MONO_TYPE_R8:
8528                 case MONO_TYPE_I8:
8529                 case MONO_TYPE_U8:
8530                 case MONO_TYPE_OBJECT:
8531                         mono_mb_emit_stloc (mb, 3);
8532                         break;
8533                 case MONO_TYPE_STRING:
8534                         csig->ret = &mono_defaults.int_class->byval_arg;
8535                         emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8536                         break;
8537                 case MONO_TYPE_VALUETYPE:
8538                 case MONO_TYPE_CLASS:
8539                 case MONO_TYPE_SZARRAY:
8540                         emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8541                         break;
8542                 default:
8543                         g_warning ("return type 0x%02x unknown", sig->ret->type);       
8544                         g_assert_not_reached ();
8545                 }
8546         } else {
8547                 mono_mb_emit_stloc (mb, 3);
8548         }
8549
8550         /* Convert byref arguments back */
8551         for (i = 0; i < sig->param_count; i ++) {
8552                 MonoType *t = sig->params [i];
8553                 MonoMarshalSpec *spec = mspecs [i + 1];
8554
8555                 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
8556                         emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8557                 }
8558                 else if (t->byref) {
8559                         switch (t->type) {
8560                         case MONO_TYPE_CLASS:
8561                         case MONO_TYPE_VALUETYPE:
8562                         case MONO_TYPE_OBJECT:
8563                                 emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8564                                 break;
8565                         }
8566                 }
8567                 else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
8568                         /* The [Out] information is encoded in the delegate signature */
8569                         switch (t->type) {
8570                         case MONO_TYPE_SZARRAY:
8571                         case MONO_TYPE_CLASS:
8572                         case MONO_TYPE_VALUETYPE:
8573                                 emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8574                                 break;
8575                         default:
8576                                 g_assert_not_reached ();
8577                         }
8578                 }
8579         }
8580
8581         if (m->retobj_var) {
8582                 mono_mb_emit_ldloc (mb, m->retobj_var);
8583                 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8584                 mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
8585         }
8586         else {
8587                 if (!MONO_TYPE_IS_VOID(sig->ret))
8588                         mono_mb_emit_ldloc (mb, 3);
8589                 mono_mb_emit_byte (mb, CEE_RET);
8590         }
8591 }
8592
8593
8594 /*
8595  * generates IL code to call managed methods from unmanaged code 
8596  */
8597 MonoMethod *
8598 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
8599 {
8600         static MonoClass *UnmanagedFunctionPointerAttribute;
8601         MonoMethodSignature *sig, *csig, *invoke_sig;
8602         MonoMethodBuilder *mb;
8603         MonoMethod *res, *invoke;
8604         MonoMarshalSpec **mspecs;
8605         MonoMethodPInvoke piinfo;
8606         GHashTable *cache;
8607         int i;
8608         EmitMarshalContext m;
8609
8610         g_assert (method != NULL);
8611         g_assert (!mono_method_signature (method)->pinvoke);
8612
8613         /* 
8614          * FIXME: Should cache the method+delegate type pair, since the same method
8615          * could be called with different delegates, thus different marshalling
8616          * options.
8617          */
8618         cache = method->klass->image->managed_wrapper_cache;
8619         if (!this && (res = mono_marshal_find_in_cache (cache, method)))
8620                 return res;
8621
8622         invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
8623         invoke_sig = mono_method_signature (invoke);
8624
8625         mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
8626         mono_method_get_marshal_info (invoke, mspecs);
8627
8628         sig = mono_method_signature (method);
8629
8630         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
8631
8632
8633         /* we copy the signature, so that we can modify it */
8634         if (this)
8635                 /* Need to free this later */
8636                 csig = mono_metadata_signature_dup (sig);
8637         else
8638                 csig = signature_dup (method->klass->image, sig);
8639         csig->hasthis = 0;
8640         csig->pinvoke = 1;
8641
8642         m.mb = mb;
8643         m.sig = sig;
8644         m.piinfo = NULL;
8645         m.retobj_var = 0;
8646         m.csig = csig;
8647         m.image = method->klass->image;
8648
8649 #ifdef PLATFORM_WIN32
8650         /* 
8651          * Under windows, delegates passed to native code must use the STDCALL
8652          * calling convention.
8653          */
8654         csig->call_convention = MONO_CALL_STDCALL;
8655 #endif
8656
8657         /* Change default calling convention if needed */
8658         /* Why is this a modopt ? */
8659         if (invoke_sig->ret && invoke_sig->ret->num_mods) {
8660                 for (i = 0; i < invoke_sig->ret->num_mods; ++i) {
8661                         MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token);
8662                         g_assert (cmod_class);
8663                         if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
8664                                 if (!strcmp (cmod_class->name, "CallConvCdecl"))
8665                                         csig->call_convention = MONO_CALL_C;
8666                                 else if (!strcmp (cmod_class->name, "CallConvStdcall"))
8667                                         csig->call_convention = MONO_CALL_STDCALL;
8668                                 else if (!strcmp (cmod_class->name, "CallConvFastcall"))
8669                                         csig->call_convention = MONO_CALL_FASTCALL;
8670                                 else if (!strcmp (cmod_class->name, "CallConvThiscall"))
8671                                         csig->call_convention = MONO_CALL_THISCALL;
8672                         }
8673                 }
8674         }
8675
8676         /* Handle the UnmanagedFunctionPointerAttribute */
8677         if (!UnmanagedFunctionPointerAttribute)
8678                 UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
8679
8680         /* The attribute is only available in Net 2.0 */
8681         if (UnmanagedFunctionPointerAttribute) {
8682                 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
8683                 MonoCustomAttrInfo *cinfo;
8684
8685                 /* 
8686                  * The pinvoke attributes are stored in a real custom attribute so we have to
8687                  * construct it.
8688                  */
8689                 cinfo = mono_custom_attrs_from_class (delegate_klass);
8690                 if (cinfo) {
8691                         attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
8692                         if (attr) {
8693                                 memset (&piinfo, 0, sizeof (piinfo));
8694                                 m.piinfo = &piinfo;
8695                                 piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
8696
8697                                 csig->call_convention = attr->call_conv - 1;
8698                         }
8699                         if (!cinfo->cached)
8700                                 mono_custom_attrs_free (cinfo);
8701                 }
8702         }
8703
8704         mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this);
8705
8706         if (!this)
8707                 res = mono_mb_create_and_cache (cache, method,
8708                                                                                          mb, csig, sig->param_count + 16);
8709         else {
8710                 mb->dynamic = 1;
8711                 res = mono_mb_create_method (mb, csig, sig->param_count + 16);
8712         }
8713         mono_mb_free (mb);
8714
8715         for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
8716                 if (mspecs [i])
8717                         mono_metadata_free_marshal_spec (mspecs [i]);
8718         g_free (mspecs);
8719
8720         /* 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)); */
8721
8722         return res;
8723 }
8724
8725 static MonoReflectionType *
8726 type_from_handle (MonoType *handle)
8727 {
8728         MonoDomain *domain = mono_domain_get (); 
8729         MonoClass *klass = mono_class_from_mono_type (handle);
8730
8731         MONO_ARCH_SAVE_REGS;
8732
8733         mono_class_init (klass);
8734         return mono_type_get_object (domain, handle);
8735 }
8736
8737 /*
8738  * mono_marshal_get_isinst:
8739  * @klass: the type of the field
8740  *
8741  * This method generates a function which can be used to check if an object is
8742  * an instance of the given type, icluding the case where the object is a proxy.
8743  * The generated function has the following signature:
8744  * MonoObject* __isinst_wrapper_ (MonoObject *obj)
8745  */
8746 MonoMethod *
8747 mono_marshal_get_isinst (MonoClass *klass)
8748 {
8749         static MonoMethodSignature *isint_sig = NULL;
8750         GHashTable *cache;
8751         MonoMethod *res;
8752         int pos_was_ok, pos_failed, pos_end, pos_end2;
8753         char *name;
8754         MonoMethodBuilder *mb;
8755
8756         cache = klass->image->isinst_cache;
8757         if ((res = mono_marshal_find_in_cache (cache, klass)))
8758                 return res;
8759
8760         if (!isint_sig) {
8761                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
8762                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
8763                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
8764                 isint_sig->pinvoke = 0;
8765         }
8766         
8767         name = g_strdup_printf ("__isinst_wrapper_%s", klass->name); 
8768         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ISINST);
8769         g_free (name);
8770         
8771         mb->method->save_lmf = 1;
8772
8773         /* check if the object is a proxy that needs special cast */
8774         mono_mb_emit_ldarg (mb, 0);
8775         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8776         mono_mb_emit_op (mb, CEE_MONO_CISINST, klass);
8777
8778         /* The result of MONO_ISINST can be:
8779                 0) the type check succeeded
8780                 1) the type check did not succeed
8781                 2) a CanCastTo call is needed */
8782         
8783         mono_mb_emit_byte (mb, CEE_DUP);
8784         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
8785
8786         mono_mb_emit_byte (mb, CEE_LDC_I4_2);
8787         pos_failed = mono_mb_emit_branch (mb, CEE_BNE_UN);
8788         
8789         /* get the real proxy from the transparent proxy*/
8790
8791         mono_mb_emit_ldarg (mb, 0);
8792         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
8793         pos_end = mono_mb_emit_branch (mb, CEE_BR);
8794         
8795         /* fail */
8796         
8797         mono_mb_patch_branch (mb, pos_failed);
8798         mono_mb_emit_byte (mb, CEE_LDNULL);
8799         pos_end2 = mono_mb_emit_branch (mb, CEE_BR);
8800         
8801         /* success */
8802         
8803         mono_mb_patch_branch (mb, pos_was_ok);
8804         mono_mb_emit_byte (mb, CEE_POP);
8805         mono_mb_emit_ldarg (mb, 0);
8806         
8807         /* the end */
8808         
8809         mono_mb_patch_branch (mb, pos_end);
8810         mono_mb_patch_branch (mb, pos_end2);
8811         mono_mb_emit_byte (mb, CEE_RET);
8812
8813         res = mono_mb_create_and_cache (cache, klass, mb, isint_sig, isint_sig->param_count + 16);
8814         mono_mb_free (mb);
8815
8816         return res;
8817 }
8818
8819 /*
8820  * mono_marshal_get_castclass:
8821  * @klass: the type of the field
8822  *
8823  * This method generates a function which can be used to cast an object to
8824  * an instance of the given type, icluding the case where the object is a proxy.
8825  * The generated function has the following signature:
8826  * MonoObject* __castclass_wrapper_ (MonoObject *obj)
8827  */
8828 MonoMethod *
8829 mono_marshal_get_castclass (MonoClass *klass)
8830 {
8831         static MonoMethodSignature *castclass_sig = NULL;
8832         GHashTable *cache;
8833         MonoMethod *res;
8834         int pos_was_ok, pos_was_ok2;
8835         char *name;
8836         MonoMethodBuilder *mb;
8837
8838         cache = klass->image->castclass_cache;
8839         if ((res = mono_marshal_find_in_cache (cache, klass)))
8840                 return res;
8841
8842         if (!castclass_sig) {
8843                 castclass_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
8844                 castclass_sig->params [0] = &mono_defaults.object_class->byval_arg;
8845                 castclass_sig->ret = &mono_defaults.object_class->byval_arg;
8846                 castclass_sig->pinvoke = 0;
8847         }
8848         
8849         name = g_strdup_printf ("__castclass_wrapper_%s", klass->name); 
8850         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_CASTCLASS);
8851         g_free (name);
8852         
8853         mb->method->save_lmf = 1;
8854
8855         /* check if the object is a proxy that needs special cast */
8856         mono_mb_emit_ldarg (mb, 0);
8857         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8858         mono_mb_emit_op (mb, CEE_MONO_CCASTCLASS, klass);
8859
8860         /* The result of MONO_ISINST can be:
8861                 0) the cast is valid
8862                 1) cast of unknown proxy type
8863                 or an exception if the cast is is invalid
8864         */
8865         
8866         pos_was_ok = mono_mb_emit_branch (mb, CEE_BRFALSE);
8867
8868         /* get the real proxy from the transparent proxy*/
8869
8870         mono_mb_emit_ldarg (mb, 0);
8871         mono_mb_emit_managed_call (mb, mono_marshal_get_proxy_cancast (klass), NULL);
8872         pos_was_ok2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
8873         
8874         /* fail */
8875         mono_mb_emit_exception (mb, "InvalidCastException", NULL);
8876         
8877         /* success */
8878         mono_mb_patch_branch (mb, pos_was_ok);
8879         mono_mb_patch_branch (mb, pos_was_ok2);
8880         mono_mb_emit_ldarg (mb, 0);
8881         
8882         /* the end */
8883         mono_mb_emit_byte (mb, CEE_RET);
8884
8885         res = mono_mb_create_and_cache (cache, klass, mb, castclass_sig, castclass_sig->param_count + 16);
8886         mono_mb_free (mb);
8887
8888         return res;
8889 }
8890
8891 MonoMethod *
8892 mono_marshal_get_proxy_cancast (MonoClass *klass)
8893 {
8894         static MonoMethodSignature *isint_sig = NULL;
8895         GHashTable *cache;
8896         MonoMethod *res;
8897         int pos_failed, pos_end;
8898         char *name;
8899         MonoMethod *can_cast_to;
8900         MonoMethodDesc *desc;
8901         MonoMethodBuilder *mb;
8902
8903         cache = klass->image->proxy_isinst_cache;
8904         if ((res = mono_marshal_find_in_cache (cache, klass)))
8905                 return res;
8906
8907         if (!isint_sig) {
8908                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
8909                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
8910                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
8911                 isint_sig->pinvoke = 0;
8912         }
8913         
8914         name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass->name); 
8915         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
8916         g_free (name);
8917         
8918         mb->method->save_lmf = 1;
8919
8920         /* get the real proxy from the transparent proxy*/
8921         mono_mb_emit_ldarg (mb, 0);
8922         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
8923         mono_mb_emit_byte (mb, CEE_LDIND_REF);
8924         
8925         /* get the reflection type from the type handle */
8926         mono_mb_emit_ptr (mb, &klass->byval_arg);
8927         mono_mb_emit_icall (mb, type_from_handle);
8928         
8929         mono_mb_emit_ldarg (mb, 0);
8930         
8931         /* make the call to CanCastTo (type, ob) */
8932         desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
8933         can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
8934         g_assert (can_cast_to);
8935         mono_method_desc_free (desc);
8936         mono_mb_emit_op (mb, CEE_CALLVIRT, can_cast_to);
8937         
8938         pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
8939
8940         /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
8941         mono_mb_emit_ptr (mb, &klass->byval_arg);
8942         mono_mb_emit_icall (mb, type_from_handle);
8943         mono_mb_emit_ldarg (mb, 0);
8944         
8945         mono_mb_emit_icall (mb, mono_upgrade_remote_class_wrapper);
8946         emit_thread_interrupt_checkpoint (mb);
8947         
8948         mono_mb_emit_ldarg (mb, 0);
8949         pos_end = mono_mb_emit_branch (mb, CEE_BR);
8950         
8951         /* fail */
8952         
8953         mono_mb_patch_branch (mb, pos_failed);
8954         mono_mb_emit_byte (mb, CEE_LDNULL);
8955         
8956         /* the end */
8957         
8958         mono_mb_patch_branch (mb, pos_end);
8959         mono_mb_emit_byte (mb, CEE_RET);
8960
8961         res = mono_mb_create_and_cache (cache, klass, mb, isint_sig, isint_sig->param_count + 16);
8962         mono_mb_free (mb);
8963
8964         return res;
8965 }
8966
8967 void
8968 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy)
8969 {
8970         MonoClass *klass;
8971         MonoDomain *domain = ((MonoObject*)tproxy)->vtable->domain;
8972         klass = mono_class_from_mono_type (rtype->type);
8973         mono_upgrade_remote_class (domain, (MonoObject*)tproxy, klass);
8974 }
8975
8976 /**
8977  * mono_marshal_get_struct_to_ptr:
8978  * @klass:
8979  *
8980  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
8981  */
8982 MonoMethod *
8983 mono_marshal_get_struct_to_ptr (MonoClass *klass)
8984 {
8985         MonoMethodBuilder *mb;
8986         static MonoMethod *stoptr = NULL;
8987         MonoMethod *res;
8988
8989         g_assert (klass != NULL);
8990
8991         mono_marshal_load_type_info (klass);
8992
8993         if (klass->marshal_info->str_to_ptr)
8994                 return klass->marshal_info->str_to_ptr;
8995
8996         if (!stoptr) 
8997                 stoptr = mono_class_get_method_from_name (mono_defaults.marshal_class, "StructureToPtr", 3);
8998         g_assert (stoptr);
8999
9000         mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
9001
9002         if (klass->blittable) {
9003                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9004                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9005                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9006                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9007                 mono_mb_emit_byte (mb, CEE_PREFIX1);
9008                 mono_mb_emit_byte (mb, CEE_CPBLK);
9009         } else {
9010
9011                 /* allocate local 0 (pointer) src_ptr */
9012                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9013                 /* allocate local 1 (pointer) dst_ptr */
9014                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9015                 /* allocate local 2 (boolean) delete_old */
9016                 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
9017                 mono_mb_emit_byte (mb, CEE_LDARG_2);
9018                 mono_mb_emit_stloc (mb, 2);
9019
9020                 /* initialize src_ptr to point to the start of object data */
9021                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9022                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9023                 mono_mb_emit_stloc (mb, 0);
9024
9025                 /* initialize dst_ptr */
9026                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9027                 mono_mb_emit_stloc (mb, 1);
9028
9029                 emit_struct_conv (mb, klass, FALSE);
9030         }
9031
9032         mono_mb_emit_byte (mb, CEE_RET);
9033
9034         res = mono_mb_create_method (mb, mono_method_signature (stoptr), 0);
9035         mono_mb_free (mb);
9036
9037         klass->marshal_info->str_to_ptr = res;
9038         return res;
9039 }
9040
9041 /**
9042  * mono_marshal_get_ptr_to_struct:
9043  * @klass:
9044  *
9045  * generates IL code for PtrToStructure (IntPtr src, object structure)
9046  */
9047 MonoMethod *
9048 mono_marshal_get_ptr_to_struct (MonoClass *klass)
9049 {
9050         MonoMethodBuilder *mb;
9051         static MonoMethodSignature *ptostr = NULL;
9052         MonoMethod *res;
9053
9054         g_assert (klass != NULL);
9055
9056         mono_marshal_load_type_info (klass);
9057
9058         if (klass->marshal_info->ptr_to_str)
9059                 return klass->marshal_info->ptr_to_str;
9060
9061         if (!ptostr)
9062                 /* Create the signature corresponding to
9063                           static void PtrToStructure (IntPtr ptr, object structure);
9064                    defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9065                 ptostr = mono_create_icall_signature ("void ptr object");
9066
9067         mb = mono_mb_new (klass, "PtrToStructure", MONO_WRAPPER_UNKNOWN);
9068
9069         if (klass->blittable) {
9070                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9071                 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9072                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9073                 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9074                 mono_mb_emit_byte (mb, CEE_PREFIX1);
9075                 mono_mb_emit_byte (mb, CEE_CPBLK);
9076         } else {
9077
9078                 /* allocate local 0 (pointer) src_ptr */
9079                 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9080                 /* allocate local 1 (pointer) dst_ptr */
9081                 mono_mb_add_local (mb, &klass->this_arg);
9082                 
9083                 /* initialize src_ptr to point to the start of object data */
9084                 mono_mb_emit_byte (mb, CEE_LDARG_0);
9085                 mono_mb_emit_stloc (mb, 0);
9086
9087                 /* initialize dst_ptr */
9088                 mono_mb_emit_byte (mb, CEE_LDARG_1);
9089                 mono_mb_emit_op (mb, CEE_UNBOX, klass);
9090                 mono_mb_emit_stloc (mb, 1);
9091
9092                 emit_struct_conv (mb, klass, TRUE);
9093         }
9094
9095         mono_mb_emit_byte (mb, CEE_RET);
9096
9097         res = mono_mb_create_method (mb, ptostr, 0);
9098         mono_mb_free (mb);
9099
9100         klass->marshal_info->ptr_to_str = res;
9101         return res;
9102 }
9103
9104 /*
9105  * generates IL code for the synchronized wrapper: the generated method
9106  * calls METHOD while locking 'this' or the parent type.
9107  */
9108 MonoMethod *
9109 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
9110 {
9111         static MonoMethod *enter_method, *exit_method;
9112         MonoMethodSignature *sig;
9113         MonoExceptionClause *clause;
9114         MonoMethodHeader *header;
9115         MonoMethodBuilder *mb;
9116         MonoMethod *res;
9117         GHashTable *cache;
9118         int i, pos, this_local, ret_local = 0;
9119
9120         g_assert (method);
9121
9122         if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
9123                 return method;
9124
9125         cache = method->klass->image->synchronized_cache;
9126         if ((res = mono_marshal_find_in_cache (cache, method)))
9127                 return res;
9128
9129         sig = signature_dup (method->klass->image, mono_method_signature (method));
9130         sig->pinvoke = 0;
9131
9132         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
9133
9134         /* result */
9135         if (!MONO_TYPE_IS_VOID (sig->ret))
9136                 ret_local = mono_mb_add_local (mb, sig->ret);
9137
9138         /* this */
9139         this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
9140
9141         mono_loader_lock ();
9142         clause = mono_mempool_alloc0 (method->klass->image->mempool, sizeof (MonoExceptionClause));
9143         mono_loader_unlock ();
9144         clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
9145
9146         if (!enter_method) {
9147                 MonoMethodDesc *desc;
9148
9149                 desc = mono_method_desc_new ("Monitor:Enter", FALSE);
9150                 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9151                 g_assert (enter_method);
9152                 mono_method_desc_free (desc);
9153                 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
9154                 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9155                 g_assert (exit_method);
9156                 mono_method_desc_free (desc);
9157         }
9158
9159         /* Push this or the type object */
9160         if (method->flags & METHOD_ATTRIBUTE_STATIC) {
9161                 /*
9162                  * GetTypeFromHandle isn't called as a managed method because it has
9163                  * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
9164                  * transformed into something else by the JIT.
9165                  */
9166                 mono_mb_emit_ptr (mb, &method->klass->byval_arg);
9167                 mono_mb_emit_icall (mb, type_from_handle);
9168         }
9169         else
9170                 mono_mb_emit_ldarg (mb, 0);
9171         mono_mb_emit_stloc (mb, this_local);
9172
9173         /* Call Monitor::Enter() */
9174         mono_mb_emit_ldloc (mb, this_local);
9175         mono_mb_emit_managed_call (mb, enter_method, NULL);
9176
9177         clause->try_offset = mono_mb_get_label (mb);
9178
9179         /* Call the method */
9180         if (sig->hasthis)
9181                 mono_mb_emit_ldarg (mb, 0);
9182         for (i = 0; i < sig->param_count; i++)
9183                 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
9184         
9185         /* this is needed to avoid recursion */
9186         mono_mb_emit_byte (mb, CEE_PREFIX1);
9187         mono_mb_emit_op (mb, CEE_LDFTN, method);
9188         mono_mb_emit_calli (mb, mono_method_signature (method));
9189
9190         if (!MONO_TYPE_IS_VOID (sig->ret))
9191                 mono_mb_emit_stloc (mb, ret_local);
9192
9193         pos = mono_mb_emit_branch (mb, CEE_LEAVE);
9194
9195         clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
9196         clause->handler_offset = mono_mb_get_label (mb);
9197
9198         /* Call Monitor::Exit() */
9199         mono_mb_emit_ldloc (mb, this_local);
9200 /*      mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */
9201         mono_mb_emit_managed_call (mb, exit_method, NULL);
9202         mono_mb_emit_byte (mb, CEE_ENDFINALLY);
9203
9204         clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
9205
9206         mono_mb_patch_branch (mb, pos);
9207         if (!MONO_TYPE_IS_VOID (sig->ret))
9208                 mono_mb_emit_ldloc (mb, ret_local);
9209         mono_mb_emit_byte (mb, CEE_RET);
9210
9211         res = mono_mb_create_and_cache (cache, method,
9212                                                                         mb, sig, sig->param_count + 16);
9213         mono_mb_free (mb);
9214
9215         header = ((MonoMethodNormal *)res)->header;
9216         header->num_clauses = 1;
9217         header->clauses = clause;
9218
9219         return res;     
9220 }
9221
9222
9223 /*
9224  * the returned method calls 'method' unboxing the this argument
9225  */
9226 MonoMethod *
9227 mono_marshal_get_unbox_wrapper (MonoMethod *method)
9228 {
9229         MonoMethodSignature *sig = mono_method_signature (method);
9230         int i;
9231         MonoMethodBuilder *mb;
9232         MonoMethod *res;
9233         GHashTable *cache;
9234
9235         cache = method->klass->image->unbox_wrapper_cache;
9236         if ((res = mono_marshal_find_in_cache (cache, method)))
9237                 return res;
9238
9239         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNBOX);
9240
9241         g_assert (sig->hasthis);
9242         
9243         mono_mb_emit_ldarg (mb, 0); 
9244         mono_mb_emit_icon (mb, sizeof (MonoObject));
9245         mono_mb_emit_byte (mb, CEE_ADD);
9246         for (i = 0; i < sig->param_count; ++i)
9247                 mono_mb_emit_ldarg (mb, i + 1);
9248         mono_mb_emit_managed_call (mb, method, NULL);
9249         mono_mb_emit_byte (mb, CEE_RET);
9250
9251         res = mono_mb_create_and_cache (cache, method,
9252                                                                                  mb, sig, sig->param_count + 16);
9253         mono_mb_free (mb);
9254
9255         /* 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)); */
9256
9257         return res;     
9258 }
9259
9260 MonoMethod*
9261 mono_marshal_get_stelemref ()
9262 {
9263         static MonoMethod* ret = NULL;
9264         MonoMethodSignature *sig;
9265         MonoMethodBuilder *mb;
9266         
9267         guint32 b1, b2, b3, b4;
9268         guint32 copy_pos;
9269         int aklass, vklass;
9270         int array_slot_addr;
9271         
9272         if (ret)
9273                 return ret;
9274         
9275         mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
9276         
9277
9278         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9279
9280         /* void stelemref (void* array, int idx, void* value) */
9281         sig->ret = &mono_defaults.void_class->byval_arg;
9282         sig->params [0] = &mono_defaults.object_class->byval_arg;
9283         sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
9284         sig->params [2] = &mono_defaults.object_class->byval_arg;
9285                 
9286         aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9287         vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9288         array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
9289         
9290         /*
9291         the method:
9292         <ldelema (bound check)>
9293         if (!value)
9294                 goto store;
9295         
9296         aklass = array->vtable->klass->element_class;
9297         vklass = value->vtable->klass;
9298         
9299         if (vklass->idepth < aklass->idepth)
9300                 goto long;
9301         
9302         if (vklass->supertypes [aklass->idepth - 1] != aklass)
9303                 goto long;
9304         
9305         store:
9306                 *array_slot_addr = value;
9307                 return;
9308         
9309         long:
9310                 if (mono_object_isinst (value, aklass))
9311                         goto store;
9312                 
9313                 throw new ArrayTypeMismatchException ();
9314         */
9315         
9316         /* ldelema (implicit bound check) */
9317         mono_mb_emit_ldarg (mb, 0);
9318         mono_mb_emit_ldarg (mb, 1);
9319         mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
9320         mono_mb_emit_stloc (mb, array_slot_addr);
9321                 
9322         /* if (!value) goto do_store */
9323         mono_mb_emit_ldarg (mb, 2);
9324         b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
9325         
9326         /* aklass = array->vtable->klass->element_class */
9327         mono_mb_emit_ldarg (mb, 0);
9328         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
9329         mono_mb_emit_byte (mb, CEE_LDIND_I);
9330         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
9331         mono_mb_emit_byte (mb, CEE_LDIND_I);
9332         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, element_class));
9333         mono_mb_emit_byte (mb, CEE_LDIND_I);
9334         mono_mb_emit_stloc (mb, aklass);
9335         
9336         /* vklass = value->vtable->klass */
9337         mono_mb_emit_ldarg (mb, 2);
9338         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
9339         mono_mb_emit_byte (mb, CEE_LDIND_I);
9340         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoVTable, klass));
9341         mono_mb_emit_byte (mb, CEE_LDIND_I);
9342         mono_mb_emit_stloc (mb, vklass);
9343         
9344         /* if (vklass->idepth < aklass->idepth) goto failue */
9345         mono_mb_emit_ldloc (mb, vklass);
9346         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
9347         mono_mb_emit_byte (mb, CEE_LDIND_U2);
9348         
9349         mono_mb_emit_ldloc (mb, aklass);
9350         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
9351         mono_mb_emit_byte (mb, CEE_LDIND_U2);
9352         
9353         b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
9354         
9355         /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
9356         mono_mb_emit_ldloc (mb, vklass);
9357         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, supertypes));
9358         mono_mb_emit_byte (mb, CEE_LDIND_I);
9359         
9360         mono_mb_emit_ldloc (mb, aklass);
9361         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoClass, idepth));
9362         mono_mb_emit_byte (mb, CEE_LDIND_U2);
9363         mono_mb_emit_icon (mb, 1);
9364         mono_mb_emit_byte (mb, CEE_SUB);
9365         mono_mb_emit_icon (mb, sizeof (void*));
9366         mono_mb_emit_byte (mb, CEE_MUL);
9367         mono_mb_emit_byte (mb, CEE_ADD);
9368         mono_mb_emit_byte (mb, CEE_LDIND_I);
9369         
9370         mono_mb_emit_ldloc (mb, aklass);
9371         
9372         b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
9373         
9374         copy_pos = mono_mb_get_label (mb);
9375         /* do_store */
9376         mono_mb_patch_branch (mb, b1);
9377         mono_mb_emit_ldloc (mb, array_slot_addr);
9378         mono_mb_emit_ldarg (mb, 2);
9379         mono_mb_emit_byte (mb, CEE_STIND_REF);
9380         
9381         mono_mb_emit_byte (mb, CEE_RET);
9382         
9383         /* the hard way */
9384         mono_mb_patch_branch (mb, b2);
9385         mono_mb_patch_branch (mb, b3);
9386         
9387         mono_mb_emit_ldarg (mb, 2);
9388         mono_mb_emit_ldloc (mb, aklass);
9389         mono_mb_emit_icall (mb, mono_object_isinst);
9390         
9391         b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
9392         mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
9393         mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
9394         
9395         mono_mb_emit_byte (mb, CEE_RET);
9396         ret = mono_mb_create_method (mb, sig, 4);
9397         mono_mb_free (mb);
9398         return ret;
9399 }
9400
9401 typedef struct {
9402         int rank;
9403         int elem_size;
9404         MonoMethod *method;
9405 } ArrayElemAddr;
9406
9407 /* LOCKING: vars accessed under the marshal lock */
9408 static ArrayElemAddr *elem_addr_cache = NULL;
9409 static int elem_addr_cache_size = 0;
9410 static int elem_addr_cache_next = 0;
9411
9412 /**
9413  * mono_marshal_get_array_address:
9414  * @rank: rank of the array type
9415  * @elem_size: size in bytes of an element of an array.
9416  *
9417  * Returns a MonoMethd that implements the code to get the address
9418  * of an element in a multi-dimenasional array of @rank dimensions.
9419  * The returned method takes an array as the first argument and then
9420  * @rank indexes for the @rank dimensions.
9421  */
9422 MonoMethod*
9423 mono_marshal_get_array_address (int rank, int elem_size)
9424 {
9425         MonoMethod *ret;
9426         MonoMethodBuilder *mb;
9427         MonoMethodSignature *sig;
9428         int i, bounds, ind, realidx;
9429         int branch_pos, *branch_positions;
9430         int cached;
9431
9432         ret = NULL;
9433         mono_marshal_lock ();
9434         for (i = 0; i < elem_addr_cache_next; ++i) {
9435                 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
9436                         ret = elem_addr_cache [i].method;
9437                         break;
9438                 }
9439         }
9440         mono_marshal_unlock ();
9441         if (ret)
9442                 return ret;
9443
9444         branch_positions = g_new0 (int, rank);
9445
9446         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank);
9447
9448         /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
9449         sig->ret = &mono_defaults.int_class->byval_arg;
9450         sig->params [0] = &mono_defaults.object_class->byval_arg;
9451         for (i = 0; i < rank; ++i) {
9452                 sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
9453         }
9454
9455         mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED);
9456         
9457         bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9458         ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
9459         realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
9460
9461         /* bounds = array->bounds; */
9462         mono_mb_emit_ldarg (mb, 0);
9463         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, bounds));
9464         mono_mb_emit_byte (mb, CEE_LDIND_I);
9465         mono_mb_emit_stloc (mb, bounds);
9466
9467         /* ind is the overall element index, realidx is the partial index in a single dimension */
9468         /* ind = idx0 - bounds [0].lower_bound */
9469         mono_mb_emit_ldarg (mb, 1);
9470         mono_mb_emit_ldloc (mb, bounds);
9471         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
9472         mono_mb_emit_byte (mb, CEE_ADD);
9473         mono_mb_emit_byte (mb, CEE_LDIND_I4);
9474         mono_mb_emit_byte (mb, CEE_SUB);
9475         mono_mb_emit_stloc (mb, ind);
9476         /* if (ind >= bounds [0].length) goto exeception; */
9477         mono_mb_emit_ldloc (mb, ind);
9478         mono_mb_emit_ldloc (mb, bounds);
9479         mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, length));
9480         mono_mb_emit_byte (mb, CEE_ADD);
9481         mono_mb_emit_byte (mb, CEE_LDIND_I4);
9482         /* note that we use unsigned comparison */
9483         branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
9484
9485         /* For large ranks (> 4?) use a loop n IL later to reduce code size.
9486          * We could also decide to ignore the passed elem_size and get it
9487          * from the array object, to reduce the number of methods we generate:
9488          * the additional cost is 3 memory loads and a non-immediate mul.
9489          */
9490         for (i = 1; i < rank; ++i) {
9491                 /* realidx = idxi - bounds [i].lower_bound */
9492                 mono_mb_emit_ldarg (mb, 1 + i);
9493                 mono_mb_emit_ldloc (mb, bounds);
9494                 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
9495                 mono_mb_emit_byte (mb, CEE_ADD);
9496                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
9497                 mono_mb_emit_byte (mb, CEE_SUB);
9498                 mono_mb_emit_stloc (mb, realidx);
9499                 /* if (realidx >= bounds [i].length) goto exeception; */
9500                 mono_mb_emit_ldloc (mb, realidx);
9501                 mono_mb_emit_ldloc (mb, bounds);
9502                 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
9503                 mono_mb_emit_byte (mb, CEE_ADD);
9504                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
9505                 branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
9506                 /* ind = ind * bounds [i].length + realidx */
9507                 mono_mb_emit_ldloc (mb, ind);
9508                 mono_mb_emit_ldloc (mb, bounds);
9509                 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
9510                 mono_mb_emit_byte (mb, CEE_ADD);
9511                 mono_mb_emit_byte (mb, CEE_LDIND_I4);
9512                 mono_mb_emit_byte (mb, CEE_MUL);
9513                 mono_mb_emit_ldloc (mb, realidx);
9514                 mono_mb_emit_byte (mb, CEE_ADD);
9515                 mono_mb_emit_stloc (mb, ind);
9516         }
9517
9518         /* return array->vector + ind * element_size */
9519         mono_mb_emit_ldarg (mb, 0);
9520         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
9521         mono_mb_emit_ldloc (mb, ind);
9522         mono_mb_emit_icon (mb, elem_size);
9523         mono_mb_emit_byte (mb, CEE_MUL);
9524         mono_mb_emit_byte (mb, CEE_ADD);
9525         mono_mb_emit_byte (mb, CEE_RET);
9526
9527         /* patch the branches to get here and throw */
9528         for (i = 1; i < rank; ++i) {
9529                 mono_mb_patch_branch (mb, branch_positions [i]);
9530         }
9531         mono_mb_patch_branch (mb, branch_pos);
9532         /* throw exception */
9533         mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
9534
9535         g_free (branch_positions);
9536         ret = mono_mb_create_method (mb, sig, 4);
9537         mono_mb_free (mb);
9538
9539         /* cache the result */
9540         cached = 0;
9541         mono_marshal_lock ();
9542         for (i = 0; i < elem_addr_cache_next; ++i) {
9543                 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
9544                         /* FIXME: free ret */
9545                         ret = elem_addr_cache [i].method;
9546                         cached = TRUE;
9547                         break;
9548                 }
9549         }
9550         if (!cached) {
9551                 if (elem_addr_cache_next >= elem_addr_cache_size) {
9552                         int new_size = elem_addr_cache_size + 4;
9553                         ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size);
9554                         memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr));
9555                         g_free (elem_addr_cache);
9556                         elem_addr_cache = new_array;
9557                         elem_addr_cache_size = new_size;
9558                 }
9559                 elem_addr_cache [elem_addr_cache_next].rank = rank;
9560                 elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
9561                 elem_addr_cache [elem_addr_cache_next].method = ret;
9562         }
9563         mono_marshal_unlock ();
9564         return ret;
9565 }
9566
9567 MonoMethod*
9568 mono_marshal_get_write_barrier (void)
9569 {
9570         static MonoMethod* ret = NULL;
9571         MonoMethodSignature *sig;
9572         MonoMethodBuilder *mb;
9573         int max_stack = 2;
9574
9575         if (ret)
9576                 return ret;
9577         
9578         mb = mono_mb_new (mono_defaults.object_class, "writebarrier", MONO_WRAPPER_WRITE_BARRIER);
9579
9580         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
9581
9582         /* void writebarrier (MonoObject** addr, MonoObject* obj) */
9583         sig->ret = &mono_defaults.void_class->byval_arg;
9584         sig->params [0] = &mono_defaults.object_class->this_arg;
9585         sig->params [1] = &mono_defaults.object_class->byval_arg;
9586
9587         /* just the store right now: add an hook for the GC to use, maybe something
9588          * that can be used for stelemref as well
9589          * We need a write barrier variant to be used with struct copies as well, though
9590          * there are also other approaches possible, like writing a wrapper specific to
9591          * the struct or to the reference pattern in the struct...
9592          * Depending on the GC, we may want variants that take the object we store to
9593          * when it is available.
9594          */
9595         mono_mb_emit_ldarg (mb, 0);
9596         mono_mb_emit_ldarg (mb, 1);
9597         mono_mb_emit_icall (mb, mono_gc_wbarrier_generic_store);
9598         /*mono_mb_emit_byte (mb, CEE_STIND_REF);*/
9599
9600         mono_mb_emit_byte (mb, CEE_RET);
9601
9602         ret = mono_mb_create_method (mb, sig, max_stack);
9603         mono_mb_free (mb);
9604         return ret;
9605 }
9606
9607 void*
9608 mono_marshal_alloc (gulong size)
9609 {
9610         gpointer res;
9611
9612 #ifdef PLATFORM_WIN32
9613         res = CoTaskMemAlloc (size);
9614 #else
9615         res = g_try_malloc ((gulong)size);
9616         if (!res)
9617                 mono_gc_out_of_memory ((gulong)size);
9618 #endif
9619         return res;
9620 }
9621
9622 void
9623 mono_marshal_free (gpointer ptr)
9624 {
9625 #ifdef PLATFORM_WIN32
9626         CoTaskMemFree (ptr);
9627 #else
9628         g_free (ptr);
9629 #endif
9630 }
9631
9632 void
9633 mono_marshal_free_array (gpointer *ptr, int size) 
9634 {
9635         int i;
9636
9637         if (!ptr)
9638                 return;
9639
9640         for (i = 0; i < size; i++)
9641                 if (ptr [i])
9642                         g_free (ptr [i]);
9643 }
9644
9645 void *
9646 mono_marshal_string_to_utf16 (MonoString *s)
9647 {
9648         return s ? mono_string_chars (s) : NULL;
9649 }
9650
9651 static void *
9652 mono_marshal_string_to_utf16_copy (MonoString *s)
9653 {
9654         if (s == NULL) {
9655                 return NULL;
9656         } else {
9657                 gunichar2 *res = mono_marshal_alloc ((mono_string_length (s) * 2) + 2);
9658                 memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
9659                 res [mono_string_length (s)] = 0;
9660                 return res;
9661         }
9662 }
9663
9664 /**
9665  * mono_marshal_set_last_error:
9666  *
9667  * This function is invoked to set the last error value from a P/Invoke call
9668  * which has SetLastError set.
9669  */
9670 void
9671 mono_marshal_set_last_error (void)
9672 {
9673 #ifdef WIN32
9674         TlsSetValue (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
9675 #else
9676         TlsSetValue (last_error_tls_id, GINT_TO_POINTER (errno));
9677 #endif
9678 }
9679
9680 static void
9681 mono_marshal_set_last_error_windows (int error)
9682 {
9683 #ifdef WIN32
9684         TlsSetValue (last_error_tls_id, GINT_TO_POINTER (error));
9685 #endif
9686 }
9687
9688 void
9689 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
9690                                                                     gpointer dest, gint32 length)
9691 {
9692         int element_size;
9693         void *source_addr;
9694
9695         MONO_ARCH_SAVE_REGS;
9696
9697         MONO_CHECK_ARG_NULL (src);
9698         MONO_CHECK_ARG_NULL (dest);
9699
9700         if (src->obj.vtable->klass->rank != 1)
9701                 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
9702         if (start_index < 0)
9703                 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
9704         if (length < 0)
9705                 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
9706         if (start_index + length > mono_array_length (src))
9707                 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
9708
9709         element_size = mono_array_element_size (src->obj.vtable->klass);
9710
9711         /* no references should be involved */
9712         source_addr = mono_array_addr_with_size (src, element_size, start_index);
9713
9714         memcpy (dest, source_addr, length * element_size);
9715 }
9716
9717 void
9718 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
9719                                                                       MonoArray *dest, gint32 length)
9720 {
9721         int element_size;
9722         void *dest_addr;
9723
9724         MONO_ARCH_SAVE_REGS;
9725
9726         MONO_CHECK_ARG_NULL (src);
9727         MONO_CHECK_ARG_NULL (dest);
9728
9729         if (dest->obj.vtable->klass->rank != 1)
9730                 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
9731         if (start_index < 0)
9732                 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
9733         if (length < 0)
9734                 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
9735         if (start_index + length > mono_array_length (dest))
9736                 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
9737
9738         element_size = mono_array_element_size (dest->obj.vtable->klass);
9739           
9740         /* no references should be involved */
9741         dest_addr = mono_array_addr_with_size (dest, element_size, start_index);
9742
9743         memcpy (dest_addr, src, length * element_size);
9744 }
9745
9746 #if NO_UNALIGNED_ACCESS
9747 #define RETURN_UNALIGNED(type, addr) \
9748         { \
9749                 type val; \
9750                 memcpy(&val, p + offset, sizeof(val)); \
9751                 return val; \
9752         }
9753 #define WRITE_UNALIGNED(type, addr, val) \
9754         memcpy(addr, &val, sizeof(type))
9755 #else
9756 #define RETURN_UNALIGNED(type, addr) \
9757         return *(type*)(p + offset);
9758 #define WRITE_UNALIGNED(type, addr, val) \
9759         (*(type *)(addr) = (val))
9760 #endif
9761
9762 gpointer
9763 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
9764 {
9765         char *p = ptr;
9766
9767         MONO_ARCH_SAVE_REGS;
9768
9769         RETURN_UNALIGNED(gpointer, p + offset);
9770 }
9771
9772 unsigned char
9773 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
9774 {
9775         char *p = ptr;
9776
9777         MONO_ARCH_SAVE_REGS;
9778
9779         return *(unsigned char*)(p + offset);
9780 }
9781
9782 gint16
9783 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
9784 {
9785         char *p = ptr;
9786
9787         MONO_ARCH_SAVE_REGS;
9788
9789         RETURN_UNALIGNED(gint16, p + offset);
9790 }
9791
9792 gint32
9793 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
9794 {
9795         char *p = ptr;
9796
9797         MONO_ARCH_SAVE_REGS;
9798
9799         RETURN_UNALIGNED(gint32, p + offset);
9800 }
9801
9802 gint64
9803 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
9804 {
9805         char *p = ptr;
9806
9807         MONO_ARCH_SAVE_REGS;
9808
9809         RETURN_UNALIGNED(gint64, p + offset);
9810 }
9811
9812 void
9813 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
9814 {
9815         char *p = ptr;
9816
9817         MONO_ARCH_SAVE_REGS;
9818
9819         *(unsigned char*)(p + offset) = val;
9820 }
9821
9822 void
9823 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
9824 {
9825         char *p = ptr;
9826
9827         MONO_ARCH_SAVE_REGS;
9828
9829         WRITE_UNALIGNED(gpointer, p + offset, val);
9830 }
9831
9832 void
9833 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
9834 {
9835         char *p = ptr;
9836
9837         MONO_ARCH_SAVE_REGS;
9838
9839         WRITE_UNALIGNED(gint16, p + offset, val);
9840 }
9841
9842 void
9843 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
9844 {
9845         char *p = ptr;
9846
9847         MONO_ARCH_SAVE_REGS;
9848
9849         WRITE_UNALIGNED(gint32, p + offset, val);
9850 }
9851
9852 void
9853 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
9854 {
9855         char *p = ptr;
9856
9857         MONO_ARCH_SAVE_REGS;
9858
9859         WRITE_UNALIGNED(gint64, p + offset, val);
9860 }
9861
9862 MonoString *
9863 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
9864 {
9865         MONO_ARCH_SAVE_REGS;
9866
9867         if (ptr == NULL)
9868                 return NULL;
9869         else
9870                 return mono_string_new (mono_domain_get (), ptr);
9871 }
9872
9873 MonoString *
9874 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
9875 {
9876         MONO_ARCH_SAVE_REGS;
9877
9878         if (ptr == NULL) {
9879                 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
9880                 g_assert_not_reached ();
9881                 return NULL;
9882         } else {
9883                 return mono_string_new_len (mono_domain_get (), ptr, len);
9884         }
9885 }
9886
9887 MonoString *
9888 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
9889 {
9890         MonoDomain *domain = mono_domain_get (); 
9891         int len = 0;
9892         guint16 *t = ptr;
9893
9894         MONO_ARCH_SAVE_REGS;
9895
9896         if (ptr == NULL)
9897                 return NULL;
9898
9899         while (*t++)
9900                 len++;
9901
9902         return mono_string_new_utf16 (domain, ptr, len);
9903 }
9904
9905 MonoString *
9906 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
9907 {
9908         MonoDomain *domain = mono_domain_get (); 
9909
9910         MONO_ARCH_SAVE_REGS;
9911
9912         if (ptr == NULL) {
9913                 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
9914                 g_assert_not_reached ();
9915                 return NULL;
9916         } else {
9917                 return mono_string_new_utf16 (domain, ptr, len);
9918         }
9919 }
9920
9921 MonoString *
9922 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
9923 {
9924         MONO_ARCH_SAVE_REGS;
9925
9926         return mono_string_from_bstr(ptr);
9927 }
9928
9929 gpointer
9930 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
9931 {
9932         MONO_ARCH_SAVE_REGS;
9933
9934         return mono_string_to_bstr(ptr);
9935 }
9936
9937 typedef struct
9938 {
9939         int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
9940         int (STDCALL *AddRef)(gpointer pUnk);
9941         int (STDCALL *Release)(gpointer pUnk);
9942 } MonoIUnknown;
9943
9944 void
9945 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
9946 {
9947         MONO_ARCH_SAVE_REGS;
9948
9949         mono_free_bstr (ptr);
9950 }
9951
9952 int
9953 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
9954 {
9955         g_assert (pUnk);
9956         return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
9957 }
9958
9959 int
9960 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
9961 {
9962         g_assert (pUnk);
9963         return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
9964 }
9965
9966 int
9967 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
9968 {
9969         g_assert (pUnk);
9970         return (*(MonoIUnknown**)pUnk)->Release(pUnk);
9971 }
9972
9973 static void*
9974 cominterop_get_idispatch_for_object (MonoObject* object)
9975 {
9976         if (!object)
9977                 return NULL;
9978
9979         if (cominterop_object_is_rcw (object)) {
9980                 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object, 
9981                         mono_defaults.idispatch_class, TRUE);
9982         }
9983         else {
9984                 return cominterop_get_ccw (object, mono_defaults.idispatch_class);
9985         }
9986 }
9987
9988 void*
9989 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
9990 {
9991         if (!object)
9992                 return NULL;
9993
9994         if (cominterop_object_is_rcw (object)) {
9995                 MonoClass *klass = NULL;
9996                 MonoRealProxy* real_proxy = NULL;
9997                 if (!object)
9998                         return NULL;
9999                 klass = mono_object_class (object);
10000                 if (klass != mono_defaults.transparent_proxy_class) {
10001                         g_assert_not_reached ();
10002                         return NULL;
10003                 }
10004
10005                 real_proxy = ((MonoTransparentProxy*)object)->rp;
10006                 if (!real_proxy) {
10007                         g_assert_not_reached ();
10008                         return NULL;
10009                 }
10010
10011                 klass = mono_object_class (real_proxy);
10012                 if (klass != mono_defaults.com_interop_proxy_class) {
10013                         g_assert_not_reached ();
10014                         return NULL;
10015                 }
10016
10017                 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
10018                         g_assert_not_reached ();
10019                         return NULL;
10020                 }
10021
10022                 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
10023         }
10024         else {
10025                 return cominterop_get_ccw (object, mono_defaults.iunknown_class);
10026         }
10027 }
10028
10029 MonoObject*
10030 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
10031 {
10032         MonoObject* object = NULL;
10033
10034         if (!pUnk)
10035                 return NULL;
10036
10037         /* see if it is a CCW */
10038         object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
10039
10040         return object;
10041 }
10042
10043 void*
10044 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
10045 {
10046         return cominterop_get_idispatch_for_object (object);
10047 }
10048
10049 void*
10050 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
10051 {
10052         MonoClass* klass = NULL;
10053         void* itf = NULL;
10054         g_assert (type);
10055         g_assert (type->type);
10056         klass = mono_type_get_class (type->type);
10057         g_assert (klass);
10058         itf = cominterop_get_ccw (object, klass);
10059         g_assert (itf);
10060         return itf;
10061 }
10062
10063
10064 MonoBoolean
10065 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
10066 {
10067         return (MonoBoolean)cominterop_object_is_rcw (object);
10068 }
10069
10070 gint32
10071 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
10072 {
10073         MonoComInteropProxy* proxy = NULL;
10074         gint32 ref_count = 0;
10075
10076         g_assert (object);
10077         g_assert (cominterop_object_is_rcw (object));
10078
10079         proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
10080         g_assert (proxy);
10081
10082         ref_count = InterlockedDecrement (&proxy->ref_count);
10083         g_assert (ref_count >= 0);
10084
10085         if (ref_count == 0)
10086                 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
10087
10088         return ref_count;
10089 }
10090
10091 guint32
10092 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
10093 {
10094         MONO_ARCH_SAVE_REGS;
10095
10096         return cominterop_get_com_slot_for_method (m->method);
10097 }
10098
10099 guint32 
10100 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10101 {
10102         MONO_ARCH_SAVE_REGS;
10103
10104         return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id)));
10105 }
10106
10107 guint32 
10108 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype)
10109 {
10110         MonoClass *klass;
10111         MonoType *type;
10112         guint32 layout;
10113
10114         MONO_ARCH_SAVE_REGS;
10115
10116         MONO_CHECK_ARG_NULL (rtype);
10117
10118         type = rtype->type;
10119         klass = mono_class_from_mono_type (type);
10120         layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
10121
10122         if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
10123                 gchar *msg;
10124                 MonoException *exc;
10125
10126                 msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name);
10127                 exc = mono_get_exception_argument ("t", msg);
10128                 g_free (msg);
10129                 mono_raise_exception (exc);
10130         }
10131
10132
10133         return mono_class_native_size (klass, NULL);
10134 }
10135
10136 void
10137 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
10138 {
10139         MonoMethod *method;
10140         gpointer pa [3];
10141
10142         MONO_ARCH_SAVE_REGS;
10143
10144         MONO_CHECK_ARG_NULL (obj);
10145         MONO_CHECK_ARG_NULL (dst);
10146
10147         method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
10148
10149         pa [0] = obj;
10150         pa [1] = &dst;
10151         pa [2] = &delete_old;
10152
10153         mono_runtime_invoke (method, NULL, pa, NULL);
10154 }
10155
10156 static void
10157 ptr_to_structure (gpointer src, MonoObject *dst)
10158 {
10159         MonoMethod *method;
10160         gpointer pa [2];
10161
10162         method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
10163
10164         pa [0] = &src;
10165         pa [1] = dst;
10166
10167         mono_runtime_invoke (method, NULL, pa, NULL);
10168 }
10169
10170 void
10171 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
10172 {
10173         MonoType *t;
10174
10175         MONO_ARCH_SAVE_REGS;
10176
10177         MONO_CHECK_ARG_NULL (src);
10178         MONO_CHECK_ARG_NULL (dst);
10179         
10180         t = mono_type_get_underlying_type (mono_class_get_type (dst->vtable->klass));
10181
10182         if (t->type == MONO_TYPE_VALUETYPE) {
10183                 MonoException *exc;
10184                 gchar *tmp;
10185
10186                 tmp = g_strdup_printf ("Destination is a boxed value type.");
10187                 exc = mono_get_exception_argument ("dst", tmp);
10188                 g_free (tmp);  
10189
10190                 mono_raise_exception (exc);
10191                 return;
10192         }
10193
10194         ptr_to_structure (src, dst);
10195 }
10196
10197 MonoObject *
10198 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
10199 {
10200         MonoDomain *domain = mono_domain_get (); 
10201         MonoObject *res;
10202
10203         MONO_ARCH_SAVE_REGS;
10204
10205         MONO_CHECK_ARG_NULL (src);
10206         MONO_CHECK_ARG_NULL (type);
10207
10208         res = mono_object_new (domain, mono_class_from_mono_type (type->type));
10209
10210         ptr_to_structure (src, res);
10211
10212         return res;
10213 }
10214
10215 int
10216 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
10217 {
10218         MonoMarshalType *info;
10219         MonoClass *klass;
10220         char *fname;
10221         int match_index = -1;
10222         
10223         MONO_ARCH_SAVE_REGS;
10224
10225         MONO_CHECK_ARG_NULL (type);
10226         MONO_CHECK_ARG_NULL (field_name);
10227
10228         fname = mono_string_to_utf8 (field_name);
10229         klass = mono_class_from_mono_type (type->type);
10230
10231         while (klass && match_index == -1) {
10232                 MonoClassField* field;
10233                 int i = 0;
10234                 gpointer iter = NULL;
10235                 while ((field = mono_class_get_fields (klass, &iter))) {
10236                         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
10237                                 continue;
10238                         if (!strcmp (fname, field->name)) {
10239                                 match_index = i;
10240                                 break;
10241                         }
10242                         i ++;
10243                 }
10244
10245                 if (match_index == -1)
10246                         klass = klass->parent;
10247         }
10248
10249         g_free (fname);
10250
10251         if(match_index == -1) {
10252                 MonoException* exc;
10253                 gchar *tmp;
10254
10255                 /* Get back original class instance */
10256                 klass = mono_class_from_mono_type (type->type);
10257
10258                 tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
10259                 exc = mono_get_exception_argument ("fieldName", tmp);
10260                 g_free (tmp);
10261  
10262                 mono_raise_exception ((MonoException*)exc);
10263         }
10264
10265         info = mono_marshal_load_type_info (klass);     
10266         return info->fields [match_index].offset;
10267 }
10268
10269 gpointer
10270 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
10271 {
10272         MONO_ARCH_SAVE_REGS;
10273
10274         return mono_string_to_utf8 (string);
10275 }
10276
10277 gpointer
10278 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
10279 {
10280         MONO_ARCH_SAVE_REGS;
10281
10282         if (string == NULL)
10283                 return NULL;
10284         else {
10285                 gunichar2 *res = g_malloc ((mono_string_length (string) + 1) * 2);
10286                 memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
10287                 res [mono_string_length (string)] = 0;
10288                 return res;
10289         }
10290 }
10291
10292 static void
10293 mono_struct_delete_old (MonoClass *klass, char *ptr)
10294 {
10295         MonoMarshalType *info;
10296         int i;
10297
10298         info = mono_marshal_load_type_info (klass);
10299
10300         for (i = 0; i < info->num_fields; i++) {
10301                 MonoMarshalNative ntype;
10302                 MonoMarshalConv conv;
10303                 MonoType *ftype = info->fields [i].field->type;
10304                 char *cpos;
10305
10306                 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
10307                         continue;
10308
10309                 ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, 
10310                                                 klass->unicode, &conv);
10311                         
10312                 cpos = ptr + info->fields [i].offset;
10313
10314                 switch (conv) {
10315                 case MONO_MARSHAL_CONV_NONE:
10316                         if (MONO_TYPE_ISSTRUCT (ftype)) {
10317                                 mono_struct_delete_old (ftype->data.klass, cpos);
10318                                 continue;
10319                         }
10320                         break;
10321                 case MONO_MARSHAL_CONV_STR_LPWSTR:
10322                         /* We assume this field points inside a MonoString */
10323                         break;
10324                 case MONO_MARSHAL_CONV_STR_LPTSTR:
10325 #ifdef PLATFORM_WIN32
10326                         /* We assume this field points inside a MonoString 
10327                          * on Win32 */
10328                         break;
10329 #endif
10330                 case MONO_MARSHAL_CONV_STR_LPSTR:
10331                 case MONO_MARSHAL_CONV_STR_BSTR:
10332                 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
10333                 case MONO_MARSHAL_CONV_STR_TBSTR:
10334                         mono_marshal_free (*(gpointer *)cpos);
10335                         break;
10336
10337                 default:
10338                         continue;
10339                 }
10340         }
10341 }
10342
10343 void
10344 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
10345 {
10346         MonoClass *klass;
10347
10348         MONO_ARCH_SAVE_REGS;
10349
10350         MONO_CHECK_ARG_NULL (src);
10351         MONO_CHECK_ARG_NULL (type);
10352
10353         klass = mono_class_from_mono_type (type->type);
10354
10355         mono_struct_delete_old (klass, (char *)src);
10356 }
10357
10358 void*
10359 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
10360 {
10361         gpointer res;
10362
10363         MONO_ARCH_SAVE_REGS;
10364
10365         if ((gulong)size == 0)
10366                 /* This returns a valid pointer for size 0 on MS.NET */
10367                 size = 4;
10368
10369 #ifdef PLATFORM_WIN32
10370         res = GlobalAlloc (GMEM_FIXED, (gulong)size);
10371 #else
10372         res = g_try_malloc ((gulong)size);
10373 #endif
10374         if (!res)
10375                 mono_gc_out_of_memory ((gulong)size);
10376
10377         return res;
10378 }
10379
10380 gpointer
10381 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, int size)
10382 {
10383         gpointer res;
10384
10385         if (ptr == NULL) {
10386                 mono_gc_out_of_memory ((gulong)size);
10387                 return NULL;
10388         }
10389
10390 #ifdef PLATFORM_WIN32
10391         res = GlobalReAlloc (ptr, (gulong)size, GMEM_MOVEABLE);
10392 #else
10393         res = g_try_realloc (ptr, (gulong)size);
10394 #endif
10395         if (!res)
10396                 mono_gc_out_of_memory ((gulong)size);
10397
10398         return res;
10399 }
10400
10401 void
10402 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
10403 {
10404         MONO_ARCH_SAVE_REGS;
10405
10406 #ifdef PLATFORM_WIN32
10407         GlobalFree (ptr);
10408 #else
10409         g_free (ptr);
10410 #endif
10411 }
10412
10413 void*
10414 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
10415 {
10416         MONO_ARCH_SAVE_REGS;
10417
10418 #ifdef PLATFORM_WIN32
10419         return CoTaskMemAlloc (size);
10420 #else
10421         return g_try_malloc ((gulong)size);
10422 #endif
10423 }
10424
10425 void
10426 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
10427 {
10428         MONO_ARCH_SAVE_REGS;
10429
10430 #ifdef PLATFORM_WIN32
10431         CoTaskMemFree (ptr);
10432 #else
10433         g_free (ptr);
10434 #endif
10435 }
10436
10437 gpointer
10438 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
10439 {
10440         MONO_ARCH_SAVE_REGS;
10441
10442 #ifdef PLATFORM_WIN32
10443         return CoTaskMemRealloc (ptr, size);
10444 #else
10445         return g_try_realloc (ptr, (gulong)size);
10446 #endif
10447 }
10448
10449 void*
10450 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
10451 {
10452         return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
10453 }
10454
10455 MonoDelegate*
10456 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type)
10457 {
10458         return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn);
10459 }
10460
10461 /* Only used for COM RCWs */
10462 MonoObject *
10463 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
10464 {
10465         MonoClass *klass;
10466         MonoDomain *domain;
10467         MonoObject *obj;
10468         
10469         MONO_ARCH_SAVE_REGS;
10470
10471         domain = mono_object_domain (type);
10472         klass = mono_class_from_mono_type (type->type);
10473
10474         /* call mono_object_new_alloc_specific instead of mono_object_new
10475          * because we want to actually create object. mono_object_new checks
10476          * to see if type is import and creates transparent proxy. this method
10477          * is called by the corresponding real proxy to create the real RCW.
10478          * Constructor does not need to be called. Will be called later.
10479         */
10480         obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
10481         return obj;
10482 }
10483
10484 static gboolean    
10485 cominterop_finalizer (gpointer key, gpointer value, gpointer user_data)
10486 {
10487         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
10488         return TRUE;
10489 }
10490
10491 void
10492 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
10493 {
10494         g_assert(obj);
10495         if (obj->itf_hash) {
10496                 guint32 gchandle = 0;
10497                 mono_cominterop_lock ();
10498                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
10499                 if (gchandle) {
10500                         mono_gchandle_free (gchandle);
10501                         g_hash_table_remove (rcw_hash, obj->iunknown);
10502                 }
10503
10504                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL);
10505                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
10506                 obj->itf_hash = obj->iunknown = NULL;
10507                 mono_cominterop_unlock ();
10508         }
10509 }
10510
10511 gpointer
10512 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
10513 {
10514         return cominterop_get_interface (obj, mono_type_get_class (type->type), (gboolean)throw_exception);
10515 }
10516
10517 void
10518 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
10519 {
10520         guint32 gchandle = 0;
10521         if (!rcw_hash) {
10522                 mono_cominterop_lock ();
10523                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
10524                 mono_cominterop_unlock ();
10525         }
10526
10527         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
10528
10529         mono_cominterop_lock ();
10530         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
10531         mono_cominterop_unlock ();
10532 }
10533
10534 MonoComInteropProxy*
10535 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
10536 {
10537         MonoComInteropProxy* proxy = NULL;
10538         guint32 gchandle = 0;
10539
10540         mono_cominterop_lock ();
10541         if (rcw_hash)
10542                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
10543         mono_cominterop_unlock ();
10544         if (gchandle) {
10545                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
10546                 /* proxy is null means we need to free up old RCW */
10547                 if (!proxy) {
10548                         mono_gchandle_free (gchandle);
10549                         g_hash_table_remove (rcw_hash, pUnk);
10550                 }
10551         }
10552         return proxy;
10553 }
10554
10555 /**
10556  * mono_marshal_is_loading_type_info:
10557  *
10558  *  Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
10559  * thread.
10560  */
10561 static gboolean
10562 mono_marshal_is_loading_type_info (MonoClass *klass)
10563 {
10564         GSList *loads_list = TlsGetValue (load_type_info_tls_id);
10565
10566         return g_slist_find (loads_list, klass) != NULL;
10567 }
10568
10569 /**
10570  * mono_marshal_load_type_info:
10571  *
10572  *  Initialize klass->marshal_info using information from metadata. This function can
10573  * recursively call itself, and the caller is responsible to avoid that by calling 
10574  * mono_marshal_is_loading_type_info () beforehand.
10575  *
10576  * LOCKING: Acquires the loader lock.
10577  */
10578 MonoMarshalType *
10579 mono_marshal_load_type_info (MonoClass* klass)
10580 {
10581         int j, count = 0;
10582         guint32 native_size = 0, min_align = 1;
10583         MonoMarshalType *info;
10584         MonoClassField* field;
10585         gpointer iter;
10586         guint32 layout;
10587         GSList *loads_list;
10588
10589         g_assert (klass != NULL);
10590
10591         if (klass->marshal_info)
10592                 return klass->marshal_info;
10593
10594         if (!klass->inited)
10595                 mono_class_init (klass);
10596
10597         mono_loader_lock ();
10598
10599         if (klass->marshal_info) {
10600                 mono_loader_unlock ();
10601                 return klass->marshal_info;
10602         }
10603
10604         /*
10605          * This function can recursively call itself, so we keep the list of classes which are
10606          * under initialization in a TLS list.
10607          */
10608         g_assert (!mono_marshal_is_loading_type_info (klass));
10609         loads_list = TlsGetValue (load_type_info_tls_id);
10610         loads_list = g_slist_prepend (loads_list, klass);
10611         TlsSetValue (load_type_info_tls_id, loads_list);
10612         
10613         iter = NULL;
10614         while ((field = mono_class_get_fields (klass, &iter))) {
10615                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
10616                         continue;
10617                 if (mono_field_is_deleted (field))
10618                         continue;
10619                 count++;
10620         }
10621
10622         layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
10623
10624         /* The mempool is protected by the loader lock */
10625         info = mono_mempool_alloc0 (klass->image->mempool, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
10626         info->num_fields = count;
10627         
10628         /* Try to find a size for this type in metadata */
10629         mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
10630
10631         if (klass->parent) {
10632                 int parent_size = mono_class_native_size (klass->parent, NULL);
10633
10634                 /* Add parent size to real size */
10635                 native_size += parent_size;
10636                 info->native_size = parent_size;
10637         }
10638
10639         iter = NULL;
10640         j = 0;
10641         while ((field = mono_class_get_fields (klass, &iter))) {
10642                 int size;
10643                 guint32 align;
10644                 
10645                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
10646                         continue;
10647
10648                 if (mono_field_is_deleted (field))
10649                         continue;
10650                 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
10651                         mono_metadata_field_info (klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1, 
10652                                                   NULL, NULL, &info->fields [j].mspec);
10653
10654                 info->fields [j].field = field;
10655
10656                 if ((mono_class_num_fields (klass) == 1) && (klass->instance_size == sizeof (MonoObject)) &&
10657                         (strcmp (field->name, "$PRIVATE$") == 0)) {
10658                         /* This field is a hack inserted by MCS to empty structures */
10659                         continue;
10660                 }
10661
10662                 switch (layout) {
10663                 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
10664                 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
10665                         size = mono_marshal_type_size (field->type, info->fields [j].mspec, 
10666                                                        &align, TRUE, klass->unicode);
10667                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
10668                         min_align = MAX (align, min_align);
10669                         info->fields [j].offset = info->native_size;
10670                         info->fields [j].offset += align - 1;
10671                         info->fields [j].offset &= ~(align - 1);
10672                         info->native_size = info->fields [j].offset + size;
10673                         break;
10674                 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
10675                         size = mono_marshal_type_size (field->type, info->fields [j].mspec, 
10676                                                        &align, TRUE, klass->unicode);
10677                         align = klass->packing_size ? MIN (klass->packing_size, align): align;
10678                         min_align = MAX (align, min_align);
10679                         info->fields [j].offset = field->offset - sizeof (MonoObject);
10680                         info->native_size = MAX (info->native_size, info->fields [j].offset + size);
10681                         break;
10682                 }       
10683                 j++;
10684         }
10685
10686         if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
10687                 info->native_size = MAX (native_size, info->native_size);
10688         }
10689
10690         if (info->native_size & (min_align - 1)) {
10691                 info->native_size += min_align - 1;
10692                 info->native_size &= ~(min_align - 1);
10693         }
10694
10695         /* Update the class's blittable info, if the layouts don't match */
10696         if (info->native_size != mono_class_value_size (klass, NULL))
10697                 klass->blittable = FALSE;
10698
10699         /* If this is an array type, ensure that we have element info */
10700         if (klass->element_class && !mono_marshal_is_loading_type_info (klass->element_class)) {
10701                 mono_marshal_load_type_info (klass->element_class);
10702         }
10703
10704         loads_list = TlsGetValue (load_type_info_tls_id);
10705         loads_list = g_slist_remove (loads_list, klass);
10706         TlsSetValue (load_type_info_tls_id, loads_list);
10707
10708         klass->marshal_info = info;
10709
10710         mono_loader_unlock ();
10711
10712         return klass->marshal_info;
10713 }
10714
10715 /**
10716  * mono_class_native_size:
10717  * @klass: a class 
10718  * 
10719  * Returns: the native size of an object instance (when marshaled 
10720  * to unmanaged code) 
10721  */
10722 gint32
10723 mono_class_native_size (MonoClass *klass, guint32 *align)
10724 {       
10725         if (!klass->marshal_info) {
10726                 if (mono_marshal_is_loading_type_info (klass)) {
10727                         if (align)
10728                                 *align = 0;
10729                         return 0;
10730                 } else {
10731                         mono_marshal_load_type_info (klass);
10732                 }
10733         }
10734
10735         if (align)
10736                 *align = klass->min_align;
10737
10738         return klass->marshal_info->native_size;
10739 }
10740
10741 /*
10742  * mono_type_native_stack_size:
10743  * @t: the type to return the size it uses on the stack
10744  *
10745  * Returns: the number of bytes required to hold an instance of this
10746  * type on the native stack
10747  */
10748 int
10749 mono_type_native_stack_size (MonoType *t, guint32 *align)
10750 {
10751         guint32 tmp;
10752
10753         g_assert (t != NULL);
10754
10755         if (!align)
10756                 align = &tmp;
10757
10758         if (t->byref) {
10759                 *align = 4;
10760                 return 4;
10761         }
10762
10763         switch (t->type){
10764         case MONO_TYPE_BOOLEAN:
10765         case MONO_TYPE_CHAR:
10766         case MONO_TYPE_I1:
10767         case MONO_TYPE_U1:
10768         case MONO_TYPE_I2:
10769         case MONO_TYPE_U2:
10770         case MONO_TYPE_I4:
10771         case MONO_TYPE_U4:
10772         case MONO_TYPE_I:
10773         case MONO_TYPE_U:
10774         case MONO_TYPE_STRING:
10775         case MONO_TYPE_OBJECT:
10776         case MONO_TYPE_CLASS:
10777         case MONO_TYPE_SZARRAY:
10778         case MONO_TYPE_PTR:
10779         case MONO_TYPE_FNPTR:
10780         case MONO_TYPE_ARRAY:
10781         case MONO_TYPE_TYPEDBYREF:
10782                 *align = 4;
10783                 return 4;
10784         case MONO_TYPE_R4:
10785                 *align = 4;
10786                 return 4;
10787         case MONO_TYPE_I8:
10788         case MONO_TYPE_U8:
10789         case MONO_TYPE_R8:
10790                 *align = 4;
10791                 return 8;
10792         case MONO_TYPE_VALUETYPE: {
10793                 guint32 size;
10794
10795                 if (t->data.klass->enumtype)
10796                         return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
10797                 else {
10798                         size = mono_class_native_size (t->data.klass, align);
10799                         *align = *align + 3;
10800                         *align &= ~3;
10801                         
10802                         size +=  3;
10803                         size &= ~3;
10804
10805                         return size;
10806                 }
10807         }
10808         default:
10809                 g_error ("type 0x%02x unknown", t->type);
10810         }
10811         return 0;
10812 }
10813
10814 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
10815    the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
10816    but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
10817 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
10818
10819 gint32
10820 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
10821                         gboolean as_field, gboolean unicode)
10822 {
10823         MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
10824         MonoClass *klass;
10825
10826         switch (native_type) {
10827         case MONO_NATIVE_BOOLEAN:
10828                 *align = 4;
10829                 return 4;
10830         case MONO_NATIVE_I1:
10831         case MONO_NATIVE_U1:
10832                 *align = 1;
10833                 return 1;
10834         case MONO_NATIVE_I2:
10835         case MONO_NATIVE_U2:
10836         case MONO_NATIVE_VARIANTBOOL:
10837                 *align = 2;
10838                 return 2;
10839         case MONO_NATIVE_I4:
10840         case MONO_NATIVE_U4:
10841         case MONO_NATIVE_ERROR:
10842                 *align = 4;
10843                 return 4;
10844         case MONO_NATIVE_I8:
10845         case MONO_NATIVE_U8:
10846                 *align = ALIGNMENT(guint64);
10847                 return 8;
10848         case MONO_NATIVE_R4:
10849                 *align = 4;
10850                 return 4;
10851         case MONO_NATIVE_R8:
10852                 *align = ALIGNMENT(double);
10853                 return 8;
10854         case MONO_NATIVE_INT:
10855         case MONO_NATIVE_UINT:
10856         case MONO_NATIVE_LPSTR:
10857         case MONO_NATIVE_LPWSTR:
10858         case MONO_NATIVE_LPTSTR:
10859         case MONO_NATIVE_BSTR:
10860         case MONO_NATIVE_ANSIBSTR:
10861         case MONO_NATIVE_TBSTR:
10862         case MONO_NATIVE_LPARRAY:
10863         case MONO_NATIVE_SAFEARRAY:
10864         case MONO_NATIVE_IUNKNOWN:
10865         case MONO_NATIVE_IDISPATCH:
10866         case MONO_NATIVE_INTERFACE:
10867         case MONO_NATIVE_ASANY:
10868         case MONO_NATIVE_FUNC:
10869         case MONO_NATIVE_LPSTRUCT:
10870                 *align = ALIGNMENT(gpointer);
10871                 return sizeof (gpointer);
10872         case MONO_NATIVE_STRUCT: 
10873                 klass = mono_class_from_mono_type (type);
10874                 if (klass == mono_defaults.object_class &&
10875                         (mspec && mspec->native == MONO_NATIVE_STRUCT)) {
10876                 *align = 16;
10877                 return 16;
10878                 }
10879                 return mono_class_native_size (klass, align);
10880         case MONO_NATIVE_BYVALTSTR: {
10881                 int esize = unicode ? 2: 1;
10882                 g_assert (mspec);
10883                 *align = esize;
10884                 return mspec->data.array_data.num_elem * esize;
10885         }
10886         case MONO_NATIVE_BYVALARRAY: {
10887                 // FIXME: Have to consider ArraySubType
10888                 int esize;
10889                 klass = mono_class_from_mono_type (type);
10890                 if (klass->element_class == mono_defaults.char_class) {
10891                         esize = unicode ? 2 : 1;
10892                         *align = esize;
10893                 } else {
10894                         esize = mono_class_native_size (klass->element_class, align);
10895                 }
10896                 g_assert (mspec);
10897                 return mspec->data.array_data.num_elem * esize;
10898         }
10899         case MONO_NATIVE_CUSTOM:
10900                 *align = sizeof (gpointer);
10901                 return sizeof (gpointer);
10902                 break;
10903         case MONO_NATIVE_CURRENCY:
10904         case MONO_NATIVE_VBBYREFSTR:
10905         default:
10906                 g_error ("native type %02x not implemented", native_type); 
10907                 break;
10908         }
10909         g_assert_not_reached ();
10910         return 0;
10911 }
10912
10913 gpointer
10914 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
10915 {
10916         MonoType *t;
10917         MonoClass *klass;
10918
10919         if (o == NULL)
10920                 return NULL;
10921
10922         t = &o->vtable->klass->byval_arg;
10923         switch (t->type) {
10924         case MONO_TYPE_I4:
10925         case MONO_TYPE_U4:
10926         case MONO_TYPE_PTR:
10927         case MONO_TYPE_I1:
10928         case MONO_TYPE_U1:
10929         case MONO_TYPE_BOOLEAN:
10930         case MONO_TYPE_I2:
10931         case MONO_TYPE_U2:
10932         case MONO_TYPE_CHAR:
10933         case MONO_TYPE_I8:
10934         case MONO_TYPE_U8:
10935         case MONO_TYPE_R4:
10936         case MONO_TYPE_R8:
10937                 return mono_object_unbox (o);
10938                 break;
10939         case MONO_TYPE_STRING:
10940                 switch (string_encoding) {
10941                 case MONO_NATIVE_LPWSTR:
10942                         return mono_string_to_utf16 ((MonoString*)o);
10943                         break;
10944                 case MONO_NATIVE_LPSTR:
10945                         return mono_string_to_lpstr ((MonoString*)o);
10946                         break;
10947                 default:
10948                         g_warning ("marshaling conversion %d not implemented", string_encoding);
10949                         g_assert_not_reached ();
10950                 }
10951                 break;
10952         case MONO_TYPE_CLASS:
10953         case MONO_TYPE_VALUETYPE: {
10954                 MonoMethod *method;
10955                 gpointer pa [3];
10956                 gpointer res;
10957                 MonoBoolean delete_old = FALSE;
10958
10959                 klass = t->data.klass;
10960
10961                 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
10962                         break;
10963
10964                 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
10965                         klass->blittable || klass->enumtype))
10966                         return mono_object_unbox (o);
10967
10968                 res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
10969
10970                 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
10971                         method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
10972
10973                         pa [0] = o;
10974                         pa [1] = &res;
10975                         pa [2] = &delete_old;
10976
10977                         mono_runtime_invoke (method, NULL, pa, NULL);
10978                 }
10979
10980                 return res;
10981         }
10982         }
10983
10984         mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
10985
10986         return NULL;
10987 }
10988
10989 void
10990 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
10991 {
10992         MonoType *t;
10993         MonoClass *klass;
10994
10995         if (o == NULL)
10996                 return;
10997
10998         t = &o->vtable->klass->byval_arg;
10999         switch (t->type) {
11000         case MONO_TYPE_STRING:
11001                 switch (string_encoding) {
11002                 case MONO_NATIVE_LPWSTR:
11003                 case MONO_NATIVE_LPSTR:
11004                         mono_marshal_free (ptr);
11005                         break;
11006                 default:
11007                         g_warning ("marshaling conversion %d not implemented", string_encoding);
11008                         g_assert_not_reached ();
11009                 }
11010                 break;
11011         case MONO_TYPE_CLASS:
11012         case MONO_TYPE_VALUETYPE: {
11013                 klass = t->data.klass;
11014
11015                 if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
11016                                                                  klass->blittable || klass->enumtype))
11017                         break;
11018
11019                 if (param_attrs & PARAM_ATTRIBUTE_OUT) {
11020                         MonoMethod *method = mono_marshal_get_ptr_to_struct (o->vtable->klass);
11021                         gpointer pa [2];
11022
11023                         pa [0] = &ptr;
11024                         pa [1] = o;
11025
11026                         mono_runtime_invoke (method, NULL, pa, NULL);
11027                 }
11028
11029                 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
11030                         mono_struct_delete_old (klass, ptr);
11031                 }
11032
11033                 mono_marshal_free (ptr);
11034                 break;
11035         }
11036         default:
11037                 break;
11038         }
11039 }
11040
11041 MonoMethod *
11042 mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar *name, MonoMethod *method)
11043 {
11044         MonoMethodSignature *sig, *csig;
11045         MonoMethodBuilder *mb;
11046         MonoMethod *res;
11047         int i;
11048
11049         mb = mono_mb_new_no_dup_name (class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
11050         mb->method->slot = -1;
11051
11052         mb->method->flags = METHOD_ATTRIBUTE_PRIVATE | METHOD_ATTRIBUTE_VIRTUAL |
11053                 METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
11054
11055         sig = mono_method_signature (method);
11056         csig = signature_dup (method->klass->image, sig);
11057         csig->generic_param_count = 0;
11058
11059         mono_mb_emit_ldarg (mb, 0);
11060         for (i = 0; i < csig->param_count; i++)
11061                 mono_mb_emit_ldarg (mb, i + 1);
11062         mono_mb_emit_managed_call (mb, method, NULL);
11063         mono_mb_emit_byte (mb, CEE_RET);
11064
11065         res = mono_mb_create_method (mb, csig, csig->param_count + 16);
11066
11067         /* We can corlib internal methods */
11068         res->skip_visibility = TRUE;
11069
11070         mono_mb_free (mb);
11071
11072         return res;
11073 }
11074
11075 /*
11076  * The mono_win32_compat_* functions are implementations of inline
11077  * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11078  * although not exported by kernel32.
11079  *
11080  * We map the appropiate kernel32 entries to these functions using
11081  * dllmaps declared in the global etc/mono/config.
11082  */
11083
11084 void
11085 mono_win32_compat_CopyMemory (gpointer dest, gconstpointer source, gsize length)
11086 {
11087         if (!dest || !source)
11088                 return;
11089
11090         memcpy (dest, source, length);
11091 }
11092
11093 void
11094 mono_win32_compat_FillMemory (gpointer dest, gsize length, guchar fill)
11095 {
11096         memset (dest, fill, length);
11097 }
11098
11099 void
11100 mono_win32_compat_MoveMemory (gpointer dest, gconstpointer source, gsize length)
11101 {
11102         if (!dest || !source)
11103                 return;
11104
11105         memmove (dest, source, length);
11106 }
11107
11108 void
11109 mono_win32_compat_ZeroMemory (gpointer dest, gsize length)
11110 {
11111         memset (dest, 0, length);
11112 }
11113
11114 /* Put COM Interop related stuff here */
11115
11116 /**
11117  * cominterop_get_ccw_object:
11118  * @ccw_entry: a pointer to the CCWEntry
11119  * @verify: verify ccw_entry is in fact a ccw
11120  *
11121  * Returns: the corresponding object for the CCW
11122  */
11123 static MonoObject*
11124 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
11125 {
11126         MonoCCW *ccw = NULL;
11127
11128         /* no CCW's exist yet */
11129         if (!ccw_interface_hash)
11130                 return NULL;
11131
11132         if (verify) {
11133                 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
11134         }
11135         else {
11136                 ccw = ccw_entry->ccw;
11137                 g_assert (ccw);
11138         }
11139         if (ccw)
11140                 return mono_gchandle_get_target (ccw->gc_handle);
11141         else
11142                 return NULL;
11143 }
11144
11145 static void
11146 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
11147 {
11148         MonoMethodSignature *sig, *csig;
11149         sig = mono_method_signature (method);
11150         /* we copy the signature, so that we can modify it */
11151         /* FIXME: which to use? */
11152         csig = signature_dup (method->klass->image, sig);
11153         /* csig = mono_metadata_signature_dup (sig); */
11154         
11155         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
11156 #ifdef PLATFORM_WIN32
11157         csig->call_convention = MONO_CALL_STDCALL;
11158 #else
11159         csig->call_convention = MONO_CALL_C;
11160 #endif
11161         csig->hasthis = 0;
11162         csig->pinvoke = 1;
11163
11164         m->image = method->klass->image;
11165         m->piinfo = NULL;
11166         m->retobj_var = 0;
11167         m->sig = sig;
11168         m->csig = csig;
11169 }
11170
11171 /**
11172  * cominterop_get_ccw:
11173  * @object: a pointer to the object
11174  * @itf: interface type needed
11175  *
11176  * Returns: a value indicating if the object is a
11177  * Runtime Callable Wrapper (RCW) for a COM object
11178  */
11179 static gpointer
11180 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
11181 {
11182         int i;
11183         MonoCCW *ccw = NULL;
11184         MonoCCWInterface* ccw_entry = NULL;
11185         gpointer *vtable = NULL;
11186         static gpointer iunknown[3] = {NULL, NULL, NULL};
11187         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
11188         MonoClass* iface = NULL;
11189         MonoClass* klass = NULL;
11190         EmitMarshalContext m;
11191         int start_slot = 3;
11192         int method_count = 0;
11193         GList *ccw_list, *ccw_list_item;
11194         MonoCustomAttrInfo *cinfo = NULL;
11195
11196         if (!object)
11197                 return NULL;
11198
11199         klass = mono_object_get_class (object);
11200
11201         if (!ccw_hash)
11202                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
11203         if (!ccw_interface_hash)
11204                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
11205
11206         ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
11207
11208         ccw_list_item = ccw_list;
11209         while (ccw_list_item) {
11210                 MonoCCW* ccw_iter = ccw_list_item->data;
11211                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
11212                         ccw = ccw_iter;
11213                         break;
11214                 }
11215                 ccw_list_item = g_list_next(ccw_list_item);
11216         }
11217
11218         if (!iunknown [0]) {
11219                 iunknown [0] = cominterop_ccw_queryinterface;
11220                 iunknown [1] = cominterop_ccw_addref;
11221                 iunknown [2] = cominterop_ccw_release;
11222         }
11223
11224         if (!idispatch [0]) {
11225                 idispatch [0] = cominterop_ccw_get_type_info_count;
11226                 idispatch [1] = cominterop_ccw_get_type_info;
11227                 idispatch [2] = cominterop_ccw_get_ids_of_names;
11228                 idispatch [3] = cominterop_ccw_invoke;
11229         }
11230
11231         if (!ccw) {
11232                 ccw = g_new0 (MonoCCW, 1);
11233                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
11234                 ccw->ref_count = 0;
11235                 /* just alloc a weak handle until we are addref'd*/
11236                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
11237
11238                 if (!ccw_list) {
11239                         ccw_list = g_list_alloc ();
11240                         ccw_list->data = ccw;
11241                 }
11242                 else
11243                         ccw_list = g_list_append (ccw_list, ccw);
11244                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
11245                 /* register for finalization to clean up ccw */
11246                 mono_object_register_finalizer (object);
11247         }
11248
11249         cinfo = mono_custom_attrs_from_class (itf);
11250         if (cinfo) {
11251                 static MonoClass* coclass_attribute = NULL;
11252                 if (!coclass_attribute)
11253                         coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
11254                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
11255                         g_assert(itf->interface_count && itf->interfaces[0]);
11256                         itf = itf->interfaces[0];
11257                 }
11258                 if (!cinfo->cached)
11259                         mono_custom_attrs_free (cinfo);
11260         }
11261
11262         iface = itf;
11263         if (iface == mono_defaults.iunknown_class) {
11264                 start_slot = 3;
11265         }
11266         else if (iface == mono_defaults.idispatch_class) {
11267                 start_slot = 7;
11268         }
11269         else {
11270                 method_count += iface->method.count;
11271                 start_slot = cominterop_get_com_slot_begin (iface);
11272                 iface = NULL;
11273         }
11274
11275         ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
11276
11277         if (!ccw_entry) {
11278                 int vtable_index = method_count-1+start_slot;
11279                 mono_loader_lock ();
11280                 vtable = mono_mempool_alloc0 (klass->image->mempool, sizeof (gpointer)*(method_count+start_slot));
11281                 mono_loader_unlock ();
11282                 memcpy (vtable, iunknown, sizeof (iunknown));
11283                 if (start_slot == 7)
11284                         memcpy (vtable+3, idispatch, sizeof (idispatch));
11285
11286                 iface = itf;
11287                 for (i = iface->method.count-1; i >= 0;i--) {
11288                         int param_index = 0;
11289                         MonoMethodBuilder *mb;
11290                         MonoMarshalSpec ** mspecs;
11291                         MonoMethod *wrapper_method, *adjust_method;
11292                         MonoMethod *method = iface->methods [i];
11293                         MonoMethodSignature* sig_adjusted;
11294                         MonoMethodSignature* sig = mono_method_signature (method);
11295                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
11296
11297
11298                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
11299                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
11300                         sig_adjusted = mono_method_signature (adjust_method);
11301                         
11302                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
11303                         mono_method_get_marshal_info (method, mspecs);
11304
11305                         
11306                         /* move managed args up one */
11307                         for (param_index = sig->param_count; param_index >= 1; param_index--)
11308                                 mspecs [param_index+1] = mspecs [param_index];
11309
11310                         /* first arg is IntPtr for interface */
11311                         mspecs [1] = NULL;
11312
11313                         /* move return spec to last param */
11314                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
11315                                 mspecs [sig_adjusted->param_count] = mspecs [0];
11316                                 mspecs [0] = NULL;
11317                         }
11318
11319                         cominterop_setup_marshal_context (&m, adjust_method);
11320                         m.mb = mb;
11321                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL);
11322                         mono_loader_lock ();
11323                         mono_marshal_lock ();
11324                         wrapper_method = mono_mb_create_method (mb, sig_adjusted, sig_adjusted->param_count + 16);
11325                         mono_marshal_unlock ();
11326                         mono_loader_unlock ();
11327
11328                         /* skip visiblity since we call internal methods */
11329                         wrapper_method->skip_visibility = TRUE;
11330
11331                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
11332
11333                         
11334                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
11335                                 if (mspecs [param_index])
11336                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
11337                         g_free (mspecs);
11338                 }
11339
11340                 ccw_entry = g_new0 (MonoCCWInterface, 1);
11341                 ccw_entry->ccw = ccw;
11342                 ccw_entry->vtable = vtable;
11343                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
11344                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
11345         }
11346
11347         return ccw_entry;
11348 }
11349
11350 static gboolean    
11351 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
11352 {
11353         g_assert (value);
11354         g_free (value);
11355         return TRUE;
11356 }
11357
11358 /**
11359  * mono_marshal_free_ccw:
11360  * @object: the mono object
11361  *
11362  * Returns: whether the object had a CCW
11363  */
11364 gboolean
11365 mono_marshal_free_ccw (MonoObject* object)
11366 {
11367         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
11368         /* no ccw's were created */
11369         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
11370                 return FALSE;
11371
11372         /* need to cache orig list address to remove from hash_table if empty */
11373         mono_cominterop_lock ();
11374         ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
11375         mono_cominterop_unlock ();
11376
11377         if (!ccw_list)
11378                 return FALSE;
11379
11380         ccw_list_item = ccw_list;
11381         while (ccw_list_item) {
11382                 MonoCCW* ccw_iter = ccw_list_item->data;
11383                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
11384
11385                 /* Looks like the GC NULLs the weakref handle target before running the
11386                  * finalizer. So if we get a NULL target, destroy the CCW as well. */
11387                 if (!handle_target || handle_target == object) {
11388                         /* remove all interfaces */
11389                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
11390                         g_hash_table_destroy (ccw_iter->vtable_hash);
11391
11392                         /* get next before we delete */
11393                         ccw_list_item = g_list_next(ccw_list_item);
11394
11395                         /* remove ccw from list */
11396                         ccw_list = g_list_remove (ccw_list, ccw_iter);
11397                         g_free (ccw_iter);
11398                 }
11399                 else
11400                         ccw_list_item = g_list_next(ccw_list_item);
11401         }
11402
11403         /* if list is empty remove original address from hash */
11404         if (g_list_length (ccw_list) == 0)
11405                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
11406
11407
11408         return TRUE;
11409 }
11410
11411 /**
11412  * cominterop_get_native_wrapper_adjusted:
11413  * @method: managed COM Interop method
11414  *
11415  * Returns: the generated method to call with signature matching
11416  * the unmanaged COM Method signature
11417  */
11418 static MonoMethod *
11419 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
11420 {
11421         static MonoMethod *get_hr_for_exception = NULL;
11422         MonoMethod *res = NULL;
11423         MonoMethodBuilder *mb;
11424         MonoMarshalSpec **mspecs;
11425         MonoMethodSignature *sig, *sig_native;
11426         MonoExceptionClause *main_clause = NULL;
11427         MonoMethodHeader *header;
11428         int pos_leave;
11429         int hr = 0;
11430         int i;
11431         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
11432
11433         if (!get_hr_for_exception)
11434                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
11435
11436         sig = mono_method_signature (method);
11437
11438         /* create unmanaged wrapper */
11439         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
11440
11441         sig_native = cominterop_method_signature (method);
11442
11443         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
11444
11445         mono_method_get_marshal_info (method, mspecs);
11446
11447         /* move managed args up one */
11448         for (i = sig->param_count; i >= 1; i--)
11449                 mspecs [i+1] = mspecs [i];
11450
11451         /* first arg is IntPtr for interface */
11452         mspecs [1] = NULL;
11453
11454         /* move return spec to last param */
11455         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
11456                 mspecs [sig_native->param_count] = mspecs [0];
11457
11458         mspecs [0] = NULL;
11459
11460         if (!preserve_sig) {
11461                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
11462
11463                 /* try */
11464                 main_clause = g_new0 (MonoExceptionClause, 1);
11465                 main_clause->try_offset = mono_mb_get_label (mb);
11466         }
11467
11468         /* load last param to store result if not preserve_sig and not void */
11469         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
11470                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
11471
11472         /* the CCW -> object conversion */
11473         mono_mb_emit_ldarg (mb, 0);
11474         mono_mb_emit_icon (mb, FALSE);
11475         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
11476
11477         for (i = 0; i < sig->param_count; i++)
11478                 mono_mb_emit_ldarg (mb, i+1);
11479
11480         mono_mb_emit_managed_call (mb, method, NULL);
11481
11482         if (!preserve_sig) {
11483                 /* store result if not preserve_sig and we have one */
11484                 if (!MONO_TYPE_IS_VOID (sig->ret))
11485                         mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
11486
11487                 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
11488
11489                 /* Main exception catch */
11490                 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
11491                 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
11492                 main_clause->data.catch_class = mono_defaults.object_class;
11493                 
11494                 /* handler code */
11495                 main_clause->handler_offset = mono_mb_get_label (mb);
11496                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
11497                 mono_mb_emit_stloc (mb, hr);
11498                 mono_mb_emit_branch (mb, CEE_LEAVE);
11499                 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
11500                 /* end catch */
11501
11502                 mono_mb_patch_branch (mb, pos_leave);
11503
11504                 mono_mb_emit_ldloc (mb, hr);
11505         }
11506
11507         mono_mb_emit_byte (mb, CEE_RET);
11508
11509         mono_loader_lock ();
11510         mono_marshal_lock ();
11511         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
11512         mono_marshal_unlock ();
11513         mono_loader_unlock ();
11514
11515         mono_mb_free (mb);
11516
11517         for (i = sig_native->param_count; i >= 0; i--)
11518                 if (mspecs [i])
11519                         mono_metadata_free_marshal_spec (mspecs [i]);
11520         g_free (mspecs);
11521
11522         if (!preserve_sig) {
11523                 header = ((MonoMethodNormal *)res)->header;
11524                 header->num_clauses = 1;
11525                 header->clauses = main_clause;
11526         }
11527
11528         return res;
11529 }
11530
11531 /**
11532  * cominterop_mono_string_to_guid:
11533  *
11534  * Converts the standard string representation of a GUID 
11535  * to a 16 byte Microsoft GUID.
11536  */
11537 static void
11538 cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
11539         gunichar2 * chars = mono_string_chars (string);
11540         int i = 0;
11541         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
11542
11543         for (i = 0; i < sizeof(indexes); i++)
11544                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
11545 }
11546
11547 static gboolean
11548 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
11549 {
11550         guint8 klass_guid [16];
11551         if (cominterop_class_guid (klass, klass_guid))
11552                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
11553         return FALSE;
11554 }
11555
11556 static int STDCALL 
11557 cominterop_ccw_addref (MonoCCWInterface* ccwe)
11558 {
11559         gint32 ref_count = 0;
11560         MonoCCW* ccw = ccwe->ccw;
11561         g_assert (ccw);
11562         g_assert (ccw->gc_handle);
11563         g_assert (ccw->ref_count >= 0);
11564         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
11565         if (ref_count == 1) {
11566                 guint32 oldhandle = ccw->gc_handle;
11567                 g_assert (oldhandle);
11568                 /* since we now have a ref count, alloc a strong handle*/
11569                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
11570                 mono_gchandle_free (oldhandle);
11571         }
11572         return ref_count;
11573 }
11574
11575 static int STDCALL 
11576 cominterop_ccw_release (MonoCCWInterface* ccwe)
11577 {
11578         gint32 ref_count = 0;
11579         MonoCCW* ccw = ccwe->ccw;
11580         g_assert (ccw);
11581         g_assert (ccw->ref_count > 0);
11582         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
11583         if (ref_count == 0) {
11584                 /* allow gc of object */
11585                 guint32 oldhandle = ccw->gc_handle;
11586                 g_assert (oldhandle);
11587                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
11588                 mono_gchandle_free (oldhandle);
11589         }
11590         return ref_count;
11591 }
11592
11593 #define MONO_S_OK 0x00000000L
11594 #define MONO_E_NOINTERFACE 0x80004002L
11595 #define MONO_E_NOTIMPL 0x80004001L
11596
11597 static int STDCALL 
11598 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
11599 {
11600         GPtrArray *ifaces;
11601         MonoClass *itf = NULL;
11602         int i;
11603         MonoCCW* ccw = ccwe->ccw;
11604         MonoClass* klass = NULL;
11605         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
11606         
11607         g_assert (object);
11608         klass = mono_object_class (object);
11609
11610         if (ppv)
11611                 *ppv = NULL;
11612
11613         /* handle IUnknown special */
11614         if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
11615                 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
11616                 /* remember to addref on QI */
11617                 cominterop_ccw_addref (*ppv);
11618                 return MONO_S_OK;
11619         }
11620
11621         /* handle IDispatch special */
11622         if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
11623                 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
11624                 /* remember to addref on QI */
11625                 cominterop_ccw_addref (*ppv);
11626                 return MONO_S_OK;
11627         }
11628
11629         ifaces = mono_class_get_implemented_interfaces (klass);
11630         if (ifaces) {
11631                 for (i = 0; i < ifaces->len; ++i) {
11632                         MonoClass *ic = NULL;
11633                         ic = g_ptr_array_index (ifaces, i);
11634                         if (cominterop_class_guid_equal (riid, ic)) {
11635                                 itf = ic;
11636                                 break;
11637                         }
11638                 }
11639                 g_ptr_array_free (ifaces, TRUE);
11640         }
11641         if (itf) {
11642                 *ppv = cominterop_get_ccw (object, itf);
11643                 /* remember to addref on QI */
11644                 cominterop_ccw_addref (*ppv);
11645                 return MONO_S_OK;
11646         }
11647
11648         return MONO_E_NOINTERFACE;
11649 }
11650
11651 static int STDCALL 
11652 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
11653 {
11654         return MONO_E_NOTIMPL;
11655 }
11656
11657 static int STDCALL 
11658 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
11659 {
11660         return MONO_E_NOTIMPL;
11661 }
11662
11663 static int STDCALL 
11664 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
11665                                                                                          gunichar2** rgszNames, guint32 cNames,
11666                                                                                          guint32 lcid, gint32 *rgDispId)
11667 {
11668         return MONO_E_NOTIMPL;
11669 }
11670
11671 static int STDCALL 
11672 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
11673                                                                    gpointer riid, guint32 lcid,
11674                                                                    guint16 wFlags, gpointer pDispParams,
11675                                                                    gpointer pVarResult, gpointer pExcepInfo,
11676                                                                    guint32 *puArgErr)
11677 {
11678         return MONO_E_NOTIMPL;
11679 }