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