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