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