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