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