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