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