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