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