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