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