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