ea2ff0c3d7b2fc029d42a882f828d220bee6258f
[mono.git] / mono / metadata / remoting.c
1 /**
2  * \file
3  * Remoting support
4  * 
5  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
6  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
7  * Copyright 2011-2014 Xamarin, Inc (http://www.xamarin.com)
8  *
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #include "config.h"
13
14 #include "mono/metadata/handle.h"
15 #include "mono/metadata/remoting.h"
16 #include "mono/metadata/marshal.h"
17 #include "mono/metadata/marshal-internals.h"
18 #include "mono/metadata/abi-details.h"
19 #include "mono/metadata/cominterop.h"
20 #include "mono/metadata/tabledefs.h"
21 #include "mono/metadata/exception.h"
22 #include "mono/metadata/debug-helpers.h"
23 #include "mono/metadata/reflection-internals.h"
24
25 typedef enum {
26         MONO_MARSHAL_NONE,                      /* No marshalling needed */
27         MONO_MARSHAL_COPY,                      /* Can be copied by value to the new domain */
28         MONO_MARSHAL_COPY_OUT,          /* out parameter that needs to be copied back to the original instance */
29         MONO_MARSHAL_SERIALIZE          /* Value needs to be serialized into the new domain */
30 } MonoXDomainMarshalType;
31
32 #ifndef DISABLE_REMOTING
33
34 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
35         a = i,
36
37 enum {
38 #include "mono/cil/opcode.def"
39         LAST = 0xff
40 };
41 #undef OPDEF
42
43 struct _MonoRemotingMethods {
44         MonoMethod *invoke;
45         MonoMethod *invoke_with_check;
46         MonoMethod *xdomain_invoke;
47         MonoMethod *xdomain_dispatch;
48 };
49
50 typedef struct _MonoRemotingMethods MonoRemotingMethods;
51
52 static MonoObject *
53 mono_remoting_wrapper (MonoMethod *method, gpointer *params);
54
55 static gint32
56 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push);
57
58 static gboolean
59 mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image);
60
61 MONO_API void
62 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy);
63
64 static MonoXDomainMarshalType
65 mono_get_xdomain_marshal_type (MonoType *t);
66
67 static void
68 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst);
69
70 static MonoReflectionType *
71 type_from_handle (MonoType *handle);
72
73 static void
74 mono_context_set_icall (MonoAppContext *new_context);
75
76 static MonoAppContext*
77 mono_context_get_icall (void);
78
79
80 /* Class lazy loading functions */
81 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
82 static GENERATE_GET_CLASS_WITH_CACHE (call_context, "System.Runtime.Remoting.Messaging", "CallContext")
83 static GENERATE_GET_CLASS_WITH_CACHE (context, "System.Runtime.Remoting.Contexts", "Context")
84
85 static mono_mutex_t remoting_mutex;
86 static gboolean remoting_mutex_inited;
87
88 static MonoClass *byte_array_class;
89 #ifndef DISABLE_JIT
90 static MonoMethod *method_rs_serialize, *method_rs_deserialize, *method_exc_fixexc, *method_rs_appdomain_target;
91 static MonoMethod *method_set_call_context, *method_needs_context_sink, *method_rs_serialize_exc;
92 #endif
93
94 static gpointer
95 mono_compile_method_icall (MonoMethod *method);
96
97 static void
98 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
99 {
100         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
101
102         mono_register_jit_icall (func, name, sig, save);
103 }
104
105 static inline void
106 remoting_lock (void)
107 {
108         g_assert (remoting_mutex_inited);
109         mono_os_mutex_lock (&remoting_mutex);
110 }
111
112 static inline void
113 remoting_unlock (void)
114 {
115         g_assert (remoting_mutex_inited);
116         mono_os_mutex_unlock (&remoting_mutex);
117 }
118
119 /*
120  * Return the hash table pointed to by VAR, lazily creating it if neccesary.
121  */
122 static GHashTable*
123 get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
124 {
125         if (!(*var)) {
126                 remoting_lock ();
127                 if (!(*var)) {
128                         GHashTable *cache = 
129                                 g_hash_table_new (hash_func, equal_func);
130                         mono_memory_barrier ();
131                         *var = cache;
132                 }
133                 remoting_unlock ();
134         }
135         return *var;
136 }
137
138 static GHashTable*
139 get_cache_full (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
140 {
141         if (!(*var)) {
142                 remoting_lock ();
143                 if (!(*var)) {
144                         GHashTable *cache = 
145                                 g_hash_table_new_full (hash_func, equal_func, key_destroy_func, value_destroy_func);
146                         mono_memory_barrier ();
147                         *var = cache;
148                 }
149                 remoting_unlock ();
150         }
151         return *var;
152 }
153
154 void
155 mono_remoting_init (void)
156 {
157         mono_os_mutex_init (&remoting_mutex);
158         remoting_mutex_inited = TRUE;
159 }
160
161 static void
162 mono_remoting_marshal_init (void)
163 {
164         MonoClass *klass;
165
166         static gboolean module_initialized = FALSE;
167         static gboolean icalls_registered = FALSE;
168
169         if (module_initialized)
170                 return;
171
172         byte_array_class = mono_array_class_get (mono_defaults.byte_class, 1);
173
174 #ifndef DISABLE_JIT
175         klass = mono_class_get_remoting_services_class ();
176         method_rs_serialize = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
177         g_assert (method_rs_serialize);
178         method_rs_deserialize = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
179         g_assert (method_rs_deserialize);
180         method_rs_serialize_exc = mono_class_get_method_from_name (klass, "SerializeExceptionData", -1);
181         g_assert (method_rs_serialize_exc);
182         
183         klass = mono_defaults.real_proxy_class;
184         method_rs_appdomain_target = mono_class_get_method_from_name (klass, "GetAppDomainTarget", -1);
185         g_assert (method_rs_appdomain_target);
186         
187         klass = mono_defaults.exception_class;
188         method_exc_fixexc = mono_class_get_method_from_name (klass, "FixRemotingException", -1);
189         g_assert (method_exc_fixexc);
190
191         klass = mono_class_get_call_context_class ();
192         method_set_call_context = mono_class_get_method_from_name (klass, "SetCurrentCallContext", -1);
193         g_assert (method_set_call_context);
194
195         klass = mono_class_get_context_class ();
196         method_needs_context_sink = mono_class_get_method_from_name (klass, "get_NeedsContextSink", -1);
197         g_assert (method_needs_context_sink);
198 #endif  
199
200         mono_loader_lock ();
201
202         if (!icalls_registered) {
203                 register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE);
204                 register_icall (mono_marshal_set_domain_by_id, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE);
205                 register_icall (mono_marshal_check_domain_image, "mono_marshal_check_domain_image", "int32 int32 ptr", FALSE);
206                 register_icall (ves_icall_mono_marshal_xdomain_copy_value, "ves_icall_mono_marshal_xdomain_copy_value", "object object", FALSE);
207                 register_icall (mono_marshal_xdomain_copy_out_value, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE);
208                 register_icall (mono_remoting_wrapper, "mono_remoting_wrapper", "object ptr ptr", FALSE);
209                 register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE);
210
211 #ifndef DISABLE_JIT
212                 register_icall (mono_compile_method_icall, "mono_compile_method_icall", "ptr ptr", FALSE);
213 #endif
214
215                 register_icall (mono_context_get_icall, "mono_context_get_icall", "object", FALSE);
216                 register_icall (mono_context_set_icall, "mono_context_set_icall", "void object", FALSE);
217
218         }
219
220         icalls_registered = TRUE;
221
222         mono_loader_unlock ();
223
224         module_initialized = TRUE;
225 }
226
227 /* This is an icall, it will return NULL and set pending exception on failure */
228 static MonoReflectionType *
229 type_from_handle (MonoType *handle)
230 {
231         MonoError error;
232         MonoReflectionType *ret;
233         MonoDomain *domain = mono_domain_get (); 
234         MonoClass *klass = mono_class_from_mono_type (handle);
235
236         mono_class_init (klass);
237
238         ret = mono_type_get_object_checked (domain, handle, &error);
239         mono_error_set_pending_exception (&error);
240
241         return ret;
242 }
243
244 #ifndef DISABLE_JIT
245 static int
246 mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
247 {
248         int pos;
249         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
250         mono_mb_emit_byte (mb, CEE_LDIND_I);
251         mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
252         mono_mb_emit_byte (mb, CEE_ADD);
253         mono_mb_emit_byte (mb, CEE_LDIND_I);
254         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
255         mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
256         mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
257         pos = mono_mb_emit_branch (mb, branch_code);
258         return pos;
259 }
260
261 static int
262 mono_mb_emit_xdomain_check (MonoMethodBuilder *mb, int branch_code)
263 {
264         int pos;
265         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
266         mono_mb_emit_byte (mb, CEE_LDIND_REF);
267         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
268         mono_mb_emit_byte (mb, CEE_LDIND_I4);
269         mono_mb_emit_icon (mb, -1);
270         pos = mono_mb_emit_branch (mb, branch_code);
271         return pos;
272 }
273
274 static int
275 mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code)
276 {
277         static int offset = -1;
278         static guint8 mask;
279
280         if (offset < 0)
281                 mono_marshal_find_bitfield_offset (MonoClass, contextbound, &offset, &mask);
282
283         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
284         mono_mb_emit_byte (mb, CEE_LDIND_REF);
285         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
286         mono_mb_emit_byte (mb, CEE_LDIND_REF);
287         mono_mb_emit_ldflda (mb, offset);
288         mono_mb_emit_byte (mb, CEE_LDIND_U1);
289         mono_mb_emit_icon (mb, mask);
290         mono_mb_emit_byte (mb, CEE_AND);
291         mono_mb_emit_icon (mb, 0);
292         return mono_mb_emit_branch (mb, branch_code);
293 }
294 #endif /* !DISABLE_JIT */
295
296 static inline MonoMethod*
297 mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type)
298 {
299         MonoMethod *res = NULL;
300         MonoRemotingMethods *wrps = NULL;
301
302         mono_marshal_lock_internal ();
303         if (mono_method_get_wrapper_cache (method)->remoting_invoke_cache)
304                 wrps = (MonoRemotingMethods *)g_hash_table_lookup (mono_method_get_wrapper_cache (method)->remoting_invoke_cache, method);
305
306         if (wrps) {
307                 switch (wrapper_type) {
308                 case MONO_WRAPPER_REMOTING_INVOKE: res = wrps->invoke; break;
309                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = wrps->invoke_with_check; break;
310                 case MONO_WRAPPER_XDOMAIN_INVOKE: res = wrps->xdomain_invoke; break;
311                 case MONO_WRAPPER_XDOMAIN_DISPATCH: res = wrps->xdomain_dispatch; break;
312                 }
313         }
314         
315         /* it is important to do the unlock after the load from wrps, since in
316          * mono_remoting_mb_create_and_cache () we drop the marshal lock to be able
317          * to take the loader lock and some other thread may set the fields.
318          */
319         mono_marshal_unlock_internal ();
320         return res;
321 }
322
323 /* Create the method from the builder and place it in the cache */
324 static inline MonoMethod*
325 mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb, 
326                                                                    MonoMethodSignature *sig, int max_stack, WrapperInfo *info)
327 {
328         MonoMethod **res = NULL;
329         MonoRemotingMethods *wrps;
330         GHashTable *cache;
331
332         cache = get_cache_full (&mono_method_get_wrapper_cache (key)->remoting_invoke_cache, mono_aligned_addr_hash, NULL, NULL, g_free);
333
334         mono_marshal_lock_internal ();
335         wrps = (MonoRemotingMethods *)g_hash_table_lookup (cache, key);
336         if (!wrps) {
337                 wrps = g_new0 (MonoRemotingMethods, 1);
338                 g_hash_table_insert (cache, key, wrps);
339         }
340
341         switch (mb->method->wrapper_type) {
342         case MONO_WRAPPER_REMOTING_INVOKE: res = &wrps->invoke; break;
343         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: res = &wrps->invoke_with_check; break;
344         case MONO_WRAPPER_XDOMAIN_INVOKE: res = &wrps->xdomain_invoke; break;
345         case MONO_WRAPPER_XDOMAIN_DISPATCH: res = &wrps->xdomain_dispatch; break;
346         default: g_assert_not_reached (); break;
347         }
348         mono_marshal_unlock_internal ();
349
350         if (*res == NULL) {
351                 MonoMethod *newm;
352                 newm = mono_mb_create_method (mb, sig, max_stack);
353
354                 mono_marshal_lock_internal ();
355                 if (!*res) {
356                         *res = newm;
357                         mono_marshal_set_wrapper_info (*res, info);
358                         mono_marshal_unlock_internal ();
359                 } else {
360                         mono_marshal_unlock_internal ();
361                         mono_free_method (newm);
362                 }
363         }
364
365         return *res;
366 }               
367
368 static MonoObject *
369 mono_remoting_wrapper (MonoMethod *method, gpointer *params)
370 {
371         MonoError error;
372         MonoMethodMessage *msg;
373         MonoTransparentProxy *this_obj;
374         MonoObject *res, *exc;
375         MonoArray *out_args;
376
377         this_obj = *((MonoTransparentProxy **)params [0]);
378
379         g_assert (this_obj);
380         g_assert (mono_object_is_transparent_proxy (this_obj));
381         
382         /* skip the this pointer */
383         params++;
384
385         if (mono_class_is_contextbound (this_obj->remote_class->proxy_class) && this_obj->rp->context == (MonoObject *) mono_context_get ())
386         {
387                 int i;
388                 MonoMethodSignature *sig = mono_method_signature (method);
389                 int count = sig->param_count;
390                 gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
391
392                 for (i=0; i<count; i++) {
393                         MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
394                         if (klass->valuetype) {
395                                 if (sig->params [i]->byref) {
396                                         mparams[i] = *((gpointer *)params [i]);
397                                 } else {
398                                         /* runtime_invoke expects a boxed instance */
399                                         if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
400                                                 mparams[i] = mono_nullable_box ((guint8 *)params [i], klass, &error);
401                                                 if (!is_ok (&error))
402                                                         goto fail;
403                                         } else
404                                                 mparams[i] = params [i];
405                                 }
406                         } else {
407                                 mparams[i] = *((gpointer**)params [i]);
408                         }
409                 }
410
411                 res = mono_runtime_invoke_checked (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this_obj): this_obj, mparams, &error);
412                 if (!is_ok (&error))
413                         goto fail;
414
415                 return res;
416         }
417
418         msg = mono_method_call_message_new (method, params, NULL, NULL, NULL, &error);
419         if (!is_ok (&error))
420                 goto fail;
421
422         res = mono_remoting_invoke ((MonoObject *)this_obj->rp, msg, &exc, &out_args, &error);
423         if (!is_ok (&error))
424                 goto fail;
425
426         if (exc) {
427                 error_init (&error);
428                 mono_error_set_exception_instance (&error, (MonoException *)exc);
429                 goto fail;
430         }
431
432         mono_method_return_message_restore (method, params, out_args, &error);
433         if (!is_ok (&error)) goto fail;
434
435         return res;
436 fail:
437         /* This icall will be called from managed code, and more over
438          * from a protected wrapper so interruptions such as pending
439          * exceptions will not be honored.  (See
440          * is_running_protected_wrapper () in threads.c and
441          * mono_marshal_get_remoting_invoke () in remoting.c)
442          */
443         mono_error_raise_exception (&error); /* OK to throw, see note */
444         return NULL;
445
446
447
448 /**
449  * mono_marshal_get_remoting_invoke:
450  */
451 MonoMethod *
452 mono_marshal_get_remoting_invoke (MonoMethod *method)
453 {
454         MonoMethodSignature *sig;
455         MonoMethodBuilder *mb;
456         MonoMethod *res;
457         int params_var;
458         WrapperInfo *info;
459
460         g_assert (method);
461
462         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
463                 return method;
464
465         /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
466 #ifndef DISABLE_COM
467         if (mono_class_is_com_object (method->klass) || method->klass == mono_class_try_get_com_object_class ()) {
468                 MonoVTable *vtable = mono_class_vtable (mono_domain_get (), method->klass);
469                 g_assert (vtable); /*FIXME do proper error handling*/
470
471                 if (!mono_vtable_is_remote (vtable)) {
472                         return mono_cominterop_get_invoke (method);
473                 }
474         }
475 #endif
476
477         sig = mono_signature_no_pinvoke (method);
478
479         /* we cant remote methods without this pointer */
480         if (!sig->hasthis)
481                 return method;
482
483         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE)))
484                 return res;
485
486         mono_remoting_marshal_init ();
487
488         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
489
490 #ifndef DISABLE_JIT
491         mb->method->save_lmf = 1;
492
493         params_var = mono_mb_emit_save_args (mb, sig, TRUE);
494
495         mono_mb_emit_ptr (mb, method);
496         mono_mb_emit_ldloc (mb, params_var);
497         mono_mb_emit_icall (mb, mono_remoting_wrapper);
498         // FIXME: this interrupt checkpoint code is a no-op since 'mb'
499         //  is a MONO_WRAPPER_REMOTING_INVOKE, and
500         //  mono_thread_interruption_checkpoint_request (FALSE)
501         //  considers such wrappers "protected" and always returns
502         //  NULL as if there's no pending interruption.
503         mono_marshal_emit_thread_interrupt_checkpoint (mb);
504
505         if (sig->ret->type == MONO_TYPE_VOID) {
506                 mono_mb_emit_byte (mb, CEE_POP);
507                 mono_mb_emit_byte (mb, CEE_RET);
508         } else {
509                  mono_mb_emit_restore_result (mb, sig->ret);
510         }
511 #endif
512
513         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
514         info->d.remoting.method = method;
515         res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16, info);
516         mono_mb_free (mb);
517
518         return res;
519 }
520
521 /* mono_marshal_xdomain_copy_out_value()
522  * Copies the contents of the src instance into the dst instance. src and dst
523  * must have the same type, and if they are arrays, the same size.
524  *
525  * This is an icall, it may use mono_error_set_pending_exception
526  */
527 static void
528 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst)
529 {
530         MonoError error;
531         if (src == NULL || dst == NULL) return;
532         
533         g_assert (mono_object_class (src) == mono_object_class (dst));
534
535         switch (mono_object_class (src)->byval_arg.type) {
536         case MONO_TYPE_ARRAY:
537         case MONO_TYPE_SZARRAY: {
538                 int mt = mono_get_xdomain_marshal_type (&(mono_object_class (src)->element_class->byval_arg));
539                 if (mt == MONO_MARSHAL_SERIALIZE) return;
540                 if (mt == MONO_MARSHAL_COPY) {
541                         int i, len = mono_array_length ((MonoArray *)dst);
542                         for (i = 0; i < len; i++) {
543                                 MonoObject *item = (MonoObject *)mono_array_get ((MonoArray *)src, gpointer, i);
544                                 MonoObject *item_copy = mono_marshal_xdomain_copy_value (item, &error);
545                                 if (mono_error_set_pending_exception (&error))
546                                         return;
547                                 mono_array_setref ((MonoArray *)dst, i, item_copy);
548                         }
549                 } else {
550                         mono_array_full_copy ((MonoArray *)src, (MonoArray *)dst);
551                 }
552                 return;
553         }
554         default:
555                 break;
556         }
557
558 }
559
560
561 #if !defined (DISABLE_JIT)
562 static void
563 mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder *mb, MonoClass *pclass)
564 {
565         mono_mb_emit_icall (mb, ves_icall_mono_marshal_xdomain_copy_value);
566         mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
567 }
568
569 static void
570 mono_marshal_emit_xdomain_copy_out_value (MonoMethodBuilder *mb, MonoClass *pclass)
571 {
572         mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_out_value);
573 }
574 #endif
575
576 /* mono_marshal_supports_fast_xdomain()
577  * Returns TRUE if the method can use the fast xdomain wrapper.
578  */
579 static gboolean
580 mono_marshal_supports_fast_xdomain (MonoMethod *method)
581 {
582         return !mono_class_is_contextbound (method->klass) &&
583                    !((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp (".ctor", method->name) == 0));
584 }
585
586 static gint32
587 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push)
588 {
589         MonoDomain *current_domain = mono_domain_get ();
590         MonoDomain *domain = mono_domain_get_by_id (id);
591
592         if (!domain || !mono_domain_set (domain, FALSE)) {
593                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
594                 return 0;
595         }
596
597         if (push)
598                 mono_thread_push_appdomain_ref (domain);
599         else
600                 mono_thread_pop_appdomain_ref ();
601
602         return current_domain->domain_id;
603 }
604
605 #if !defined (DISABLE_JIT)
606 static void
607 mono_marshal_emit_switch_domain (MonoMethodBuilder *mb)
608 {
609         mono_mb_emit_icall (mb, mono_marshal_set_domain_by_id);
610 }
611
612 gpointer
613 mono_compile_method_icall (MonoMethod *method)
614 {
615         MonoError error;
616         gpointer result = mono_compile_method_checked (method, &error);
617         mono_error_set_pending_exception (&error);
618         return result;
619 }
620
621 /* mono_marshal_emit_load_domain_method ()
622  * Loads into the stack a pointer to the code of the provided method for
623  * the current domain.
624  */
625 static void
626 mono_marshal_emit_load_domain_method (MonoMethodBuilder *mb, MonoMethod *method)
627 {
628         /* We need a pointer to the method for the running domain (not the domain
629          * that compiles the method).
630          */
631         mono_mb_emit_ptr (mb, method);
632         mono_mb_emit_icall (mb, mono_compile_method_icall);
633 }
634 #endif
635
636 /* mono_marshal_check_domain_image ()
637  * Returns TRUE if the image is loaded in the specified
638  * application domain.
639  */
640 static gboolean
641 mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image)
642 {
643         MonoAssembly* ass;
644         GSList *tmp;
645         
646         MonoDomain *domain = mono_domain_get_by_id (domain_id);
647         if (!domain)
648                 return FALSE;
649         
650         mono_domain_assemblies_lock (domain);
651         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
652                 ass = (MonoAssembly *)tmp->data;
653                 if (ass->image == image)
654                         break;
655         }
656         mono_domain_assemblies_unlock (domain);
657         
658         return tmp != NULL;
659 }
660
661 /* mono_marshal_get_xappdomain_dispatch ()
662  * Generates a method that dispatches a method call from another domain into
663  * the current domain.
664  */
665 static MonoMethod *
666 mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, int complex_count, int complex_out_count, int ret_marshal_type)
667 {
668         MonoMethodSignature *sig, *csig;
669         MonoMethodBuilder *mb;
670         MonoMethod *res;
671         int i, j, param_index, copy_locals_base;
672         MonoClass *ret_class = NULL;
673         int loc_array=0, loc_return=0, loc_serialized_exc=0;
674         MonoExceptionClause *clauses, *main_clause, *serialization_clause;
675         int pos, pos_leave, pos_leave_serialization;
676         gboolean copy_return;
677         WrapperInfo *info;
678
679         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_DISPATCH)))
680                 return res;
681
682         sig = mono_method_signature (method);
683         copy_return = (sig->ret->type != MONO_TYPE_VOID && ret_marshal_type != MONO_MARSHAL_SERIALIZE);
684
685         j = 0;
686         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3 + sig->param_count - complex_count);
687         csig->params [j++] = &mono_defaults.object_class->byval_arg;
688         csig->params [j++] = &byte_array_class->this_arg;
689         csig->params [j++] = &byte_array_class->this_arg;
690         for (i = 0; i < sig->param_count; i++) {
691                 if (marshal_types [i] != MONO_MARSHAL_SERIALIZE)
692                         csig->params [j++] = sig->params [i];
693         }
694         if (copy_return)
695                 csig->ret = sig->ret;
696         else
697                 csig->ret = &mono_defaults.void_class->byval_arg;
698         csig->pinvoke = 1;
699         csig->hasthis = FALSE;
700
701         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_DISPATCH);
702         mb->method->save_lmf = 1;
703
704 #ifndef DISABLE_JIT
705         /* Locals */
706
707         loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
708         if (complex_count > 0)
709                 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
710         if (sig->ret->type != MONO_TYPE_VOID) {
711                 loc_return = mono_mb_add_local (mb, sig->ret);
712                 ret_class = mono_class_from_mono_type (sig->ret);
713         }
714
715         /* try */
716
717         clauses = (MonoExceptionClause *)mono_image_alloc0 (method->klass->image, 2 * sizeof (MonoExceptionClause));
718         main_clause = &clauses [0];
719         main_clause->try_offset = mono_mb_get_label (mb);
720
721         /* Clean the call context */
722
723         mono_mb_emit_byte (mb, CEE_LDNULL);
724         mono_mb_emit_managed_call (mb, method_set_call_context, NULL);
725         mono_mb_emit_byte (mb, CEE_POP);
726
727         /* Deserialize call data */
728
729         mono_mb_emit_ldarg (mb, 1);
730         mono_mb_emit_byte (mb, CEE_LDIND_REF);
731         mono_mb_emit_byte (mb, CEE_DUP);
732         pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
733         
734         mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
735         mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
736         
737         if (complex_count > 0)
738                 mono_mb_emit_stloc (mb, loc_array);
739         else
740                 mono_mb_emit_byte (mb, CEE_POP);
741
742         mono_mb_patch_short_branch (mb, pos);
743
744         /* Get the target object */
745         
746         mono_mb_emit_ldarg (mb, 0);
747         mono_mb_emit_managed_call (mb, method_rs_appdomain_target, NULL);
748
749         /* Load the arguments */
750         
751         copy_locals_base = mb->locals;
752         param_index = 3;        // Index of the first non-serialized parameter of this wrapper
753         j = 0;
754         for (i = 0; i < sig->param_count; i++) {
755                 MonoType *pt = sig->params [i];
756                 MonoClass *pclass = mono_class_from_mono_type (pt);
757                 switch (marshal_types [i]) {
758                 case MONO_MARSHAL_SERIALIZE: {
759                         /* take the value from the serialized array */
760                         mono_mb_emit_ldloc (mb, loc_array);
761                         mono_mb_emit_icon (mb, j++);
762                         if (pt->byref) {
763                                 if (pclass->valuetype) {
764                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
765                                         mono_mb_emit_op (mb, CEE_UNBOX, pclass);
766                                 } else {
767                                         mono_mb_emit_op (mb, CEE_LDELEMA, pclass);
768                                 }
769                         } else {
770                                 if (pclass->valuetype) {
771                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
772                                         mono_mb_emit_op (mb, CEE_UNBOX, pclass);
773                                         mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
774                                 } else {
775                                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
776                                         if (pclass != mono_defaults.object_class) {
777                                                 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
778                                         }
779                                 }
780                         }
781                         break;
782                 }
783                 case MONO_MARSHAL_COPY_OUT: {
784                         /* Keep a local copy of the value since we need to copy it back after the call */
785                         int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
786                         mono_mb_emit_ldarg (mb, param_index++);
787                         mono_marshal_emit_xdomain_copy_value (mb, pclass);
788                         mono_mb_emit_byte (mb, CEE_DUP);
789                         mono_mb_emit_stloc (mb, copy_local);
790                         break;
791                 }
792                 case MONO_MARSHAL_COPY: {
793                         mono_mb_emit_ldarg (mb, param_index);
794                         if (pt->byref) {
795                                 mono_mb_emit_byte (mb, CEE_DUP);
796                                 mono_mb_emit_byte (mb, CEE_DUP);
797                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
798                                 mono_marshal_emit_xdomain_copy_value (mb, pclass);
799                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
800                         } else {
801                                 mono_marshal_emit_xdomain_copy_value (mb, pclass);
802                         }
803                         param_index++;
804                         break;
805                 }
806                 case MONO_MARSHAL_NONE:
807                         mono_mb_emit_ldarg (mb, param_index++);
808                         break;
809                 }
810         }
811
812         /* Make the call to the real object */
813
814         mono_marshal_emit_thread_force_interrupt_checkpoint (mb);
815         
816         mono_mb_emit_op (mb, CEE_CALLVIRT, method);
817
818         if (sig->ret->type != MONO_TYPE_VOID)
819                 mono_mb_emit_stloc (mb, loc_return);
820
821         /* copy back MONO_MARSHAL_COPY_OUT parameters */
822
823         j = 0;
824         param_index = 3;
825         for (i = 0; i < sig->param_count; i++) {
826                 if (marshal_types [i] == MONO_MARSHAL_SERIALIZE) continue;
827                 if (marshal_types [i] == MONO_MARSHAL_COPY_OUT) {
828                         mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
829                         mono_mb_emit_ldarg (mb, param_index);
830                         mono_marshal_emit_xdomain_copy_out_value (mb, mono_class_from_mono_type (sig->params [i]));
831                 }
832                 param_index++;
833         }
834
835         /* Serialize the return values */
836         
837         if (complex_out_count > 0) {
838                 /* Reset parameters in the array that don't need to be serialized back */
839                 j = 0;
840                 for (i = 0; i < sig->param_count; i++) {
841                         if (marshal_types[i] != MONO_MARSHAL_SERIALIZE) continue;
842                         if (!sig->params [i]->byref) {
843                                 mono_mb_emit_ldloc (mb, loc_array);
844                                 mono_mb_emit_icon (mb, j);
845                                 mono_mb_emit_byte (mb, CEE_LDNULL);
846                                 mono_mb_emit_byte (mb, CEE_STELEM_REF);
847                         }
848                         j++;
849                 }
850         
851                 /* Add the return value to the array */
852         
853                 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
854                         mono_mb_emit_ldloc (mb, loc_array);
855                         mono_mb_emit_icon (mb, complex_count);  /* The array has an additional slot to hold the ret value */
856                         mono_mb_emit_ldloc (mb, loc_return);
857
858                         g_assert (ret_class); /*FIXME properly fail here*/
859                         if (ret_class->valuetype) {
860                                 mono_mb_emit_op (mb, CEE_BOX, ret_class);
861                         }
862                         mono_mb_emit_byte (mb, CEE_STELEM_REF);
863                 }
864         
865                 /* Serialize */
866         
867                 mono_mb_emit_ldarg (mb, 1);
868                 mono_mb_emit_ldloc (mb, loc_array);
869                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
870                 mono_mb_emit_byte (mb, CEE_STIND_REF);
871         } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
872                 mono_mb_emit_ldarg (mb, 1);
873                 mono_mb_emit_ldloc (mb, loc_return);
874                 if (ret_class->valuetype) {
875                         mono_mb_emit_op (mb, CEE_BOX, ret_class);
876                 }
877                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
878                 mono_mb_emit_byte (mb, CEE_STIND_REF);
879         } else {
880                 mono_mb_emit_ldarg (mb, 1);
881                 mono_mb_emit_byte (mb, CEE_LDNULL);
882                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
883                 mono_mb_emit_byte (mb, CEE_STIND_REF);
884         }
885
886         mono_mb_emit_ldarg (mb, 2);
887         mono_mb_emit_byte (mb, CEE_LDNULL);
888         mono_mb_emit_byte (mb, CEE_STIND_REF);
889         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
890
891         /* Main exception catch */
892         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
893         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
894         main_clause->data.catch_class = mono_defaults.object_class;
895         
896         /* handler code */
897         main_clause->handler_offset = mono_mb_get_label (mb);
898
899         /*
900          * We deserialize the exception in another try-catch so we can catch
901          * serialization failure exceptions.
902          */
903         serialization_clause = &clauses [1];
904         serialization_clause->try_offset = mono_mb_get_label (mb);
905
906         mono_mb_emit_managed_call (mb, method_rs_serialize_exc, NULL);
907         mono_mb_emit_stloc (mb, loc_serialized_exc);
908         mono_mb_emit_ldarg (mb, 2);
909         mono_mb_emit_ldloc (mb, loc_serialized_exc);
910         mono_mb_emit_byte (mb, CEE_STIND_REF);
911         pos_leave_serialization = mono_mb_emit_branch (mb, CEE_LEAVE);
912
913         /* Serialization exception catch */
914         serialization_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
915         serialization_clause->try_len = mono_mb_get_pos (mb) - serialization_clause->try_offset;
916         serialization_clause->data.catch_class = mono_defaults.object_class;
917
918         /* handler code */
919         serialization_clause->handler_offset = mono_mb_get_label (mb);
920
921         /*
922          * If the serialization of the original exception failed we serialize the newly
923          * thrown exception, which should always succeed, passing it over to the calling
924          * domain.
925          */
926         mono_mb_emit_managed_call (mb, method_rs_serialize_exc, NULL);
927         mono_mb_emit_stloc (mb, loc_serialized_exc);
928         mono_mb_emit_ldarg (mb, 2);
929         mono_mb_emit_ldloc (mb, loc_serialized_exc);
930         mono_mb_emit_byte (mb, CEE_STIND_REF);
931         mono_mb_emit_branch (mb, CEE_LEAVE);
932
933         /* end serialization exception catch */
934         serialization_clause->handler_len = mono_mb_get_pos (mb) - serialization_clause->handler_offset;
935         mono_mb_patch_branch (mb, pos_leave_serialization);
936
937         mono_mb_emit_branch (mb, CEE_LEAVE);
938         /* end main catch */
939         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
940         mono_mb_patch_branch (mb, pos_leave);
941         
942         if (copy_return)
943                 mono_mb_emit_ldloc (mb, loc_return);
944
945         mono_mb_emit_byte (mb, CEE_RET);
946
947         mono_mb_set_clauses (mb, 2, clauses);
948 #endif
949
950         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
951         info->d.remoting.method = method;
952         res = mono_remoting_mb_create_and_cache (method, mb, csig, csig->param_count + 16, info);
953         mono_mb_free (mb);
954
955         return res;
956 }
957
958 /**
959  * mono_marshal_get_xappdomain_invoke:
960  * Generates a fast remoting wrapper for cross app domain calls.
961  */
962 MonoMethod *
963 mono_marshal_get_xappdomain_invoke (MonoMethod *method)
964 {
965         MonoMethodSignature *sig;
966         MonoMethodBuilder *mb;
967         MonoMethod *res;
968         int i, j, complex_count, complex_out_count, copy_locals_base;
969         int *marshal_types;
970         MonoClass *ret_class = NULL;
971         MonoMethod *xdomain_method;
972         int ret_marshal_type = MONO_MARSHAL_NONE;
973         int loc_array=0, loc_serialized_data=-1, loc_real_proxy;
974         int loc_old_domainid, loc_domainid, loc_return=0, loc_serialized_exc=0, loc_context;
975         int pos, pos_dispatch, pos_noex;
976         gboolean copy_return = FALSE;
977         WrapperInfo *info;
978
979         g_assert (method);
980         
981         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)
982                 return method;
983
984         /* we cant remote methods without this pointer */
985         if (!mono_method_signature (method)->hasthis)
986                 return method;
987
988         mono_remoting_marshal_init ();
989
990         if (!mono_marshal_supports_fast_xdomain (method))
991                 return mono_marshal_get_remoting_invoke (method);
992         
993         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE)))
994                 return res;
995         
996         sig = mono_signature_no_pinvoke (method);
997
998         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE);
999         mb->method->save_lmf = 1;
1000
1001         /* Count the number of parameters that need to be serialized */
1002
1003         marshal_types = (int *)alloca (sizeof (int) * sig->param_count);
1004         complex_count = complex_out_count = 0;
1005         for (i = 0; i < sig->param_count; i++) {
1006                 MonoType *ptype = sig->params[i];
1007                 int mt = mono_get_xdomain_marshal_type (ptype);
1008                 
1009                 /* If the [Out] attribute is applied to a parameter that can be internally copied,
1010                  * the copy will be made by reusing the original object instance
1011                  */
1012                 if ((ptype->attrs & PARAM_ATTRIBUTE_OUT) != 0 && mt == MONO_MARSHAL_COPY && !ptype->byref)
1013                         mt = MONO_MARSHAL_COPY_OUT;
1014                 else if (mt == MONO_MARSHAL_SERIALIZE) {
1015                         complex_count++;
1016                         if (ptype->byref) complex_out_count++;
1017                 }
1018                 marshal_types [i] = mt;
1019         }
1020
1021         if (sig->ret->type != MONO_TYPE_VOID) {
1022                 ret_marshal_type = mono_get_xdomain_marshal_type (sig->ret);
1023                 ret_class = mono_class_from_mono_type (sig->ret);
1024                 copy_return = ret_marshal_type != MONO_MARSHAL_SERIALIZE;
1025         }
1026         
1027         /* Locals */
1028
1029 #ifndef DISABLE_JIT
1030         if (complex_count > 0)
1031                 loc_array = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1032         loc_serialized_data = mono_mb_add_local (mb, &byte_array_class->byval_arg);
1033         loc_real_proxy = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1034         if (copy_return)
1035                 loc_return = mono_mb_add_local (mb, sig->ret);
1036         loc_old_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
1037         loc_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
1038         loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg);
1039         loc_context = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1040
1041         /* Save thread domain data */
1042
1043         mono_mb_emit_icall (mb, mono_context_get_icall);
1044         mono_mb_emit_byte (mb, CEE_DUP);
1045         mono_mb_emit_stloc (mb, loc_context);
1046
1047         /* If the thread is not running in the default context, it needs to go
1048          * through the whole remoting sink, since the context is going to change
1049          */
1050         mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL);
1051         pos = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1052         
1053         /* Another case in which the fast path can't be used: when the target domain
1054          * has a different image for the same assembly.
1055          */
1056
1057         /* Get the target domain id */
1058
1059         mono_mb_emit_ldarg (mb, 0);
1060         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1061         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1062         mono_mb_emit_byte (mb, CEE_DUP);
1063         mono_mb_emit_stloc (mb, loc_real_proxy);
1064
1065         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
1066         mono_mb_emit_byte (mb, CEE_LDIND_I4);
1067         mono_mb_emit_stloc (mb, loc_domainid);
1068
1069         /* Check if the target domain has the same image for the required assembly */
1070
1071         mono_mb_emit_ldloc (mb, loc_domainid);
1072         mono_mb_emit_ptr (mb, method->klass->image);
1073         mono_mb_emit_icall (mb, mono_marshal_check_domain_image);
1074         pos_dispatch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1075
1076         /* Use the whole remoting sink to dispatch this message */
1077
1078         mono_mb_patch_short_branch (mb, pos);
1079
1080         mono_mb_emit_ldarg (mb, 0);
1081         for (i = 0; i < sig->param_count; i++)
1082                 mono_mb_emit_ldarg (mb, i + 1);
1083         
1084         mono_mb_emit_managed_call (mb, mono_marshal_get_remoting_invoke (method), NULL);
1085         mono_mb_emit_byte (mb, CEE_RET);
1086         mono_mb_patch_short_branch (mb, pos_dispatch);
1087
1088         /* Create the array that will hold the parameters to be serialized */
1089
1090         if (complex_count > 0) {
1091                 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 */
1092                 mono_mb_emit_op (mb, CEE_NEWARR, mono_defaults.object_class);
1093         
1094                 j = 0;
1095                 for (i = 0; i < sig->param_count; i++) {
1096                         MonoClass *pclass;
1097                         if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
1098                         pclass = mono_class_from_mono_type (sig->params[i]);
1099                         mono_mb_emit_byte (mb, CEE_DUP);
1100                         mono_mb_emit_icon (mb, j);
1101                         mono_mb_emit_ldarg (mb, i + 1);         /* 0=this */
1102                         if (sig->params[i]->byref) {
1103                                 if (pclass->valuetype)
1104                                         mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
1105                                 else
1106                                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1107                         }
1108                         if (pclass->valuetype)
1109                                 mono_mb_emit_op (mb, CEE_BOX, pclass);
1110                         mono_mb_emit_byte (mb, CEE_STELEM_REF);
1111                         j++;
1112                 }
1113                 mono_mb_emit_stloc (mb, loc_array);
1114
1115                 /* Serialize parameters */
1116         
1117                 mono_mb_emit_ldloc (mb, loc_array);
1118                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
1119                 mono_mb_emit_stloc (mb, loc_serialized_data);
1120         } else {
1121                 mono_mb_emit_byte (mb, CEE_LDNULL);
1122                 mono_mb_emit_managed_call (mb, method_rs_serialize, NULL);
1123                 mono_mb_emit_stloc (mb, loc_serialized_data);
1124         }
1125
1126         /* switch domain */
1127
1128         mono_mb_emit_ldloc (mb, loc_domainid);
1129         mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1130         mono_marshal_emit_switch_domain (mb);
1131         mono_mb_emit_stloc (mb, loc_old_domainid);
1132
1133         /* Load the arguments */
1134         
1135         mono_mb_emit_ldloc (mb, loc_real_proxy);
1136         mono_mb_emit_ldloc_addr (mb, loc_serialized_data);
1137         mono_mb_emit_ldloc_addr (mb, loc_serialized_exc);
1138
1139         copy_locals_base = mb->locals;
1140         for (i = 0; i < sig->param_count; i++) {
1141                 switch (marshal_types [i]) {
1142                 case MONO_MARSHAL_SERIALIZE:
1143                         continue;
1144                 case MONO_MARSHAL_COPY: {
1145                         mono_mb_emit_ldarg (mb, i+1);
1146                         if (sig->params [i]->byref) {
1147                                 /* make a local copy of the byref parameter. The real parameter
1148                                  * will be updated after the xdomain call
1149                                  */
1150                                 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
1151                                 int copy_local = mono_mb_add_local (mb, &(pclass->byval_arg));
1152                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1153                                 mono_mb_emit_stloc (mb, copy_local);
1154                                 mono_mb_emit_ldloc_addr (mb, copy_local);
1155                         }
1156                         break;
1157                 }
1158                 case MONO_MARSHAL_COPY_OUT:
1159                 case MONO_MARSHAL_NONE:
1160                         mono_mb_emit_ldarg (mb, i+1);
1161                         break;
1162                 }
1163         }
1164
1165         /* Make the call to the invoke wrapper in the target domain */
1166
1167         xdomain_method = mono_marshal_get_xappdomain_dispatch (method, marshal_types, complex_count, complex_out_count, ret_marshal_type);
1168         mono_marshal_emit_load_domain_method (mb, xdomain_method);
1169         mono_mb_emit_calli (mb, mono_method_signature (xdomain_method));
1170
1171         if (copy_return)
1172                 mono_mb_emit_stloc (mb, loc_return);
1173
1174         /* Switch domain */
1175
1176         mono_mb_emit_ldloc (mb, loc_old_domainid);
1177         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1178         mono_marshal_emit_switch_domain (mb);
1179         mono_mb_emit_byte (mb, CEE_POP);
1180         
1181         /* Restore thread domain data */
1182         
1183         mono_mb_emit_ldloc (mb, loc_context);
1184         mono_mb_emit_icall (mb, mono_context_set_icall);
1185         
1186         /* if (loc_serialized_exc != null) ... */
1187
1188         mono_mb_emit_ldloc (mb, loc_serialized_exc);
1189         pos_noex = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1190
1191         mono_mb_emit_ldloc (mb, loc_serialized_exc);
1192         mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
1193         mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
1194         mono_mb_emit_op (mb, CEE_CASTCLASS, mono_defaults.exception_class);
1195         mono_mb_emit_managed_call (mb, method_exc_fixexc, NULL);
1196         mono_mb_emit_byte (mb, CEE_THROW);
1197         mono_mb_patch_short_branch (mb, pos_noex);
1198
1199         /* copy back non-serialized output parameters */
1200
1201         j = 0;
1202         for (i = 0; i < sig->param_count; i++) {
1203                 if (!sig->params [i]->byref || marshal_types [i] != MONO_MARSHAL_COPY) continue;
1204                 mono_mb_emit_ldarg (mb, i + 1);
1205                 mono_mb_emit_ldloc (mb, copy_locals_base + (j++));
1206                 mono_marshal_emit_xdomain_copy_value (mb, mono_class_from_mono_type (sig->params [i]));
1207                 mono_mb_emit_byte (mb, CEE_STIND_REF);
1208         }
1209
1210         /* Deserialize out parameters */
1211
1212         if (complex_out_count > 0) {
1213                 mono_mb_emit_ldloc (mb, loc_serialized_data);
1214                 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
1215                 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
1216                 mono_mb_emit_stloc (mb, loc_array);
1217         
1218                 /* Copy back output parameters and return type */
1219                 
1220                 j = 0;
1221                 for (i = 0; i < sig->param_count; i++) {
1222                         if (marshal_types [i] != MONO_MARSHAL_SERIALIZE) continue;
1223                         if (sig->params[i]->byref) {
1224                                 MonoClass *pclass = mono_class_from_mono_type (sig->params [i]);
1225                                 mono_mb_emit_ldarg (mb, i + 1);
1226                                 mono_mb_emit_ldloc (mb, loc_array);
1227                                 mono_mb_emit_icon (mb, j);
1228                                 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
1229                                 if (pclass->valuetype) {
1230                                         mono_mb_emit_op (mb, CEE_UNBOX, pclass);
1231                                         mono_mb_emit_op (mb, CEE_LDOBJ, pclass);
1232                                         mono_mb_emit_op (mb, CEE_STOBJ, pclass);
1233                                 } else {
1234                                         if (pclass != mono_defaults.object_class)
1235                                                 mono_mb_emit_op (mb, CEE_CASTCLASS, pclass);
1236                                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1237                                 }
1238                         }
1239                         j++;
1240                 }
1241         
1242                 if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
1243                         mono_mb_emit_ldloc (mb, loc_array);
1244                         mono_mb_emit_icon (mb, complex_count);
1245                         mono_mb_emit_byte (mb, CEE_LDELEM_REF);
1246                         if (ret_class->valuetype) {
1247                                 mono_mb_emit_op (mb, CEE_UNBOX, ret_class);
1248                                 mono_mb_emit_op (mb, CEE_LDOBJ, ret_class);
1249                         }
1250                 }
1251         } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) {
1252                 mono_mb_emit_ldloc (mb, loc_serialized_data);
1253                 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
1254                 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
1255                 if (ret_class->valuetype) {
1256                         mono_mb_emit_op (mb, CEE_UNBOX, ret_class);
1257                         mono_mb_emit_op (mb, CEE_LDOBJ, ret_class);
1258                 } else if (ret_class != mono_defaults.object_class) {
1259                         mono_mb_emit_op (mb, CEE_CASTCLASS, ret_class);
1260                 }
1261         } else {
1262                 mono_mb_emit_ldloc (mb, loc_serialized_data);
1263                 mono_mb_emit_byte (mb, CEE_DUP);
1264                 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1265                 mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
1266         
1267                 mono_mb_patch_short_branch (mb, pos);
1268                 mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);
1269                 mono_mb_emit_byte (mb, CEE_POP);
1270         }
1271
1272         if (copy_return) {
1273                 mono_mb_emit_ldloc (mb, loc_return);
1274                 if (ret_marshal_type == MONO_MARSHAL_COPY)
1275                         mono_marshal_emit_xdomain_copy_value (mb, ret_class);
1276         }
1277
1278         mono_mb_emit_byte (mb, CEE_RET);
1279 #endif /* DISABLE_JIT */
1280
1281         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1282         info->d.remoting.method = method;
1283         res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16, info);
1284         mono_mb_free (mb);
1285
1286         return res;
1287 }
1288
1289 /**
1290  * mono_marshal_get_remoting_invoke_for_target:
1291  */
1292 MonoMethod *
1293 mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTarget target_type)
1294 {
1295         if (target_type == MONO_REMOTING_TARGET_APPDOMAIN) {
1296                 return mono_marshal_get_xappdomain_invoke (method);
1297         } else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) {
1298 #ifndef DISABLE_COM
1299                 return mono_cominterop_get_invoke (method);
1300 #else
1301                 g_assert_not_reached ();
1302 #endif
1303         } else {
1304                 return mono_marshal_get_remoting_invoke (method);
1305         }
1306         /* Not erached */
1307         return NULL;
1308 }
1309
1310 G_GNUC_UNUSED static gpointer
1311 mono_marshal_load_remoting_wrapper (MonoRealProxy *rp, MonoMethod *method)
1312 {
1313         MonoError error;
1314         MonoMethod *marshal_method = NULL;
1315         if (rp->target_domain_id != -1)
1316                 marshal_method = mono_marshal_get_xappdomain_invoke (method);
1317         else
1318                 marshal_method = mono_marshal_get_remoting_invoke (method);
1319         gpointer compiled_ptr = mono_compile_method_checked (marshal_method, &error);
1320         mono_error_assert_ok (&error);
1321         return compiled_ptr;
1322 }
1323
1324 /**
1325  * mono_marshal_get_remoting_invoke_with_check:
1326  */
1327 MonoMethod *
1328 mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
1329 {
1330         MonoMethodSignature *sig;
1331         MonoMethodBuilder *mb;
1332         MonoMethod *res, *native;
1333         WrapperInfo *info;
1334         int i, pos, pos_rem;
1335
1336         g_assert (method);
1337
1338         if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
1339                 return method;
1340
1341         /* we cant remote methods without this pointer */
1342         g_assert (mono_method_signature (method)->hasthis);
1343
1344         if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
1345                 return res;
1346
1347         sig = mono_signature_no_pinvoke (method);
1348         
1349         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
1350
1351 #ifndef DISABLE_JIT
1352         for (i = 0; i <= sig->param_count; i++)
1353                 mono_mb_emit_ldarg (mb, i);
1354         
1355         mono_mb_emit_ldarg (mb, 0);
1356         pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
1357
1358         if (mono_marshal_supports_fast_xdomain (method)) {
1359                 mono_mb_emit_ldarg (mb, 0);
1360                 pos_rem = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
1361                 
1362                 /* wrapper for cross app domain calls */
1363                 native = mono_marshal_get_xappdomain_invoke (method);
1364                 mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
1365                 mono_mb_emit_byte (mb, CEE_RET);
1366                 
1367                 mono_mb_patch_branch (mb, pos_rem);
1368         }
1369         /* wrapper for normal remote calls */
1370         native = mono_marshal_get_remoting_invoke (method);
1371         mono_mb_emit_managed_call (mb, native, mono_method_signature (native));
1372         mono_mb_emit_byte (mb, CEE_RET);
1373
1374         /* not a proxy */
1375         mono_mb_patch_branch (mb, pos);
1376         mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
1377         mono_mb_emit_byte (mb, CEE_RET);
1378 #endif
1379
1380         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1381         info->d.remoting.method = method;
1382         res = mono_remoting_mb_create_and_cache (method, mb, sig, sig->param_count + 16, info);
1383         mono_mb_free (mb);
1384
1385         return res;
1386 }
1387
1388 /**
1389  * mono_marshal_get_ldfld_wrapper:
1390  * \param type the type of the field
1391  *
1392  * This method generates a function which can be use to load a field with type
1393  * \p type from an object. The generated function has the following signature:
1394  *
1395  * <code><i>type</i> ldfld_wrapper (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, int offset)</code>
1396  */
1397 MonoMethod *
1398 mono_marshal_get_ldfld_wrapper (MonoType *type)
1399 {
1400         MonoMethodSignature *sig;
1401         MonoMethodBuilder *mb;
1402         MonoMethod *res;
1403         MonoClass *klass;
1404         GHashTable *cache;
1405         WrapperInfo *info;
1406         char *name;
1407         int t, pos0, pos1 = 0;
1408         static MonoMethod* tp_load = NULL;
1409
1410         type = mono_type_get_underlying_type (type);
1411
1412         t = type->type;
1413
1414         if (!type->byref) {
1415                 if (type->type == MONO_TYPE_SZARRAY) {
1416                         klass = mono_defaults.array_class;
1417                 } else if (type->type == MONO_TYPE_VALUETYPE) {
1418                         klass = type->data.klass;
1419                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
1420                         klass = mono_defaults.object_class;
1421                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
1422                         klass = mono_defaults.int_class;
1423                 } else if (t == MONO_TYPE_GENERICINST) {
1424                         if (mono_type_generic_inst_is_valuetype (type))
1425                                 klass = mono_class_from_mono_type (type);
1426                         else
1427                                 klass = mono_defaults.object_class;
1428                 } else {
1429                         klass = mono_class_from_mono_type (type);                       
1430                 }
1431         } else {
1432                 klass = mono_defaults.int_class;
1433         }
1434
1435         cache = get_cache (&klass->image->ldfld_wrapper_cache, mono_aligned_addr_hash, NULL);
1436         if ((res = mono_marshal_find_in_cache (cache, klass)))
1437                 return res;
1438
1439 #ifndef DISABLE_REMOTING
1440         if (!tp_load) {
1441                 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
1442                 g_assert (tp_load != NULL);
1443         }
1444 #endif
1445
1446         /* we add the %p pointer value of klass because class names are not unique */
1447         name = g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); 
1448         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
1449         g_free (name);
1450
1451         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
1452         sig->params [0] = &mono_defaults.object_class->byval_arg;
1453         sig->params [1] = &mono_defaults.int_class->byval_arg;
1454         sig->params [2] = &mono_defaults.int_class->byval_arg;
1455         sig->params [3] = &mono_defaults.int_class->byval_arg;
1456         sig->ret = &klass->byval_arg;
1457
1458 #ifndef DISABLE_JIT
1459         mono_mb_emit_ldarg (mb, 0);
1460         pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
1461
1462 #ifndef DISABLE_REMOTING
1463         mono_mb_emit_ldarg (mb, 0);
1464         mono_mb_emit_ldarg (mb, 1);
1465         mono_mb_emit_ldarg (mb, 2);
1466
1467         mono_mb_emit_managed_call (mb, tp_load, NULL);
1468
1469         /*
1470         csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
1471         csig->params [0] = &mono_defaults.object_class->byval_arg;
1472         csig->params [1] = &mono_defaults.int_class->byval_arg;
1473         csig->params [2] = &mono_defaults.int_class->byval_arg;
1474         csig->ret = &klass->this_arg;
1475         csig->pinvoke = 1;
1476
1477         mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
1478         mono_marshal_emit_thread_interrupt_checkpoint (mb);
1479         */
1480
1481         if (klass->valuetype) {
1482                 mono_mb_emit_op (mb, CEE_UNBOX, klass);
1483                 pos1 = mono_mb_emit_branch (mb, CEE_BR);
1484         } else {
1485                 mono_mb_emit_byte (mb, CEE_RET);
1486         }
1487 #endif
1488
1489         mono_mb_patch_branch (mb, pos0);
1490
1491         mono_mb_emit_ldarg (mb, 0);
1492         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1493         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1494         mono_mb_emit_ldarg (mb, 3);
1495         mono_mb_emit_byte (mb, CEE_ADD);
1496
1497         if (klass->valuetype)
1498                 mono_mb_patch_branch (mb, pos1);
1499
1500         switch (t) {
1501         case MONO_TYPE_I1:
1502         case MONO_TYPE_U1:
1503         case MONO_TYPE_BOOLEAN:
1504         case MONO_TYPE_CHAR:
1505         case MONO_TYPE_I2:
1506         case MONO_TYPE_U2:
1507         case MONO_TYPE_I4:
1508         case MONO_TYPE_U4:
1509         case MONO_TYPE_I8:
1510         case MONO_TYPE_U8:
1511         case MONO_TYPE_R4:
1512         case MONO_TYPE_R8:
1513         case MONO_TYPE_ARRAY:
1514         case MONO_TYPE_SZARRAY:
1515         case MONO_TYPE_OBJECT:
1516         case MONO_TYPE_CLASS:
1517         case MONO_TYPE_STRING:
1518         case MONO_TYPE_I:
1519         case MONO_TYPE_U:
1520         case MONO_TYPE_PTR:
1521         case MONO_TYPE_FNPTR:
1522                 mono_mb_emit_byte (mb, mono_type_to_ldind (type));
1523                 break;
1524         case MONO_TYPE_VALUETYPE:
1525                 g_assert (!klass->enumtype);
1526                 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
1527                 break;
1528         case MONO_TYPE_GENERICINST:
1529                 if (mono_type_generic_inst_is_valuetype (type)) {
1530                         mono_mb_emit_op (mb, CEE_LDOBJ, klass);
1531                 } else {
1532                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1533                 }
1534                 break;
1535         case MONO_TYPE_VAR:
1536         case MONO_TYPE_MVAR:
1537                 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
1538                 break;
1539         default:
1540                 g_warning ("type %x not implemented", type->type);
1541                 g_assert_not_reached ();
1542         }
1543
1544         mono_mb_emit_byte (mb, CEE_RET);
1545 #endif /* DISABLE_JIT */
1546
1547         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1548         info->d.proxy.klass = klass;
1549         res = mono_mb_create_and_cache_full (cache, klass,
1550                                                                                  mb, sig, sig->param_count + 16, info, NULL);
1551         mono_mb_free (mb);
1552         
1553         return res;
1554 }
1555
1556 /*
1557  * mono_marshal_get_ldflda_wrapper:
1558  * @type: the type of the field
1559  *
1560  * This method generates a function which can be used to load a field address
1561  * from an object. The generated function has the following signature:
1562  * gpointer ldflda_wrapper (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, int offset);
1563  */
1564 MonoMethod *
1565 mono_marshal_get_ldflda_wrapper (MonoType *type)
1566 {
1567         MonoMethodSignature *sig;
1568         MonoMethodBuilder *mb;
1569         MonoMethod *res;
1570         MonoClass *klass;
1571         GHashTable *cache;
1572         WrapperInfo *info;
1573         char *name;
1574         int t, pos0, pos1, pos2, pos3;
1575
1576         type = mono_type_get_underlying_type (type);
1577         t = type->type;
1578
1579         if (!type->byref) {
1580                 if (type->type == MONO_TYPE_SZARRAY) {
1581                         klass = mono_defaults.array_class;
1582                 } else if (type->type == MONO_TYPE_VALUETYPE) {
1583                         klass = type->data.klass;
1584                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) { 
1585                         klass = mono_defaults.object_class;
1586                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
1587                         klass = mono_defaults.int_class;
1588                 } else if (t == MONO_TYPE_GENERICINST) {
1589                         if (mono_type_generic_inst_is_valuetype (type))
1590                                 klass = mono_class_from_mono_type (type);
1591                         else
1592                                 klass = mono_defaults.object_class;
1593                 } else {
1594                         klass = mono_class_from_mono_type (type);                       
1595                 }
1596         } else {
1597                 klass = mono_defaults.int_class;
1598         }
1599
1600         cache = get_cache (&klass->image->ldflda_wrapper_cache, mono_aligned_addr_hash, NULL);
1601         if ((res = mono_marshal_find_in_cache (cache, klass)))
1602                 return res;
1603
1604         /* we add the %p pointer value of klass because class names are not unique */
1605         name = g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); 
1606         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLDA);
1607         g_free (name);
1608
1609         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
1610         sig->params [0] = &mono_defaults.object_class->byval_arg;
1611         sig->params [1] = &mono_defaults.int_class->byval_arg;
1612         sig->params [2] = &mono_defaults.int_class->byval_arg;
1613         sig->params [3] = &mono_defaults.int_class->byval_arg;
1614         sig->ret = &mono_defaults.int_class->byval_arg;
1615
1616 #ifndef DISABLE_JIT
1617         /* if typeof (this) != transparent_proxy goto pos0 */
1618         mono_mb_emit_ldarg (mb, 0);
1619         pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
1620
1621         /* if same_appdomain goto pos1 */
1622         mono_mb_emit_ldarg (mb, 0);
1623         pos1 = mono_mb_emit_xdomain_check (mb, CEE_BEQ);
1624
1625         mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain.");
1626
1627         /* same app domain */
1628         mono_mb_patch_branch (mb, pos1);
1629
1630         /* if typeof (this) != contextbound goto pos2 */
1631         mono_mb_emit_ldarg (mb, 0);
1632         pos2 = mono_mb_emit_contextbound_check (mb, CEE_BEQ);
1633
1634         /* if this->rp->context == mono_context_get goto pos3 */
1635         mono_mb_emit_ldarg (mb, 0);
1636         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1637         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1638         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoRealProxy, context));
1639         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1640         mono_mb_emit_icall (mb, mono_context_get_icall);
1641         pos3 = mono_mb_emit_branch (mb, CEE_BEQ);
1642
1643         mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another context.");
1644
1645         mono_mb_patch_branch (mb, pos2);
1646         mono_mb_patch_branch (mb, pos3);
1647
1648         /* return the address of the field from this->rp->unwrapped_server */
1649         mono_mb_emit_ldarg (mb, 0);
1650         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1651         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1652         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoRealProxy, unwrapped_server));
1653         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1654         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1655         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1656         mono_mb_emit_ldarg (mb, 3);
1657         mono_mb_emit_byte (mb, CEE_ADD);
1658         mono_mb_emit_byte (mb, CEE_RET);
1659
1660         /* not a proxy: return the address of the field directly */
1661         mono_mb_patch_branch (mb, pos0);
1662
1663         mono_mb_emit_ldarg (mb, 0);
1664         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1665         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1666         mono_mb_emit_ldarg (mb, 3);
1667         mono_mb_emit_byte (mb, CEE_ADD);
1668
1669         mono_mb_emit_byte (mb, CEE_RET);
1670 #endif
1671
1672         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1673         info->d.proxy.klass = klass;
1674         res = mono_mb_create_and_cache_full (cache, klass,
1675                                                                                  mb, sig, sig->param_count + 16,
1676                                                                                  info, NULL);
1677         mono_mb_free (mb);
1678         
1679         return res;
1680 }
1681
1682
1683 /**
1684  * mono_marshal_get_stfld_wrapper:
1685  * \param type the type of the field
1686  *
1687  * This method generates a function which can be use to store a field with type
1688  * \p type. The generated function has the following signature:
1689  *
1690  * <code>void stfld_wrapper (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, int offset, <i>type</i> val)</code>
1691  */
1692 MonoMethod *
1693 mono_marshal_get_stfld_wrapper (MonoType *type)
1694 {
1695         MonoMethodSignature *sig;
1696         MonoMethodBuilder *mb;
1697         MonoMethod *res;
1698         MonoClass *klass;
1699         GHashTable *cache;
1700         WrapperInfo *info;
1701         char *name;
1702         int t, pos;
1703         static MonoMethod *tp_store = NULL;
1704
1705         type = mono_type_get_underlying_type (type);
1706         t = type->type;
1707
1708         if (!type->byref) {
1709                 if (type->type == MONO_TYPE_SZARRAY) {
1710                         klass = mono_defaults.array_class;
1711                 } else if (type->type == MONO_TYPE_VALUETYPE) {
1712                         klass = type->data.klass;
1713                 } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING) {
1714                         klass = mono_defaults.object_class;
1715                 } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
1716                         klass = mono_defaults.int_class;
1717                 } else if (t == MONO_TYPE_GENERICINST) {
1718                         if (mono_type_generic_inst_is_valuetype (type))
1719                                 klass = mono_class_from_mono_type (type);
1720                         else
1721                                 klass = mono_defaults.object_class;
1722                 } else {
1723                         klass = mono_class_from_mono_type (type);                       
1724                 }
1725         } else {
1726                 klass = mono_defaults.int_class;
1727         }
1728
1729         cache = get_cache (&klass->image->stfld_wrapper_cache, mono_aligned_addr_hash, NULL);
1730         if ((res = mono_marshal_find_in_cache (cache, klass)))
1731                 return res;
1732
1733 #ifndef DISABLE_REMOTING
1734         if (!tp_store) {
1735                 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
1736                 g_assert (tp_store != NULL);
1737         }
1738 #endif
1739
1740         /* we add the %p pointer value of klass because class names are not unique */
1741         name = g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass, klass->name_space, klass->name); 
1742         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
1743         g_free (name);
1744
1745         sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
1746         sig->params [0] = &mono_defaults.object_class->byval_arg;
1747         sig->params [1] = &mono_defaults.int_class->byval_arg;
1748         sig->params [2] = &mono_defaults.int_class->byval_arg;
1749         sig->params [3] = &mono_defaults.int_class->byval_arg;
1750         sig->params [4] = &klass->byval_arg;
1751         sig->ret = &mono_defaults.void_class->byval_arg;
1752
1753 #ifndef DISABLE_JIT
1754         mono_mb_emit_ldarg (mb, 0);
1755         pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
1756
1757 #ifndef DISABLE_REMOTING
1758         mono_mb_emit_ldarg (mb, 0);
1759         mono_mb_emit_ldarg (mb, 1);
1760         mono_mb_emit_ldarg (mb, 2);
1761         mono_mb_emit_ldarg (mb, 4);
1762         if (klass->valuetype)
1763                 mono_mb_emit_op (mb, CEE_BOX, klass);
1764
1765         mono_mb_emit_managed_call (mb, tp_store, NULL);
1766
1767         mono_mb_emit_byte (mb, CEE_RET);
1768 #endif
1769
1770         mono_mb_patch_branch (mb, pos);
1771
1772         mono_mb_emit_ldarg (mb, 0);
1773         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1774         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
1775         mono_mb_emit_ldarg (mb, 3);
1776         mono_mb_emit_byte (mb, CEE_ADD);
1777         mono_mb_emit_ldarg (mb, 4);
1778
1779         switch (t) {
1780         case MONO_TYPE_I1:
1781         case MONO_TYPE_U1:
1782         case MONO_TYPE_BOOLEAN:
1783         case MONO_TYPE_CHAR:
1784         case MONO_TYPE_I2:
1785         case MONO_TYPE_U2:
1786         case MONO_TYPE_I4:
1787         case MONO_TYPE_U4:
1788         case MONO_TYPE_I8:
1789         case MONO_TYPE_U8:
1790         case MONO_TYPE_R4:
1791         case MONO_TYPE_R8:
1792         case MONO_TYPE_ARRAY:
1793         case MONO_TYPE_SZARRAY:
1794         case MONO_TYPE_OBJECT:
1795         case MONO_TYPE_CLASS:
1796         case MONO_TYPE_STRING:
1797         case MONO_TYPE_I:
1798         case MONO_TYPE_U:
1799         case MONO_TYPE_PTR:
1800         case MONO_TYPE_FNPTR:
1801                 mono_mb_emit_byte (mb, mono_type_to_stind (type));
1802                 break;
1803         case MONO_TYPE_VALUETYPE:
1804                 g_assert (!klass->enumtype);
1805                 mono_mb_emit_op (mb, CEE_STOBJ, klass);
1806                 break;
1807         case MONO_TYPE_GENERICINST:
1808         case MONO_TYPE_VAR:
1809         case MONO_TYPE_MVAR:
1810                 mono_mb_emit_op (mb, CEE_STOBJ, klass);
1811                 break;
1812         default:
1813                 g_warning ("type %x not implemented", type->type);
1814                 g_assert_not_reached ();
1815         }
1816
1817         mono_mb_emit_byte (mb, CEE_RET);
1818 #endif
1819
1820         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1821         info->d.proxy.klass = klass;
1822         res = mono_mb_create_and_cache_full (cache, klass,
1823                                                                                  mb, sig, sig->param_count + 16,
1824                                                                                  info, NULL);
1825         mono_mb_free (mb);
1826         
1827         return res;
1828 }
1829
1830 /**
1831  * mono_marshal_get_proxy_cancast:
1832  */
1833 MonoMethod *
1834 mono_marshal_get_proxy_cancast (MonoClass *klass)
1835 {
1836         static MonoMethodSignature *isint_sig = NULL;
1837         GHashTable *cache;
1838         MonoMethod *res;
1839         WrapperInfo *info;
1840         int pos_failed, pos_end;
1841         char *name, *klass_name;
1842         MonoMethod *can_cast_to;
1843         MonoMethodDesc *desc;
1844         MonoMethodBuilder *mb;
1845
1846         cache = get_cache (&klass->image->proxy_isinst_cache, mono_aligned_addr_hash, NULL);
1847         if ((res = mono_marshal_find_in_cache (cache, klass)))
1848                 return res;
1849
1850         if (!isint_sig) {
1851                 isint_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
1852                 isint_sig->params [0] = &mono_defaults.object_class->byval_arg;
1853                 isint_sig->ret = &mono_defaults.object_class->byval_arg;
1854                 isint_sig->pinvoke = 0;
1855         }
1856
1857         klass_name = mono_type_full_name (&klass->byval_arg);
1858         name = g_strdup_printf ("__proxy_isinst_wrapper_%s", klass_name); 
1859         mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_PROXY_ISINST);
1860         g_free (klass_name);
1861         g_free (name);
1862         
1863         mb->method->save_lmf = 1;
1864
1865 #ifndef DISABLE_JIT
1866         /* get the real proxy from the transparent proxy*/
1867         mono_mb_emit_ldarg (mb, 0);
1868         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1869         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1870         
1871         /* get the reflection type from the type handle */
1872         mono_mb_emit_ptr (mb, &klass->byval_arg);
1873         mono_mb_emit_icall (mb, type_from_handle);
1874         
1875         mono_mb_emit_ldarg (mb, 0);
1876         
1877         /* make the call to CanCastTo (type, ob) */
1878         desc = mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE);
1879         can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class);
1880         g_assert (can_cast_to);
1881         mono_method_desc_free (desc);
1882         mono_mb_emit_op (mb, CEE_CALLVIRT, can_cast_to);
1883         
1884         pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
1885
1886         /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
1887         mono_mb_emit_ptr (mb, &klass->byval_arg);
1888         mono_mb_emit_icall (mb, type_from_handle);
1889         mono_mb_emit_ldarg (mb, 0);
1890         
1891         mono_mb_emit_icall (mb, mono_upgrade_remote_class_wrapper);
1892         mono_marshal_emit_thread_interrupt_checkpoint (mb);
1893         
1894         mono_mb_emit_ldarg (mb, 0);
1895         pos_end = mono_mb_emit_branch (mb, CEE_BR);
1896         
1897         /* fail */
1898         
1899         mono_mb_patch_branch (mb, pos_failed);
1900         mono_mb_emit_byte (mb, CEE_LDNULL);
1901         
1902         /* the end */
1903         
1904         mono_mb_patch_branch (mb, pos_end);
1905         mono_mb_emit_byte (mb, CEE_RET);
1906 #endif
1907
1908         info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1909         info->d.proxy.klass = klass;
1910         res = mono_mb_create_and_cache_full (cache, klass, mb, isint_sig, isint_sig->param_count + 16, info, NULL);
1911         mono_mb_free (mb);
1912
1913         return res;
1914 }
1915
1916 void
1917 mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype_raw, MonoTransparentProxy *tproxy_raw)
1918 {
1919         ICALL_ENTRY ();
1920         MONO_HANDLE_DCL (MonoReflectionType, rtype);
1921         MONO_HANDLE_DCL (MonoTransparentProxy, tproxy);
1922         MonoDomain *domain = MONO_HANDLE_DOMAIN (tproxy);
1923         MonoClass *klass = mono_class_from_mono_type (MONO_HANDLE_GETVAL (rtype, type));
1924         mono_upgrade_remote_class (domain, MONO_HANDLE_CAST (MonoObject, tproxy), klass, &error);
1925         ICALL_RETURN ();
1926 }
1927
1928 #else /* DISABLE_REMOTING */
1929
1930 void
1931 mono_remoting_init (void)
1932 {
1933 }
1934
1935 #endif /* DISABLE_REMOTING */
1936
1937 /* mono_get_xdomain_marshal_type()
1938  * Returns the kind of marshalling that a type needs for cross domain calls.
1939  */
1940 static MonoXDomainMarshalType
1941 mono_get_xdomain_marshal_type (MonoType *t)
1942 {
1943         switch (t->type) {
1944         case MONO_TYPE_VOID:
1945                 g_assert_not_reached ();
1946                 break;
1947         case MONO_TYPE_U1:
1948         case MONO_TYPE_I1:
1949         case MONO_TYPE_BOOLEAN:
1950         case MONO_TYPE_U2:
1951         case MONO_TYPE_I2:
1952         case MONO_TYPE_CHAR:
1953         case MONO_TYPE_U4:
1954         case MONO_TYPE_I4:
1955         case MONO_TYPE_I8:
1956         case MONO_TYPE_U8:
1957         case MONO_TYPE_R4:
1958         case MONO_TYPE_R8:
1959                 return MONO_MARSHAL_NONE;
1960         case MONO_TYPE_STRING:
1961                 return MONO_MARSHAL_COPY;
1962         case MONO_TYPE_ARRAY:
1963         case MONO_TYPE_SZARRAY: {
1964                 MonoClass *elem_class = mono_class_from_mono_type (t)->element_class;
1965                 if (mono_get_xdomain_marshal_type (&(elem_class->byval_arg)) != MONO_MARSHAL_SERIALIZE)
1966                         return MONO_MARSHAL_COPY;
1967                 break;
1968         }
1969         default:
1970                 break;
1971         }
1972         return MONO_MARSHAL_SERIALIZE;
1973 }
1974
1975 /* Replace the given array element by a copy in the current domain */
1976 static gboolean
1977 xdomain_copy_array_element_inplace (MonoArrayHandle arr, int i, MonoError *error)
1978 {
1979         HANDLE_FUNCTION_ENTER ();
1980         error_init (error);
1981         MonoObjectHandle item = MONO_HANDLE_NEW (MonoObject, NULL);
1982         MONO_HANDLE_ARRAY_GETREF (item, arr, i);
1983         
1984         MonoObjectHandle item_copy = mono_marshal_xdomain_copy_value_handle (item, error);
1985         if (!is_ok (error))
1986                 goto leave;
1987         MONO_HANDLE_ARRAY_SETREF (arr, i, item_copy);
1988 leave:
1989         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1990 }
1991
1992 /**
1993  * mono_marshal_xdomain_copy_value_handle:
1994  * \param val The value to copy.
1995  * \param error set on failure.
1996  * Makes a copy of \p val suitable for the current domain.
1997  * On failure returns NULL and sets \p error.
1998  */
1999 MonoObjectHandle
2000 mono_marshal_xdomain_copy_value_handle (MonoObjectHandle val, MonoError *error)
2001 {
2002         error_init (error);
2003         MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
2004         if (MONO_HANDLE_IS_NULL (val))
2005                 goto leave;
2006
2007         MonoDomain *domain = mono_domain_get ();
2008
2009         MonoClass *klass = mono_handle_class (val);
2010
2011         switch (klass->byval_arg.type) {
2012         case MONO_TYPE_VOID:
2013                 g_assert_not_reached ();
2014                 break;
2015         case MONO_TYPE_U1:
2016         case MONO_TYPE_I1:
2017         case MONO_TYPE_BOOLEAN:
2018         case MONO_TYPE_U2:
2019         case MONO_TYPE_I2:
2020         case MONO_TYPE_CHAR:
2021         case MONO_TYPE_U4:
2022         case MONO_TYPE_I4:
2023         case MONO_TYPE_I8:
2024         case MONO_TYPE_U8:
2025         case MONO_TYPE_R4:
2026         case MONO_TYPE_R8: {
2027                 uint32_t gchandle = mono_gchandle_from_handle (val, TRUE);
2028                 MonoObjectHandle res = MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (domain, klass, ((char*)val) + sizeof(MonoObject), error)); /* FIXME use handles in mono_value_box_checked */
2029                 mono_gchandle_free (gchandle);
2030                 if (!is_ok (error))
2031                         goto leave;
2032                 MONO_HANDLE_ASSIGN (result, res);
2033                 break;
2034         }
2035         case MONO_TYPE_STRING: {
2036                 MonoStringHandle str = MONO_HANDLE_CAST (MonoString, val);
2037                 uint32_t gchandle = mono_gchandle_from_handle (val, TRUE);
2038                 MonoStringHandle res = mono_string_new_utf16_handle (domain, mono_string_chars (MONO_HANDLE_RAW (str)), mono_string_handle_length (str), error);
2039                 mono_gchandle_free (gchandle);
2040                 if (!is_ok (error))
2041                         goto leave;
2042                 MONO_HANDLE_ASSIGN (result, res);
2043                 break;
2044         }
2045         case MONO_TYPE_ARRAY:
2046         case MONO_TYPE_SZARRAY: {
2047                 MonoArrayHandle arr = MONO_HANDLE_CAST (MonoArray, val);
2048                 MonoXDomainMarshalType mt = mono_get_xdomain_marshal_type (&klass->element_class->byval_arg);
2049                 if (mt == MONO_MARSHAL_SERIALIZE)
2050                         goto leave;
2051                 MonoArrayHandle acopy = mono_array_clone_in_domain (domain, arr, error);
2052                 if (!is_ok (error))
2053                         goto leave;
2054
2055                 if (mt == MONO_MARSHAL_COPY) {
2056                         int i, len = mono_array_handle_length (acopy);
2057                         for (i = 0; i < len; i++) {
2058                                 if (!xdomain_copy_array_element_inplace (acopy, i, error))
2059                                         goto leave;
2060                         }
2061                 }
2062                 MONO_HANDLE_ASSIGN (result, acopy);
2063                 break;
2064         }
2065         default:
2066                 break;
2067         }
2068
2069 leave:
2070         return result;
2071 }
2072
2073 /* mono_marshal_xdomain_copy_value
2074  * Makes a copy of "val" suitable for the current domain.
2075  */
2076 MonoObject*
2077 mono_marshal_xdomain_copy_value (MonoObject* val_raw, MonoError *error)
2078 {
2079         HANDLE_FUNCTION_ENTER ();
2080         /* FIXME callers of mono_marshal_xdomain_copy_value should use handles */
2081         MONO_HANDLE_DCL (MonoObject, val);
2082         MonoObjectHandle result = mono_marshal_xdomain_copy_value_handle (val, error);
2083         HANDLE_FUNCTION_RETURN_OBJ (result);
2084 }
2085
2086 /* mono_marshal_xdomain_copy_value
2087  * Makes a copy of "val" suitable for the current domain.
2088  */
2089 MonoObject *
2090 ves_icall_mono_marshal_xdomain_copy_value (MonoObject *val)
2091 {
2092         MonoError error;
2093         MonoObject *result = mono_marshal_xdomain_copy_value (val, &error);
2094         mono_error_set_pending_exception (&error);
2095         return result;
2096 }
2097
2098 void
2099 mono_context_set_icall (MonoAppContext *new_context_raw)
2100 {
2101         HANDLE_FUNCTION_ENTER ();
2102         MONO_HANDLE_DCL (MonoAppContext, new_context);
2103         mono_context_set_handle (new_context);
2104         HANDLE_FUNCTION_RETURN ();
2105 }
2106
2107 static MonoAppContext* 
2108 mono_context_get_icall (void)
2109 {
2110         HANDLE_FUNCTION_ENTER ();
2111         MonoAppContextHandle context = mono_context_get_handle ();
2112         HANDLE_FUNCTION_RETURN_OBJ (context);
2113 }