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