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