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