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