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