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