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