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