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