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