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