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