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