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