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