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