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