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