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