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