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