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