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