2 * marshal.c: Routines for marshaling complex types in P/Invoke methods.
5 * Paolo Molaro (lupus@ximian.com)
7 * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
20 #include "metadata/marshal.h"
21 #include "metadata/method-builder.h"
22 #include "metadata/tabledefs.h"
23 #include "metadata/exception.h"
24 #include "metadata/appdomain.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threadpool.h"
27 #include "mono/metadata/threads.h"
28 #include "mono/metadata/monitor.h"
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/domain-internals.h"
31 #include "mono/metadata/gc-internal.h"
32 #include "mono/metadata/threads-types.h"
33 #include "mono/metadata/string-icalls.h"
34 #include "mono/metadata/attrdefs.h"
35 #include "mono/metadata/gc-internal.h"
36 #include "mono/metadata/cominterop.h"
37 #include "mono/utils/mono-counters.h"
41 /* #define DEBUG_RUNTIME_CODE */
43 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
47 MONO_MARSHAL_NONE
, /* No marshalling needed */
48 MONO_MARSHAL_COPY
, /* Can be copied by value to the new domain */
49 MONO_MARSHAL_COPY_OUT
, /* out parameter that needs to be copied back to the original instance */
50 MONO_MARSHAL_SERIALIZE
/* Value needs to be serialized into the new domain */
51 } MonoXDomainMarshalType
;
54 #include "mono/cil/opcode.def"
59 struct _MonoRemotingMethods
{
61 MonoMethod
*invoke_with_check
;
62 MonoMethod
*xdomain_invoke
;
63 MonoMethod
*xdomain_dispatch
;
66 typedef struct _MonoRemotingMethods MonoRemotingMethods
;
69 * This mutex protects the various marshalling related caches in MonoImage
70 * and a few other data structures static to this file.
71 * Note that when this lock is held it is not possible to take other runtime
72 * locks like the loader lock.
74 #define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
75 #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
76 static CRITICAL_SECTION marshal_mutex
;
77 static gboolean marshal_mutex_initialized
;
79 static guint32 last_error_tls_id
;
81 static guint32 load_type_info_tls_id
;
84 delegate_hash_table_add (MonoDelegate
*d
);
87 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
90 mono_struct_delete_old (MonoClass
*klass
, char *ptr
);
93 mono_marshal_string_to_utf16 (MonoString
*s
);
96 mono_marshal_string_to_utf16_copy (MonoString
*s
);
99 mono_string_to_lpstr (MonoString
*string_obj
);
101 static MonoStringBuilder
*
102 mono_string_utf8_to_builder2 (char *text
);
104 static MonoStringBuilder
*
105 mono_string_utf16_to_builder2 (gunichar2
*text
);
108 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*eltype
, guint32 elnum
);
111 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*eltype
, guint32 elnum
);
114 mono_remoting_wrapper (MonoMethod
*method
, gpointer
*params
);
116 static MonoAsyncResult
*
117 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
);
120 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
);
123 mono_marshal_xdomain_copy_out_value (MonoObject
*src
, MonoObject
*dst
);
126 mono_marshal_set_domain_by_id (gint32 id
, MonoBoolean push
);
129 mono_marshal_check_domain_image (gint32 domain_id
, MonoImage
*image
);
132 mono_upgrade_remote_class_wrapper (MonoReflectionType
*rtype
, MonoTransparentProxy
*tproxy
);
134 static MonoReflectionType
*
135 type_from_handle (MonoType
*handle
);
138 mono_marshal_set_last_error_windows (int error
);
140 static void init_safe_handle (void);
142 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
143 static MonoMethod
*sh_dangerous_add_ref
;
144 static MonoMethod
*sh_dangerous_release
;
150 sh_dangerous_add_ref
= mono_class_get_method_from_name (
151 mono_defaults
.safehandle_class
, "DangerousAddRef", 1);
152 sh_dangerous_release
= mono_class_get_method_from_name (
153 mono_defaults
.safehandle_class
, "DangerousRelease", 0);
157 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
159 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
161 mono_register_jit_icall (func
, name
, sig
, save
);
164 static MonoMethodSignature
*
165 signature_dup (MonoImage
*image
, MonoMethodSignature
*sig
)
167 MonoMethodSignature
*res
;
170 res
= mono_metadata_signature_alloc (image
, sig
->param_count
);
171 sigsize
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
172 memcpy (res
, sig
, sigsize
);
178 mono_signature_no_pinvoke (MonoMethod
*method
)
180 MonoMethodSignature
*sig
= mono_method_signature (method
);
182 sig
= signature_dup (method
->klass
->image
, sig
);
183 sig
->pinvoke
= FALSE
;
190 mono_marshal_init (void)
192 static gboolean module_initialized
= FALSE
;
194 if (!module_initialized
) {
195 module_initialized
= TRUE
;
196 InitializeCriticalSection (&marshal_mutex
);
197 marshal_mutex_initialized
= TRUE
;
198 last_error_tls_id
= TlsAlloc ();
199 load_type_info_tls_id
= TlsAlloc ();
201 register_icall (ves_icall_System_Threading_Thread_ResetAbort
, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE
);
202 register_icall (mono_marshal_string_to_utf16
, "mono_marshal_string_to_utf16", "ptr obj", FALSE
);
203 register_icall (mono_marshal_string_to_utf16_copy
, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE
);
204 register_icall (mono_string_to_utf16
, "mono_string_to_utf16", "ptr obj", FALSE
);
205 register_icall (mono_string_from_utf16
, "mono_string_from_utf16", "obj ptr", FALSE
);
206 register_icall (mono_string_new_wrapper
, "mono_string_new_wrapper", "obj ptr", FALSE
);
207 register_icall (mono_string_to_utf8
, "mono_string_to_utf8", "ptr obj", FALSE
);
208 register_icall (mono_string_to_lpstr
, "mono_string_to_lpstr", "ptr obj", FALSE
);
209 register_icall (mono_string_to_ansibstr
, "mono_string_to_ansibstr", "ptr object", FALSE
);
210 register_icall (mono_string_builder_to_utf8
, "mono_string_builder_to_utf8", "ptr object", FALSE
);
211 register_icall (mono_string_builder_to_utf16
, "mono_string_builder_to_utf16", "ptr object", FALSE
);
212 register_icall (mono_array_to_savearray
, "mono_array_to_savearray", "ptr object", FALSE
);
213 register_icall (mono_array_to_lparray
, "mono_array_to_lparray", "ptr object", FALSE
);
214 register_icall (mono_free_lparray
, "mono_free_lparray", "void object ptr", FALSE
);
215 register_icall (mono_byvalarray_to_array
, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE
);
216 register_icall (mono_array_to_byvalarray
, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE
);
217 register_icall (mono_delegate_to_ftnptr
, "mono_delegate_to_ftnptr", "ptr object", FALSE
);
218 register_icall (mono_ftnptr_to_delegate
, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE
);
219 register_icall (mono_marshal_asany
, "mono_marshal_asany", "ptr object int32 int32", FALSE
);
220 register_icall (mono_marshal_free_asany
, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE
);
221 register_icall (mono_marshal_alloc
, "mono_marshal_alloc", "ptr int32", FALSE
);
222 register_icall (mono_marshal_free
, "mono_marshal_free", "void ptr", FALSE
);
223 register_icall (mono_marshal_set_last_error
, "mono_marshal_set_last_error", "void", FALSE
);
224 register_icall (mono_marshal_set_last_error_windows
, "mono_marshal_set_last_error_windows", "void int32", FALSE
);
225 register_icall (mono_string_utf8_to_builder
, "mono_string_utf8_to_builder", "void ptr ptr", FALSE
);
226 register_icall (mono_string_utf8_to_builder2
, "mono_string_utf8_to_builder2", "object ptr", FALSE
);
227 register_icall (mono_string_utf16_to_builder
, "mono_string_utf16_to_builder", "void ptr ptr", FALSE
);
228 register_icall (mono_string_utf16_to_builder2
, "mono_string_utf16_to_builder2", "object ptr", FALSE
);
229 register_icall (mono_marshal_free_array
, "mono_marshal_free_array", "void ptr int32", FALSE
);
230 register_icall (mono_string_to_byvalstr
, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE
);
231 register_icall (mono_string_to_byvalwstr
, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE
);
232 register_icall (g_free
, "g_free", "void ptr", FALSE
);
233 register_icall (mono_object_isinst
, "mono_object_isinst", "object object ptr", FALSE
);
234 register_icall (mono_struct_delete_old
, "mono_struct_delete_old", "void ptr ptr", FALSE
);
235 register_icall (mono_remoting_wrapper
, "mono_remoting_wrapper", "object ptr ptr", FALSE
);
236 register_icall (mono_delegate_begin_invoke
, "mono_delegate_begin_invoke", "object object ptr", FALSE
);
237 register_icall (mono_delegate_end_invoke
, "mono_delegate_end_invoke", "object object ptr", FALSE
);
238 register_icall (mono_marshal_xdomain_copy_value
, "mono_marshal_xdomain_copy_value", "object object", FALSE
);
239 register_icall (mono_marshal_xdomain_copy_out_value
, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE
);
240 register_icall (mono_marshal_set_domain_by_id
, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE
);
241 register_icall (mono_marshal_check_domain_image
, "mono_marshal_check_domain_image", "int32 int32 ptr", FALSE
);
242 register_icall (mono_compile_method
, "mono_compile_method", "ptr ptr", FALSE
);
243 register_icall (mono_context_get
, "mono_context_get", "object", FALSE
);
244 register_icall (mono_context_set
, "mono_context_set", "void object", FALSE
);
245 register_icall (mono_upgrade_remote_class_wrapper
, "mono_upgrade_remote_class_wrapper", "void object object", FALSE
);
246 register_icall (type_from_handle
, "type_from_handle", "object ptr", FALSE
);
247 register_icall (mono_gc_wbarrier_generic_nostore
, "wb_generic", "void ptr", FALSE
);
248 register_icall (mono_gchandle_get_target
, "mono_gchandle_get_target", "object int32", TRUE
);
250 mono_cominterop_init ();
255 mono_marshal_cleanup (void)
257 mono_cominterop_cleanup ();
259 TlsFree (load_type_info_tls_id
);
260 TlsFree (last_error_tls_id
);
261 DeleteCriticalSection (&marshal_mutex
);
262 marshal_mutex_initialized
= FALSE
;
265 MonoClass
*byte_array_class
;
266 static MonoMethod
*method_rs_serialize
, *method_rs_deserialize
, *method_exc_fixexc
, *method_rs_appdomain_target
;
267 static MonoMethod
*method_set_context
, *method_get_context
;
268 static MonoMethod
*method_set_call_context
, *method_needs_context_sink
, *method_rs_serialize_exc
;
271 mono_remoting_marshal_init (void)
275 static gboolean module_initialized
= FALSE
;
277 if (!module_initialized
) {
278 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting", "RemotingServices");
279 method_rs_serialize
= mono_class_get_method_from_name (klass
, "SerializeCallData", -1);
280 method_rs_deserialize
= mono_class_get_method_from_name (klass
, "DeserializeCallData", -1);
281 method_rs_serialize_exc
= mono_class_get_method_from_name (klass
, "SerializeExceptionData", -1);
283 klass
= mono_defaults
.real_proxy_class
;
284 method_rs_appdomain_target
= mono_class_get_method_from_name (klass
, "GetAppDomainTarget", -1);
286 klass
= mono_defaults
.exception_class
;
287 method_exc_fixexc
= mono_class_get_method_from_name (klass
, "FixRemotingException", -1);
289 klass
= mono_defaults
.thread_class
;
290 method_get_context
= mono_class_get_method_from_name (klass
, "get_CurrentContext", -1);
292 klass
= mono_defaults
.appdomain_class
;
293 method_set_context
= mono_class_get_method_from_name (klass
, "InternalSetContext", -1);
294 byte_array_class
= mono_array_class_get (mono_defaults
.byte_class
, 1);
296 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Messaging", "CallContext");
297 method_set_call_context
= mono_class_get_method_from_name (klass
, "SetCurrentCallContext", -1);
299 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Contexts", "Context");
300 method_needs_context_sink
= mono_class_get_method_from_name (klass
, "get_NeedsContextSink", -1);
302 module_initialized
= TRUE
;
307 mono_delegate_to_ftnptr (MonoDelegate
*delegate
)
309 MonoMethod
*method
, *wrapper
;
311 uint32_t target_handle
= 0;
316 if (delegate
->delegate_trampoline
)
317 return delegate
->delegate_trampoline
;
319 klass
= ((MonoObject
*)delegate
)->vtable
->klass
;
320 g_assert (klass
->delegate
);
322 method
= delegate
->method
;
324 if (mono_method_signature (method
)->pinvoke
) {
325 const char *exc_class
, *exc_arg
;
328 ftnptr
= mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
330 g_assert (exc_class
);
331 mono_raise_exception (mono_exception_from_name_msg (mono_defaults
.corlib
, "System", exc_class
, exc_arg
));
336 if (delegate
->target
) {
337 /* Produce a location which can be embedded in JITted code */
338 target_handle
= mono_gchandle_new_weakref (delegate
->target
, FALSE
);
341 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, target_handle
);
343 delegate
->delegate_trampoline
= mono_compile_method (wrapper
);
345 // Add the delegate to the delegate hash table
346 delegate_hash_table_add (delegate
);
348 /* when the object is collected, collect the dynamic method, too */
349 mono_object_register_finalizer ((MonoObject
*)delegate
);
351 return delegate
->delegate_trampoline
;
355 * this hash table maps from a delegate trampoline object to a weak reference
356 * of the delegate. As an optimizations with a non-moving GC we store the
357 * object pointer itself, otherwise we use a GC handle.
359 static GHashTable
*delegate_hash_table
;
362 delegate_hash_table_new (void) {
363 return g_hash_table_new (NULL
, NULL
);
367 delegate_hash_table_remove (MonoDelegate
*d
)
369 #ifdef HAVE_MOVING_COLLECTOR
372 mono_marshal_lock ();
373 if (delegate_hash_table
== NULL
)
374 delegate_hash_table
= delegate_hash_table_new ();
375 #ifdef HAVE_MOVING_COLLECTOR
376 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
378 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
379 mono_marshal_unlock ();
380 #ifdef HAVE_MOVING_COLLECTOR
381 mono_gchandle_free (gchandle
);
386 delegate_hash_table_add (MonoDelegate
*d
)
388 #ifdef HAVE_MOVING_COLLECTOR
389 guint32 gchandle
= mono_gchandle_new_weakref ((MonoObject
*)d
, FALSE
);
390 guint32 old_gchandle
;
392 mono_marshal_lock ();
393 if (delegate_hash_table
== NULL
)
394 delegate_hash_table
= delegate_hash_table_new ();
395 #ifdef HAVE_MOVING_COLLECTOR
396 old_gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
397 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
399 mono_gchandle_free (old_gchandle
);
401 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, d
);
403 mono_marshal_unlock ();
407 mono_ftnptr_to_delegate (MonoClass
*klass
, gpointer ftn
)
409 #ifdef HAVE_MOVING_COLLECTOR
417 mono_marshal_lock ();
418 if (delegate_hash_table
== NULL
)
419 delegate_hash_table
= delegate_hash_table_new ();
421 #ifdef HAVE_MOVING_COLLECTOR
422 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
423 mono_marshal_unlock ();
425 d
= (MonoDelegate
*)mono_gchandle_get_target (gchandle
);
429 d
= g_hash_table_lookup (delegate_hash_table
, ftn
);
430 mono_marshal_unlock ();
433 /* This is a native function, so construct a delegate for it */
434 static MonoClass
*UnmanagedFunctionPointerAttribute
;
435 MonoMethodSignature
*sig
;
437 MonoMarshalSpec
**mspecs
;
438 MonoCustomAttrInfo
*cinfo
;
439 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
440 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
441 MonoMethodPInvoke piinfo
;
444 memset (&piinfo
, 0, sizeof (piinfo
));
445 if (!UnmanagedFunctionPointerAttribute
)
446 UnmanagedFunctionPointerAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
448 /* The attribute is only available in Net 2.0 */
449 if (UnmanagedFunctionPointerAttribute
) {
451 * The pinvoke attributes are stored in a real custom attribute so we have to
454 cinfo
= mono_custom_attrs_from_class (klass
);
456 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr (cinfo
, UnmanagedFunctionPointerAttribute
);
458 piinfo
.piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
461 mono_custom_attrs_free (cinfo
);
465 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
466 mono_method_get_marshal_info (invoke
, mspecs
);
467 /* Freed below so don't alloc from mempool */
468 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
471 wrapper
= mono_marshal_get_native_func_wrapper (klass
->image
, sig
, &piinfo
, mspecs
, ftn
);
473 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
475 mono_metadata_free_marshal_spec (mspecs
[i
]);
479 d
= (MonoDelegate
*)mono_object_new (mono_domain_get (), klass
);
480 mono_delegate_ctor_with_method ((MonoObject
*)d
, NULL
, mono_compile_method (wrapper
), wrapper
);
483 if (d
->object
.vtable
->domain
!= mono_domain_get ())
484 mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
490 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
495 delegate_hash_table_remove (delegate
);
497 ptr
= (gpointer
)InterlockedExchangePointer (&delegate
->delegate_trampoline
, NULL
);
499 if (!delegate
->target
) {
500 /* The wrapper method is shared between delegates -> no need to free it */
507 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
510 method_data
= ((MonoMethodWrapper
*)ji
->method
)->method_data
;
512 /*the target gchandle is the first entry after size and the wrapper itself.*/
513 gchandle
= GPOINTER_TO_UINT (method_data
[2]);
516 mono_gchandle_free (gchandle
);
518 mono_runtime_free_method (mono_object_domain (delegate
), ji
->method
);
523 mono_array_to_savearray (MonoArray
*array
)
528 g_assert_not_reached ();
533 mono_array_to_lparray (MonoArray
*array
)
535 gpointer
*nativeArray
= NULL
;
536 int nativeArraySize
= 0;
545 klass
= array
->obj
.vtable
->klass
;
547 switch (klass
->element_class
->byval_arg
.type
) {
549 g_assert_not_reached ();
552 case MONO_TYPE_CLASS
:
553 nativeArraySize
= array
->max_length
;
554 nativeArray
= malloc(sizeof(gpointer
) * nativeArraySize
);
555 for(i
= 0; i
< nativeArraySize
; ++i
)
556 nativeArray
[i
] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((gpointer
*)array
->vector
)[i
]);
560 case MONO_TYPE_BOOLEAN
:
573 case MONO_TYPE_VALUETYPE
:
577 case MONO_TYPE_GENERICINST
:
578 case MONO_TYPE_OBJECT
:
579 case MONO_TYPE_ARRAY
:
580 case MONO_TYPE_SZARRAY
:
581 case MONO_TYPE_STRING
:
583 g_warning ("type 0x%x not handled", klass
->element_class
->byval_arg
.type
);
584 g_assert_not_reached ();
587 return array
->vector
;
591 mono_free_lparray (MonoArray
*array
, gpointer
* nativeArray
)
602 klass
= array
->obj
.vtable
->klass
;
604 switch (klass
->element_class
->byval_arg
.type
) {
605 case MONO_TYPE_CLASS
:
606 for(i
= 0; i
< array
->max_length
; ++i
)
607 mono_marshal_free_ccw(nativeArray
[i
]);
615 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*elclass
, guint32 elnum
)
617 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
619 if (elclass
== mono_defaults
.byte_class
) {
620 GError
*error
= NULL
;
624 ut
= g_utf8_to_utf16 (native_arr
, elnum
, NULL
, &items_written
, &error
);
627 memcpy (mono_array_addr (arr
, guint16
, 0), ut
, items_written
* sizeof (guint16
));
631 g_error_free (error
);
634 g_assert_not_reached ();
638 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*elclass
, guint32 elnum
)
640 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
642 if (elclass
== mono_defaults
.byte_class
) {
644 GError
*error
= NULL
;
646 as
= g_utf16_to_utf8 (mono_array_addr (arr
, gunichar2
, 0), mono_array_length (arr
), NULL
, NULL
, &error
);
648 MonoException
*exc
= mono_get_exception_argument ("string", error
->message
);
649 g_error_free (error
);
650 mono_raise_exception (exc
);
653 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
656 g_assert_not_reached ();
661 mono_string_utf8_to_builder (MonoStringBuilder
*sb
, char *text
)
663 GError
*error
= NULL
;
673 ut
= g_utf8_to_utf16 (text
, l
, NULL
, &items_written
, &error
);
675 if (items_written
> mono_stringbuilder_capacity (sb
))
676 items_written
= mono_stringbuilder_capacity (sb
);
679 if (! sb
->str
|| sb
->str
== sb
->cached_str
) {
680 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_size (mono_domain_get (), items_written
));
681 sb
->cached_str
= NULL
;
684 memcpy (mono_string_chars (sb
->str
), ut
, items_written
* 2);
685 sb
->length
= items_written
;
687 g_error_free (error
);
693 mono_string_utf8_to_builder2 (char *text
)
696 MonoStringBuilder
*sb
;
697 static MonoClass
*string_builder_class
;
698 static MonoMethod
*sb_ctor
;
705 if (!string_builder_class
) {
706 MonoMethodDesc
*desc
;
708 string_builder_class
= mono_class_from_name (mono_defaults
.corlib
, "System.Text", "StringBuilder");
709 g_assert (string_builder_class
);
710 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
711 sb_ctor
= mono_method_desc_search_in_class (desc
, string_builder_class
);
713 mono_method_desc_free (desc
);
718 sb
= (MonoStringBuilder
*)mono_object_new (mono_domain_get (), string_builder_class
);
721 mono_runtime_invoke (sb_ctor
, sb
, args
, &exc
);
724 mono_string_utf8_to_builder (sb
, text
);
730 * FIXME: This routine does not seem to do what it seems to do
731 * the @text is never copied into the string builder
734 mono_string_utf16_to_builder (MonoStringBuilder
*sb
, gunichar2
*text
)
741 g_assert (mono_string_chars (sb
->str
) == text
);
743 for (len
= 0; text
[len
] != 0; ++len
)
750 mono_string_utf16_to_builder2 (gunichar2
*text
)
753 MonoStringBuilder
*sb
;
754 static MonoClass
*string_builder_class
;
755 static MonoMethod
*sb_ctor
;
762 if (!string_builder_class
) {
763 MonoMethodDesc
*desc
;
765 string_builder_class
= mono_class_from_name (mono_defaults
.corlib
, "System.Text", "StringBuilder");
766 g_assert (string_builder_class
);
767 desc
= mono_method_desc_new (":.ctor(int)", FALSE
);
768 sb_ctor
= mono_method_desc_search_in_class (desc
, string_builder_class
);
770 mono_method_desc_free (desc
);
773 for (len
= 0; text
[len
] != 0; ++len
)
776 sb
= (MonoStringBuilder
*)mono_object_new (mono_domain_get (), string_builder_class
);
779 mono_runtime_invoke (sb_ctor
, sb
, args
, &exc
);
783 memcpy (mono_string_chars (sb
->str
), text
, len
* 2);
789 * mono_string_builder_to_utf8:
790 * @sb: the string builder
792 * Converts to utf8 the contents of the MonoStringBuilder.
794 * Returns: a utf8 string with the contents of the StringBuilder.
796 * The return value must be released with g_free.
799 mono_string_builder_to_utf8 (MonoStringBuilder
*sb
)
801 GError
*error
= NULL
;
802 gchar
*tmp
, *res
= NULL
;
807 if ((sb
->str
== sb
->cached_str
) && (sb
->str
->length
== 0)) {
809 * The sb could have been allocated with the default capacity and be empty.
810 * we need to alloc a buffer of the default capacity in this case.
812 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_size (mono_domain_get (), 16));
813 sb
->cached_str
= NULL
;
816 tmp
= g_utf16_to_utf8 (mono_string_chars (sb
->str
), sb
->length
, NULL
, NULL
, &error
);
818 g_error_free (error
);
819 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
821 res
= mono_marshal_alloc (mono_stringbuilder_capacity (sb
) + 1);
822 memcpy (res
, tmp
, sb
->length
+ 1);
830 * mono_string_builder_to_utf16:
831 * @sb: the string builder
833 * Converts to utf16 the contents of the MonoStringBuilder.
835 * Returns: a utf16 string with the contents of the StringBuilder.
837 * The return value must not be freed.
840 mono_string_builder_to_utf16 (MonoStringBuilder
*sb
)
848 * The stringbuilder might not have ownership of this string. If this is
849 * the case, we must duplicate the string, so that we don't munge immutable
852 if (sb
->str
== sb
->cached_str
) {
854 * The sb could have been allocated with the default capacity and be empty.
855 * we need to alloc a buffer of the default capacity in this case.
857 if (sb
->str
->length
== 0)
858 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_size (mono_domain_get (), 16));
860 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb
->str
), mono_stringbuilder_capacity (sb
)));
861 sb
->cached_str
= NULL
;
865 *(mono_string_chars (sb
->str
)) = '\0';
867 return mono_string_chars (sb
->str
);
871 mono_string_to_lpstr (MonoString
*s
)
876 GError
*error
= NULL
;
882 as
= CoTaskMemAlloc (1);
887 tmp
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &len
, &error
);
889 MonoException
*exc
= mono_get_exception_argument ("string", error
->message
);
890 g_error_free (error
);
891 mono_raise_exception(exc
);
894 as
= CoTaskMemAlloc (len
+ 1);
895 memcpy (as
, tmp
, len
+ 1);
900 return mono_string_to_utf8 (s
);
905 mono_string_to_ansibstr (MonoString
*string_obj
)
907 g_error ("UnmanagedMarshal.BStr is not implemented.");
912 * mono_string_to_byvalstr:
913 * @dst: Where to store the null-terminated utf8 decoded string.
914 * @src: the MonoString to copy.
915 * @size: the maximum number of bytes to copy.
917 * Copies the MonoString pointed to by @src as a utf8 string
918 * into @dst, it copies at most @size bytes into the destination.
921 mono_string_to_byvalstr (gpointer dst
, MonoString
*src
, int size
)
926 g_assert (dst
!= NULL
);
929 memset (dst
, 0, size
);
933 s
= mono_string_to_utf8 (src
);
934 len
= MIN (size
, strlen (s
));
937 memcpy (dst
, s
, len
);
942 * mono_string_to_byvalwstr:
943 * @dst: Where to store the null-terminated utf16 decoded string.
944 * @src: the MonoString to copy.
945 * @size: the maximum number of bytes to copy.
947 * Copies the MonoString pointed to by @src as a utf16 string into
948 * @dst, it copies at most @size bytes into the destination (including
949 * a terminating 16-bit zero terminator).
952 mono_string_to_byvalwstr (gpointer dst
, MonoString
*src
, int size
)
956 g_assert (dst
!= NULL
);
960 memset (dst
, 0, size
* 2);
964 len
= MIN (size
, (mono_string_length (src
)));
965 memcpy (dst
, mono_string_chars (src
), size
* 2);
966 if (size
<= mono_string_length (src
))
968 *((gunichar2
*) dst
+ len
) = 0;
972 mono_mb_emit_proxy_check (MonoMethodBuilder
*mb
, int branch_code
)
975 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
976 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
977 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
978 mono_mb_emit_byte (mb
, CEE_ADD
);
979 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
980 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
981 mono_mb_emit_byte (mb
, CEE_MONO_CLASSCONST
);
982 mono_mb_emit_i4 (mb
, mono_mb_add_data (mb
, mono_defaults
.transparent_proxy_class
));
983 pos
= mono_mb_emit_branch (mb
, branch_code
);
988 mono_mb_emit_xdomain_check (MonoMethodBuilder
*mb
, int branch_code
)
991 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
992 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
993 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRealProxy
, target_domain_id
));
994 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
995 mono_mb_emit_icon (mb
, -1);
996 pos
= mono_mb_emit_branch (mb
, branch_code
);
1001 mono_mb_emit_contextbound_check (MonoMethodBuilder
*mb
, int branch_code
)
1003 static int offset
= -1;
1007 mono_marshal_find_bitfield_offset (MonoClass
, contextbound
, &offset
, &mask
);
1009 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, remote_class
));
1010 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1011 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRemoteClass
, proxy_class
));
1012 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1013 mono_mb_emit_ldflda (mb
, offset
);
1014 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1015 mono_mb_emit_icon (mb
, mask
);
1016 mono_mb_emit_byte (mb
, CEE_AND
);
1017 mono_mb_emit_icon (mb
, 0);
1018 return mono_mb_emit_branch (mb
, branch_code
);
1022 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, const char *msg
)
1024 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", msg
);
1028 mono_type_to_ldind (MonoType
*type
)
1034 switch (type
->type
) {
1036 return CEE_LDIND_I1
;
1038 case MONO_TYPE_BOOLEAN
:
1039 return CEE_LDIND_U1
;
1041 return CEE_LDIND_I2
;
1043 case MONO_TYPE_CHAR
:
1044 return CEE_LDIND_U2
;
1046 return CEE_LDIND_I4
;
1048 return CEE_LDIND_U4
;
1052 case MONO_TYPE_FNPTR
:
1054 case MONO_TYPE_CLASS
:
1055 case MONO_TYPE_STRING
:
1056 case MONO_TYPE_OBJECT
:
1057 case MONO_TYPE_SZARRAY
:
1058 case MONO_TYPE_ARRAY
:
1059 return CEE_LDIND_REF
;
1062 return CEE_LDIND_I8
;
1064 return CEE_LDIND_R4
;
1066 return CEE_LDIND_R8
;
1067 case MONO_TYPE_VALUETYPE
:
1068 if (type
->data
.klass
->enumtype
) {
1069 type
= mono_class_enum_basetype (type
->data
.klass
);
1073 case MONO_TYPE_TYPEDBYREF
:
1075 case MONO_TYPE_GENERICINST
:
1076 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1079 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1085 mono_type_to_stind (MonoType
*type
)
1091 switch (type
->type
) {
1094 case MONO_TYPE_BOOLEAN
:
1095 return CEE_STIND_I1
;
1098 case MONO_TYPE_CHAR
:
1099 return CEE_STIND_I2
;
1102 return CEE_STIND_I4
;
1106 case MONO_TYPE_FNPTR
:
1108 case MONO_TYPE_CLASS
:
1109 case MONO_TYPE_STRING
:
1110 case MONO_TYPE_OBJECT
:
1111 case MONO_TYPE_SZARRAY
:
1112 case MONO_TYPE_ARRAY
:
1113 return CEE_STIND_REF
;
1116 return CEE_STIND_I8
;
1118 return CEE_STIND_R4
;
1120 return CEE_STIND_R8
;
1121 case MONO_TYPE_VALUETYPE
:
1122 if (type
->data
.klass
->enumtype
) {
1123 type
= mono_class_enum_basetype (type
->data
.klass
);
1127 case MONO_TYPE_TYPEDBYREF
:
1129 case MONO_TYPE_GENERICINST
:
1130 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1133 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1139 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1142 case MONO_MARSHAL_CONV_BOOL_I4
:
1143 mono_mb_emit_ldloc (mb
, 1);
1144 mono_mb_emit_ldloc (mb
, 0);
1145 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
1146 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1147 mono_mb_emit_byte (mb
, 3);
1148 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1149 mono_mb_emit_byte (mb
, CEE_BR_S
);
1150 mono_mb_emit_byte (mb
, 1);
1151 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1152 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1154 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1155 mono_mb_emit_ldloc (mb
, 1);
1156 mono_mb_emit_ldloc (mb
, 0);
1157 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
1158 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1159 mono_mb_emit_byte (mb
, 3);
1160 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1161 mono_mb_emit_byte (mb
, CEE_BR_S
);
1162 mono_mb_emit_byte (mb
, 1);
1163 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1164 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1166 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1167 MonoClass
*eklass
= NULL
;
1170 if (type
->type
== MONO_TYPE_SZARRAY
) {
1171 eklass
= type
->data
.klass
;
1173 g_assert_not_reached ();
1176 esize
= mono_class_native_size (eklass
, NULL
);
1178 /* create a new array */
1179 mono_mb_emit_ldloc (mb
, 1);
1180 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1181 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
1182 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1184 if (eklass
->blittable
) {
1185 /* copy the elements */
1186 mono_mb_emit_ldloc (mb
, 1);
1187 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1188 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
1189 mono_mb_emit_byte (mb
, CEE_ADD
);
1190 mono_mb_emit_ldloc (mb
, 0);
1191 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1192 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1193 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1196 int array_var
, src_var
, dst_var
, index_var
;
1197 guint32 label2
, label3
;
1199 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1200 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1201 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1204 mono_mb_emit_ldloc (mb
, 1);
1205 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1206 mono_mb_emit_stloc (mb
, array_var
);
1208 /* save the old src pointer */
1209 mono_mb_emit_ldloc (mb
, 0);
1210 mono_mb_emit_stloc (mb
, src_var
);
1211 /* save the old dst pointer */
1212 mono_mb_emit_ldloc (mb
, 1);
1213 mono_mb_emit_stloc (mb
, dst_var
);
1215 /* Emit marshalling loop */
1216 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1217 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1218 mono_mb_emit_stloc (mb
, index_var
);
1221 label2
= mono_mb_get_label (mb
);
1222 mono_mb_emit_ldloc (mb
, index_var
);
1223 mono_mb_emit_ldloc (mb
, array_var
);
1224 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1225 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1227 /* src is already set */
1230 mono_mb_emit_ldloc (mb
, array_var
);
1231 mono_mb_emit_ldloc (mb
, index_var
);
1232 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1233 mono_mb_emit_stloc (mb
, 1);
1235 /* Do the conversion */
1236 emit_struct_conv (mb
, eklass
, TRUE
);
1239 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1241 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
1243 mono_mb_patch_branch (mb
, label3
);
1245 /* restore the old src pointer */
1246 mono_mb_emit_ldloc (mb
, src_var
);
1247 mono_mb_emit_stloc (mb
, 0);
1248 /* restore the old dst pointer */
1249 mono_mb_emit_ldloc (mb
, dst_var
);
1250 mono_mb_emit_stloc (mb
, 1);
1254 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1255 MonoClass
*eclass
= mono_defaults
.char_class
;
1257 /* create a new array */
1258 mono_mb_emit_ldloc (mb
, 1);
1259 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1260 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
1261 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1263 mono_mb_emit_ldloc (mb
, 1);
1264 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1265 mono_mb_emit_ldloc (mb
, 0);
1266 mono_mb_emit_ptr (mb
, mono_defaults
.byte_class
);
1267 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1268 mono_mb_emit_icall (mb
, mono_byvalarray_to_array
);
1271 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1272 mono_mb_emit_ldloc (mb
, 1);
1273 mono_mb_emit_ldloc (mb
, 0);
1274 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1275 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1277 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
1278 mono_mb_emit_ldloc (mb
, 1);
1279 mono_mb_emit_ldloc (mb
, 0);
1280 mono_mb_emit_icall (mb
, mono_string_from_utf16
);
1281 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1283 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1284 mono_mb_emit_ldloc (mb
, 1);
1285 mono_mb_emit_ldloc (mb
, 0);
1286 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1288 mono_mb_emit_icall (mb
, mono_string_from_utf16
);
1290 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1292 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1294 case MONO_MARSHAL_CONV_STR_LPSTR
:
1295 mono_mb_emit_ldloc (mb
, 1);
1296 mono_mb_emit_ldloc (mb
, 0);
1297 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1298 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1299 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1301 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1302 mono_mb_emit_ldloc (mb
, 1);
1303 mono_mb_emit_ldloc (mb
, 0);
1304 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1305 mono_mb_emit_icall (mb
, mono_string_from_utf16
);
1306 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1308 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1309 MonoClass
*klass
= mono_class_from_mono_type (type
);
1310 int src_var
, dst_var
;
1312 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1313 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1315 /* *dst = new object */
1316 mono_mb_emit_ldloc (mb
, 1);
1317 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1318 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
1319 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1321 /* save the old src pointer */
1322 mono_mb_emit_ldloc (mb
, 0);
1323 mono_mb_emit_stloc (mb
, src_var
);
1324 /* save the old dst pointer */
1325 mono_mb_emit_ldloc (mb
, 1);
1326 mono_mb_emit_stloc (mb
, dst_var
);
1328 /* dst = pointer to newly created object data */
1329 mono_mb_emit_ldloc (mb
, 1);
1330 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1331 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
1332 mono_mb_emit_byte (mb
, CEE_ADD
);
1333 mono_mb_emit_stloc (mb
, 1);
1335 emit_struct_conv (mb
, klass
, TRUE
);
1337 /* restore the old src pointer */
1338 mono_mb_emit_ldloc (mb
, src_var
);
1339 mono_mb_emit_stloc (mb
, 0);
1340 /* restore the old dst pointer */
1341 mono_mb_emit_ldloc (mb
, dst_var
);
1342 mono_mb_emit_stloc (mb
, 1);
1345 case MONO_MARSHAL_CONV_DEL_FTN
: {
1346 MonoClass
*klass
= mono_class_from_mono_type (type
);
1348 mono_mb_emit_ldloc (mb
, 1);
1349 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1350 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1351 mono_mb_emit_ldloc (mb
, 0);
1352 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1353 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
1354 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1357 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1358 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type
)->name
);
1362 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
1363 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1364 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1365 mono_cominterop_emit_ptr_to_object_conv (mb
, type
, conv
, mspec
);
1367 #endif /* DISABLE_COM */
1369 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1371 * Passing SafeHandles as ref does not allow the unmanaged code
1372 * to change the SafeHandle value. If the value is changed,
1373 * we should issue a diagnostic exception (NotSupportedException)
1374 * that informs the user that changes to handles in unmanaged code
1377 * Since we currently have no access to the original
1378 * SafeHandle that was used during the marshalling,
1379 * for now we just ignore this, and ignore/discard any
1380 * changes that might have happened to the handle.
1385 case MONO_MARSHAL_CONV_HANDLEREF
: {
1387 * Passing HandleRefs in a struct that is ref()ed does not
1388 * copy the values back to the HandleRef
1393 case MONO_MARSHAL_CONV_STR_BSTR
:
1394 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1395 case MONO_MARSHAL_CONV_STR_TBSTR
:
1396 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1398 char *msg
= g_strdup_printf ("marshaling conversion %d not implemented", conv
);
1400 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1408 conv_to_icall (MonoMarshalConv conv
)
1411 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1412 return mono_marshal_string_to_utf16
;
1413 case MONO_MARSHAL_CONV_LPWSTR_STR
:
1414 return mono_string_from_utf16
;
1415 case MONO_MARSHAL_CONV_LPSTR_STR
:
1417 return mono_string_from_utf16
;
1419 return mono_string_new_wrapper
;
1421 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1423 return mono_marshal_string_to_utf16
;
1425 return mono_string_to_lpstr
;
1427 case MONO_MARSHAL_CONV_STR_LPSTR
:
1428 return mono_string_to_lpstr
;
1429 case MONO_MARSHAL_CONV_STR_BSTR
:
1430 return mono_string_to_bstr
;
1431 case MONO_MARSHAL_CONV_BSTR_STR
:
1432 return mono_string_from_bstr
;
1433 case MONO_MARSHAL_CONV_STR_TBSTR
:
1434 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1435 return mono_string_to_ansibstr
;
1436 case MONO_MARSHAL_CONV_SB_LPSTR
:
1437 return mono_string_builder_to_utf8
;
1438 case MONO_MARSHAL_CONV_SB_LPTSTR
:
1440 return mono_string_builder_to_utf16
;
1442 return mono_string_builder_to_utf8
;
1444 case MONO_MARSHAL_CONV_SB_LPWSTR
:
1445 return mono_string_builder_to_utf16
;
1446 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1447 return mono_array_to_savearray
;
1448 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1449 return mono_array_to_lparray
;
1450 case MONO_MARSHAL_FREE_LPARRAY
:
1451 return mono_free_lparray
;
1452 case MONO_MARSHAL_CONV_DEL_FTN
:
1453 return mono_delegate_to_ftnptr
;
1454 case MONO_MARSHAL_CONV_FTN_DEL
:
1455 return mono_ftnptr_to_delegate
;
1456 case MONO_MARSHAL_CONV_LPSTR_SB
:
1457 return mono_string_utf8_to_builder
;
1458 case MONO_MARSHAL_CONV_LPTSTR_SB
:
1460 return mono_string_utf16_to_builder
;
1462 return mono_string_utf8_to_builder
;
1464 case MONO_MARSHAL_CONV_LPWSTR_SB
:
1465 return mono_string_utf16_to_builder
;
1466 case MONO_MARSHAL_FREE_ARRAY
:
1467 return mono_marshal_free_array
;
1468 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1469 return mono_string_to_byvalstr
;
1470 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
1471 return mono_string_to_byvalwstr
;
1473 g_assert_not_reached ();
1480 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1485 case MONO_MARSHAL_CONV_BOOL_I4
:
1486 mono_mb_emit_ldloc (mb
, 1);
1487 mono_mb_emit_ldloc (mb
, 0);
1488 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1489 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
1491 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1492 mono_mb_emit_ldloc (mb
, 1);
1493 mono_mb_emit_ldloc (mb
, 0);
1494 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1495 mono_mb_emit_byte (mb
, CEE_NEG
);
1496 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
1498 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1499 case MONO_MARSHAL_CONV_STR_LPSTR
:
1500 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1501 case MONO_MARSHAL_CONV_STR_BSTR
:
1502 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
1503 case MONO_MARSHAL_CONV_STR_TBSTR
: {
1506 /* free space if free == true */
1507 mono_mb_emit_ldloc (mb
, 2);
1508 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1509 mono_mb_emit_ldloc (mb
, 1);
1510 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1511 mono_mb_emit_icall (mb
, g_free
);
1512 mono_mb_patch_short_branch (mb
, pos
);
1514 mono_mb_emit_ldloc (mb
, 1);
1515 mono_mb_emit_ldloc (mb
, 0);
1516 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1517 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
1518 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1521 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
1522 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
1523 case MONO_MARSHAL_CONV_DEL_FTN
:
1524 mono_mb_emit_ldloc (mb
, 1);
1525 mono_mb_emit_ldloc (mb
, 0);
1526 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1527 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
1528 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1530 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1531 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
1534 mono_mb_emit_ldloc (mb
, 1); /* dst */
1535 mono_mb_emit_ldloc (mb
, 0);
1536 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
1537 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1538 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
1541 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1542 MonoClass
*eklass
= NULL
;
1545 if (type
->type
== MONO_TYPE_SZARRAY
) {
1546 eklass
= type
->data
.klass
;
1548 g_assert_not_reached ();
1551 if (eklass
->valuetype
)
1552 esize
= mono_class_native_size (eklass
, NULL
);
1554 esize
= sizeof (gpointer
);
1556 mono_mb_emit_ldloc (mb
, 0);
1557 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1558 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1560 if (eklass
->blittable
) {
1561 mono_mb_emit_ldloc (mb
, 1);
1562 mono_mb_emit_ldloc (mb
, 0);
1563 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1564 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
1565 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1566 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1567 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1569 int array_var
, src_var
, dst_var
, index_var
;
1570 guint32 label2
, label3
;
1572 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1573 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1574 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1577 mono_mb_emit_ldloc (mb
, 0);
1578 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1579 mono_mb_emit_stloc (mb
, array_var
);
1581 /* save the old src pointer */
1582 mono_mb_emit_ldloc (mb
, 0);
1583 mono_mb_emit_stloc (mb
, src_var
);
1584 /* save the old dst pointer */
1585 mono_mb_emit_ldloc (mb
, 1);
1586 mono_mb_emit_stloc (mb
, dst_var
);
1588 /* Emit marshalling loop */
1589 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1590 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1591 mono_mb_emit_stloc (mb
, index_var
);
1594 label2
= mono_mb_get_label (mb
);
1595 mono_mb_emit_ldloc (mb
, index_var
);
1596 mono_mb_emit_ldloc (mb
, array_var
);
1597 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1598 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1601 mono_mb_emit_ldloc (mb
, array_var
);
1602 mono_mb_emit_ldloc (mb
, index_var
);
1603 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1604 mono_mb_emit_stloc (mb
, 0);
1606 /* dst is already set */
1608 /* Do the conversion */
1609 emit_struct_conv (mb
, eklass
, FALSE
);
1612 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1614 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
1616 mono_mb_patch_branch (mb
, label3
);
1618 /* restore the old src pointer */
1619 mono_mb_emit_ldloc (mb
, src_var
);
1620 mono_mb_emit_stloc (mb
, 0);
1621 /* restore the old dst pointer */
1622 mono_mb_emit_ldloc (mb
, dst_var
);
1623 mono_mb_emit_stloc (mb
, 1);
1626 mono_mb_patch_branch (mb
, pos
);
1629 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1630 mono_mb_emit_ldloc (mb
, 0);
1631 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1632 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1634 mono_mb_emit_ldloc (mb
, 1);
1635 mono_mb_emit_ldloc (mb
, 0);
1636 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1637 mono_mb_emit_ptr (mb
, mono_defaults
.byte_class
);
1638 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1639 mono_mb_emit_icall (mb
, mono_array_to_byvalarray
);
1640 mono_mb_patch_short_branch (mb
, pos
);
1643 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1644 int src_var
, dst_var
;
1646 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1647 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1649 mono_mb_emit_ldloc (mb
, 0);
1650 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1651 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1653 /* save the old src pointer */
1654 mono_mb_emit_ldloc (mb
, 0);
1655 mono_mb_emit_stloc (mb
, src_var
);
1656 /* save the old dst pointer */
1657 mono_mb_emit_ldloc (mb
, 1);
1658 mono_mb_emit_stloc (mb
, dst_var
);
1660 /* src = pointer to object data */
1661 mono_mb_emit_ldloc (mb
, 0);
1662 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1663 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
1664 mono_mb_emit_byte (mb
, CEE_ADD
);
1665 mono_mb_emit_stloc (mb
, 0);
1667 emit_struct_conv (mb
, mono_class_from_mono_type (type
), FALSE
);
1669 /* restore the old src pointer */
1670 mono_mb_emit_ldloc (mb
, src_var
);
1671 mono_mb_emit_stloc (mb
, 0);
1672 /* restore the old dst pointer */
1673 mono_mb_emit_ldloc (mb
, dst_var
);
1674 mono_mb_emit_stloc (mb
, 1);
1676 mono_mb_patch_branch (mb
, pos
);
1681 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
1682 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1683 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1684 mono_cominterop_emit_object_to_ptr_conv (mb
, type
, conv
, mspec
);
1686 #endif /* DISABLE_COM */
1688 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1689 int dar_release_slot
, pos
;
1691 dar_release_slot
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
1694 * The following is ifdefed-out, because I have no way of doing the
1695 * DangerousRelease when destroying the structure
1698 /* set release = false */
1699 mono_mb_emit_icon (mb
, 0);
1700 mono_mb_emit_stloc (mb
, dar_release_slot
);
1701 if (!sh_dangerous_add_ref
)
1702 init_safe_handle ();
1704 /* safehandle.DangerousAddRef (ref release) */
1705 mono_mb_emit_ldloc (mb
, 0); /* the source */
1706 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1707 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
1708 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
1710 mono_mb_emit_ldloc (mb
, 0);
1711 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1712 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1713 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
1714 mono_mb_patch_branch (mb
, pos
);
1716 /* Pull the handle field from SafeHandle */
1717 mono_mb_emit_ldloc (mb
, 1);
1718 mono_mb_emit_ldloc (mb
, 0);
1719 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1720 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
1721 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1722 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1726 case MONO_MARSHAL_CONV_HANDLEREF
: {
1727 mono_mb_emit_ldloc (mb
, 1);
1728 mono_mb_emit_ldloc (mb
, 0);
1729 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoHandleRef
, handle
));
1730 mono_mb_emit_byte (mb
, CEE_ADD
);
1731 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1732 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1737 char *msg
= g_strdup_printf ("marshalling conversion %d not implemented", conv
);
1738 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
1739 g_warning ("%s", msg
);
1741 mono_raise_exception (exc
);
1747 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
1749 MonoMarshalType
*info
;
1753 emit_struct_conv(mb
, klass
->parent
, to_object
);
1755 info
= mono_marshal_load_type_info (klass
);
1757 if (info
->native_size
== 0)
1760 if (klass
->blittable
) {
1761 int msize
= mono_class_value_size (klass
, NULL
);
1762 g_assert (msize
== info
->native_size
);
1763 mono_mb_emit_ldloc (mb
, 1);
1764 mono_mb_emit_ldloc (mb
, 0);
1765 mono_mb_emit_icon (mb
, msize
);
1766 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1767 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1769 mono_mb_emit_add_to_local (mb
, 0, msize
);
1770 mono_mb_emit_add_to_local (mb
, 1, msize
);
1774 if (klass
!= mono_defaults
.safehandle_class
) {
1775 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
1776 char *msg
= g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
1777 mono_type_full_name (&klass
->byval_arg
));
1778 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1783 for (i
= 0; i
< info
->num_fields
; i
++) {
1784 MonoMarshalNative ntype
;
1785 MonoMarshalConv conv
;
1786 MonoType
*ftype
= info
->fields
[i
].field
->type
;
1789 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
1791 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
1794 ntype
= mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, klass
->unicode
, &conv
);
1797 msize
= klass
->instance_size
- info
->fields
[i
].field
->offset
;
1798 usize
= info
->native_size
- info
->fields
[i
].offset
;
1800 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
1801 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
1804 if (klass
!= mono_defaults
.safehandle_class
){
1806 * FIXME: Should really check for usize==0 and msize>0, but we apply
1807 * the layout to the managed structure as well.
1810 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) && (usize
== 0)) {
1811 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
1812 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
1813 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
1814 "reference field at the same offset as another field.",
1815 mono_type_full_name (&klass
->byval_arg
));
1820 case MONO_MARSHAL_CONV_NONE
: {
1823 if (ftype
->byref
|| ftype
->type
== MONO_TYPE_I
||
1824 ftype
->type
== MONO_TYPE_U
) {
1825 mono_mb_emit_ldloc (mb
, 1);
1826 mono_mb_emit_ldloc (mb
, 0);
1827 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1828 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1839 case MONO_TYPE_BOOLEAN
:
1842 case MONO_TYPE_CHAR
:
1848 mono_mb_emit_ldloc (mb
, 1);
1849 mono_mb_emit_ldloc (mb
, 0);
1850 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
1851 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
1853 case MONO_TYPE_VALUETYPE
: {
1854 int src_var
, dst_var
;
1856 if (ftype
->data
.klass
->enumtype
) {
1857 ftype
= mono_class_enum_basetype (ftype
->data
.klass
);
1861 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1862 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1864 /* save the old src pointer */
1865 mono_mb_emit_ldloc (mb
, 0);
1866 mono_mb_emit_stloc (mb
, src_var
);
1867 /* save the old dst pointer */
1868 mono_mb_emit_ldloc (mb
, 1);
1869 mono_mb_emit_stloc (mb
, dst_var
);
1871 emit_struct_conv (mb
, ftype
->data
.klass
, to_object
);
1873 /* restore the old src pointer */
1874 mono_mb_emit_ldloc (mb
, src_var
);
1875 mono_mb_emit_stloc (mb
, 0);
1876 /* restore the old dst pointer */
1877 mono_mb_emit_ldloc (mb
, dst_var
);
1878 mono_mb_emit_stloc (mb
, 1);
1881 case MONO_TYPE_OBJECT
: {
1882 mono_init_com_types ();
1884 static MonoMethod
*variant_clear
= NULL
;
1885 static MonoMethod
*get_object_for_native_variant
= NULL
;
1888 variant_clear
= mono_class_get_method_from_name (mono_defaults
.variant_class
, "Clear", 0);
1889 if (!get_object_for_native_variant
)
1890 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
1891 mono_mb_emit_ldloc (mb
, 1);
1892 mono_mb_emit_ldloc (mb
, 0);
1893 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
1894 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1896 mono_mb_emit_ldloc (mb
, 0);
1897 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
1900 static MonoMethod
*get_native_variant_for_object
= NULL
;
1902 if (!get_native_variant_for_object
)
1903 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
1905 mono_mb_emit_ldloc (mb
, 0);
1906 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
1907 mono_mb_emit_ldloc (mb
, 1);
1908 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
1914 g_warning ("marshaling type %02x not implemented", ftype
->type
);
1915 g_assert_not_reached ();
1920 int src_var
, dst_var
;
1922 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1923 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1925 /* save the old src pointer */
1926 mono_mb_emit_ldloc (mb
, 0);
1927 mono_mb_emit_stloc (mb
, src_var
);
1928 /* save the old dst pointer */
1929 mono_mb_emit_ldloc (mb
, 1);
1930 mono_mb_emit_stloc (mb
, dst_var
);
1933 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1935 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1937 /* restore the old src pointer */
1938 mono_mb_emit_ldloc (mb
, src_var
);
1939 mono_mb_emit_stloc (mb
, 0);
1940 /* restore the old dst pointer */
1941 mono_mb_emit_ldloc (mb
, dst_var
);
1942 mono_mb_emit_stloc (mb
, 1);
1947 mono_mb_emit_add_to_local (mb
, 0, usize
);
1948 mono_mb_emit_add_to_local (mb
, 1, msize
);
1950 mono_mb_emit_add_to_local (mb
, 0, msize
);
1951 mono_mb_emit_add_to_local (mb
, 1, usize
);
1957 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
1959 /* Call DestroyStructure */
1960 /* FIXME: Only do this if needed */
1961 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1962 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1963 mono_mb_emit_ldloc (mb
, struct_var
);
1964 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
1968 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, gpointer checkpoint_func
)
1972 mono_mb_emit_ptr (mb
, (gpointer
) mono_thread_interruption_request_flag ());
1973 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
1974 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1976 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1977 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
1979 mono_mb_emit_icall (mb
, checkpoint_func
);
1981 mono_mb_patch_branch (mb
, pos_noabort
);
1985 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1987 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
1990 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_interruption_checkpoint
);
1994 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1996 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_force_interruption_checkpoint
);
2000 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2002 emit_thread_interrupt_checkpoint (mb
);
2005 static MonoAsyncResult
*
2006 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
2008 MonoMethodMessage
*msg
;
2009 MonoDelegate
*async_callback
;
2010 MonoMulticastDelegate
*mcast_delegate
;
2014 MonoMethod
*method
= NULL
, *method2
= NULL
;
2016 g_assert (delegate
);
2017 mcast_delegate
= (MonoMulticastDelegate
*) delegate
;
2018 if (mcast_delegate
->prev
!= NULL
)
2019 mono_raise_exception (mono_get_exception_argument (NULL
, "The delegate must have only one target"));
2021 if (delegate
->target
&& mono_object_class (delegate
->target
) == mono_defaults
.transparent_proxy_class
) {
2023 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
2024 if (!tp
->remote_class
->proxy_class
->contextbound
|| tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
2026 /* If the target is a proxy, make a direct call. Is proxy's work
2027 // to make the call asynchronous.
2029 MonoAsyncResult
*ares
;
2031 MonoArray
*out_args
;
2032 method
= delegate
->method
;
2034 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
);
2035 ares
= mono_async_result_new (mono_domain_get (), NULL
, state
, NULL
, NULL
);
2036 MONO_OBJECT_SETREF (ares
, async_delegate
, (MonoObject
*)delegate
);
2037 MONO_OBJECT_SETREF (ares
, async_callback
, (MonoObject
*)async_callback
);
2038 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
2039 msg
->call_type
= CallType_BeginInvoke
;
2042 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
);
2044 mono_raise_exception ((MonoException
*) exc
);
2049 klass
= delegate
->object
.vtable
->klass
;
2051 method
= mono_get_delegate_invoke (klass
);
2052 method2
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
2055 g_assert (method
!= NULL
);
2057 im
= mono_get_delegate_invoke (method
->klass
);
2058 msg
= mono_method_call_message_new (method
, params
, im
, &async_callback
, &state
);
2060 return mono_thread_pool_add ((MonoObject
*)delegate
, msg
, async_callback
, state
);
2064 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
2066 int i
, params_var
, tmp_var
;
2068 /* allocate local (pointer) *params[] */
2069 params_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2070 /* allocate local (pointer) tmp */
2071 tmp_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2073 /* alloate space on stack to store an array of pointers to the arguments */
2074 mono_mb_emit_icon (mb
, sizeof (gpointer
) * (sig
->param_count
+ 1));
2075 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2076 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2077 mono_mb_emit_stloc (mb
, params_var
);
2080 mono_mb_emit_ldloc (mb
, params_var
);
2081 mono_mb_emit_stloc (mb
, tmp_var
);
2083 if (save_this
&& sig
->hasthis
) {
2084 mono_mb_emit_ldloc (mb
, tmp_var
);
2085 mono_mb_emit_ldarg_addr (mb
, 0);
2086 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2087 /* tmp = tmp + sizeof (gpointer) */
2088 if (sig
->param_count
)
2089 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2093 for (i
= 0; i
< sig
->param_count
; i
++) {
2094 mono_mb_emit_ldloc (mb
, tmp_var
);
2095 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
2096 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2097 /* tmp = tmp + sizeof (gpointer) */
2098 if (i
< (sig
->param_count
- 1))
2099 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2106 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
2110 GString
*res
= g_string_new ("");
2113 g_string_append (res
, prefix
);
2114 g_string_append_c (res
, '_');
2117 mono_type_get_desc (res
, sig
->ret
, FALSE
);
2120 g_string_append (res
, "__this__");
2122 for (i
= 0; i
< sig
->param_count
; ++i
) {
2123 g_string_append_c (res
, '_');
2124 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
2127 g_string_free (res
, FALSE
);
2132 * mono_marshal_get_string_encoding:
2134 * Return the string encoding which should be used for a given parameter.
2136 static MonoMarshalNative
2137 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2139 /* First try the parameter marshal info */
2141 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
2142 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
2143 return spec
->data
.array_data
.elem_type
;
2146 return spec
->native
;
2150 return MONO_NATIVE_LPSTR
;
2152 /* Then try the method level marshal info */
2153 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
2154 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
2155 return MONO_NATIVE_LPSTR
;
2156 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
2157 return MONO_NATIVE_LPWSTR
;
2158 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
2160 return MONO_NATIVE_LPWSTR
;
2162 return MONO_NATIVE_LPSTR
;
2165 return MONO_NATIVE_LPSTR
;
2169 static MonoMarshalConv
2170 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2172 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2175 case MONO_NATIVE_LPWSTR
:
2176 return MONO_MARSHAL_CONV_STR_LPWSTR
;
2177 case MONO_NATIVE_LPSTR
:
2178 return MONO_MARSHAL_CONV_STR_LPSTR
;
2179 case MONO_NATIVE_LPTSTR
:
2180 return MONO_MARSHAL_CONV_STR_LPTSTR
;
2181 case MONO_NATIVE_BSTR
:
2182 return MONO_MARSHAL_CONV_STR_BSTR
;
2188 static MonoMarshalConv
2189 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2191 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2194 case MONO_NATIVE_LPWSTR
:
2195 return MONO_MARSHAL_CONV_SB_LPWSTR
;
2197 case MONO_NATIVE_LPSTR
:
2198 return MONO_MARSHAL_CONV_SB_LPSTR
;
2200 case MONO_NATIVE_LPTSTR
:
2201 return MONO_MARSHAL_CONV_SB_LPTSTR
;
2208 static MonoMarshalConv
2209 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2211 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2216 case MONO_NATIVE_LPWSTR
:
2218 return MONO_MARSHAL_CONV_LPWSTR_STR
;
2219 case MONO_NATIVE_LPSTR
:
2220 return MONO_MARSHAL_CONV_LPSTR_STR
;
2221 case MONO_NATIVE_LPTSTR
:
2222 return MONO_MARSHAL_CONV_LPTSTR_STR
;
2223 case MONO_NATIVE_BSTR
:
2224 return MONO_MARSHAL_CONV_BSTR_STR
;
2230 static MonoMarshalConv
2231 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2233 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2238 case MONO_NATIVE_LPWSTR
:
2240 * mono_string_builder_to_utf16 does not allocate a
2241 * new buffer, so no need to free it.
2244 return MONO_MARSHAL_CONV_LPWSTR_SB
;
2245 case MONO_NATIVE_LPSTR
:
2246 return MONO_MARSHAL_CONV_LPSTR_SB
;
2248 case MONO_NATIVE_LPTSTR
:
2249 return MONO_MARSHAL_CONV_LPTSTR_SB
;
2257 * Return whenever a field of a native structure or an array member needs to
2261 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2263 MonoMarshalNative encoding
;
2264 MonoMarshalConv conv
;
2267 case MONO_TYPE_VALUETYPE
:
2268 /* FIXME: Optimize this */
2270 case MONO_TYPE_OBJECT
:
2271 case MONO_TYPE_CLASS
:
2272 if (t
->data
.klass
== mono_defaults
.stringbuilder_class
) {
2274 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
2278 case MONO_TYPE_STRING
:
2279 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2280 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
2287 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
2290 get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
2293 mono_marshal_lock ();
2296 g_hash_table_new (hash_func
, equal_func
);
2297 mono_memory_barrier ();
2300 mono_marshal_unlock ();
2306 mono_marshal_get_cache (GHashTable
**var
, GHashFunc hash_func
, GCompareFunc equal_func
)
2308 return get_cache (var
, hash_func
, equal_func
);
2312 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
2316 mono_marshal_lock ();
2317 res
= g_hash_table_lookup (cache
, key
);
2318 mono_marshal_unlock ();
2322 /* Create the method from the builder and place it in the cache */
2324 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
2325 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
2330 mono_marshal_lock ();
2331 res
= g_hash_table_lookup (cache
, key
);
2332 mono_marshal_unlock ();
2335 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
2336 mono_marshal_lock ();
2337 res
= g_hash_table_lookup (cache
, key
);
2340 g_hash_table_insert (cache
, key
, res
);
2341 mono_marshal_set_wrapper_info (res
, key
);
2342 mono_marshal_unlock ();
2344 mono_marshal_unlock ();
2345 mono_free_method (newm
);
2353 static inline MonoMethod
*
2354 mono_marshal_remoting_find_in_cache (MonoMethod
*method
, int wrapper_type
)
2356 MonoMethod
*res
= NULL
;
2357 MonoRemotingMethods
*wrps
;
2359 mono_marshal_lock ();
2360 if (method
->klass
->image
->remoting_invoke_cache
)
2361 wrps
= g_hash_table_lookup (method
->klass
->image
->remoting_invoke_cache
, method
);
2366 switch (wrapper_type
) {
2367 case MONO_WRAPPER_REMOTING_INVOKE
: res
= wrps
->invoke
; break;
2368 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
: res
= wrps
->invoke_with_check
; break;
2369 case MONO_WRAPPER_XDOMAIN_INVOKE
: res
= wrps
->xdomain_invoke
; break;
2370 case MONO_WRAPPER_XDOMAIN_DISPATCH
: res
= wrps
->xdomain_dispatch
; break;
2374 /* it is important to do the unlock after the load from wrps, since in
2375 * mono_remoting_mb_create_and_cache () we drop the marshal lock to be able
2376 * to take the loader lock and some other thread may set the fields.
2378 mono_marshal_unlock ();
2382 /* Create the method from the builder and place it in the cache */
2383 static inline MonoMethod
*
2384 mono_remoting_mb_create_and_cache (MonoMethod
*key
, MonoMethodBuilder
*mb
,
2385 MonoMethodSignature
*sig
, int max_stack
)
2387 MonoMethod
**res
= NULL
;
2388 MonoRemotingMethods
*wrps
;
2389 GHashTable
*cache
= get_cache (&key
->klass
->image
->remoting_invoke_cache
, mono_aligned_addr_hash
, NULL
);
2391 mono_marshal_lock ();
2392 wrps
= g_hash_table_lookup (cache
, key
);
2394 wrps
= g_new0 (MonoRemotingMethods
, 1);
2395 g_hash_table_insert (cache
, key
, wrps
);
2398 switch (mb
->method
->wrapper_type
) {
2399 case MONO_WRAPPER_REMOTING_INVOKE
: res
= &wrps
->invoke
; break;
2400 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
: res
= &wrps
->invoke_with_check
; break;
2401 case MONO_WRAPPER_XDOMAIN_INVOKE
: res
= &wrps
->xdomain_invoke
; break;
2402 case MONO_WRAPPER_XDOMAIN_DISPATCH
: res
= &wrps
->xdomain_dispatch
; break;
2403 default: g_assert_not_reached (); break;
2405 mono_marshal_unlock ();
2409 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
2411 mono_marshal_lock ();
2414 mono_marshal_set_wrapper_info (*res
, key
);
2415 mono_marshal_unlock ();
2417 mono_marshal_unlock ();
2418 mono_free_method (newm
);
2426 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
2429 int wrapper_type
= wrapper
->wrapper_type
;
2431 if (wrapper_type
== MONO_WRAPPER_NONE
|| wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2434 switch (wrapper_type
) {
2435 case MONO_WRAPPER_REMOTING_INVOKE
:
2436 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
:
2437 case MONO_WRAPPER_XDOMAIN_INVOKE
:
2438 case MONO_WRAPPER_SYNCHRONIZED
:
2439 case MONO_WRAPPER_MANAGED_TO_NATIVE
:
2440 case MONO_WRAPPER_RUNTIME_INVOKE
:
2441 res
= mono_method_get_wrapper_data (wrapper
, 1);
2451 * mono_marshal_get_wrapper_info:
2453 * Retrieve the pointer stored by mono_marshal_set_wrapper_info.
2456 mono_marshal_get_wrapper_info (MonoMethod
*wrapper
)
2458 g_assert (wrapper
->wrapper_type
);
2460 return mono_method_get_wrapper_data (wrapper
, 1);
2464 * mono_marshal_set_wrapper_info:
2466 * Store an arbitrary pointer inside the wrapper which is retrievable by
2467 * mono_marshal_get_wrapper_info. The format of the data depends on the type of the
2468 * wrapper (method->wrapper_type).
2471 mono_marshal_set_wrapper_info (MonoMethod
*method
, gpointer data
)
2475 if (method
->wrapper_type
== MONO_WRAPPER_NONE
|| method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
2478 datav
= ((MonoMethodWrapper
*)method
)->method_data
;
2483 * get_wrapper_target_class:
2485 * Return the class where a wrapper method should be placed.
2488 get_wrapper_target_class (MonoImage
*image
)
2494 * - can't put all wrappers into an mscorlib class, because they reference
2495 * metadata (signature) so they should be put into the same image as the
2496 * method they wrap, so they are unloaded together.
2497 * - putting them into a class with a type initalizer could cause the
2498 * initializer to be executed which can be a problem if the wrappers are
2500 * - putting them into an inflated class can cause problems if the the
2501 * class is deleted because it references an image which is unloaded.
2502 * To avoid these problems, we put the wrappers into the <Module> class of
2506 klass
= ((MonoDynamicImage
*)image
)->wrappers_type
;
2508 klass
= mono_class_get (image
, mono_metadata_make_token (MONO_TABLE_TYPEDEF
, 1));
2515 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
2517 MonoMethodSignature
*sig
;
2518 MonoMethodBuilder
*mb
;
2524 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
2525 !strcmp (method
->name
, "BeginInvoke"));
2527 sig
= mono_signature_no_pinvoke (method
);
2529 cache
= get_cache (&method
->klass
->image
->delegate_begin_invoke_cache
,
2530 (GHashFunc
)mono_signature_hash
,
2531 (GCompareFunc
)mono_metadata_signature_equal
);
2532 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2535 g_assert (sig
->hasthis
);
2537 name
= mono_signature_to_name (sig
, "begin_invoke");
2538 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
2541 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
2543 mono_mb_emit_ldarg (mb
, 0);
2544 mono_mb_emit_ldloc (mb
, params_var
);
2545 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
2546 mono_mb_emit_byte (mb
, CEE_RET
);
2548 res
= mono_mb_create_and_cache (cache
, sig
, mb
, sig
, sig
->param_count
+ 16);
2554 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
2556 MonoDomain
*domain
= mono_domain_get ();
2557 MonoAsyncResult
*ares
;
2558 MonoMethod
*method
= NULL
;
2559 MonoMethodSignature
*sig
;
2560 MonoMethodMessage
*msg
;
2561 MonoObject
*res
, *exc
;
2562 MonoArray
*out_args
;
2565 g_assert (delegate
);
2567 if (!delegate
->method_info
) {
2568 g_assert (delegate
->method
);
2569 MONO_OBJECT_SETREF (delegate
, method_info
, mono_method_get_object (domain
, delegate
->method
, NULL
));
2572 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
2573 g_assert_not_reached ();
2575 klass
= delegate
->object
.vtable
->klass
;
2577 method
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
2578 g_assert (method
!= NULL
);
2580 sig
= mono_signature_no_pinvoke (method
);
2582 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
);
2584 ares
= mono_array_get (msg
->args
, gpointer
, sig
->param_count
- 1);
2586 mono_raise_exception (mono_exception_from_name_msg (mono_defaults
.corlib
, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
2590 if (ares
->async_delegate
!= (MonoObject
*)delegate
) {
2591 mono_raise_exception (mono_get_exception_invalid_operation (
2592 "The IAsyncResult object provided does not match this delegate."));
2596 if (delegate
->target
&& mono_object_class (delegate
->target
) == mono_defaults
.transparent_proxy_class
) {
2597 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
2598 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
2599 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
);
2600 msg
->call_type
= CallType_EndInvoke
;
2601 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
2602 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
);
2604 res
= mono_thread_pool_finish (ares
, &out_args
, &exc
);
2608 if (((MonoException
*)exc
)->stack_trace
) {
2609 char *strace
= mono_string_to_utf8 (((MonoException
*)exc
)->stack_trace
);
2611 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
2613 MONO_OBJECT_SETREF (((MonoException
*)exc
), stack_trace
, mono_string_new (domain
, tmp
));
2616 mono_raise_exception ((MonoException
*)exc
);
2619 mono_method_return_message_restore (method
, params
, out_args
);
2624 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
2626 MonoType
*t
= mono_type_get_underlying_type (return_type
);
2628 if (return_type
->byref
)
2629 return_type
= &mono_defaults
.int_class
->byval_arg
;
2632 case MONO_TYPE_VOID
:
2633 g_assert_not_reached ();
2636 case MONO_TYPE_STRING
:
2637 case MONO_TYPE_CLASS
:
2638 case MONO_TYPE_OBJECT
:
2639 case MONO_TYPE_ARRAY
:
2640 case MONO_TYPE_SZARRAY
:
2644 case MONO_TYPE_BOOLEAN
:
2647 case MONO_TYPE_CHAR
:
2657 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (return_type
));
2658 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
2660 case MONO_TYPE_GENERICINST
:
2661 if (!mono_type_generic_inst_is_valuetype (t
))
2664 case MONO_TYPE_VALUETYPE
: {
2665 MonoClass
*klass
= mono_class_from_mono_type (return_type
);
2666 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
2667 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
2671 g_warning ("type 0x%x not handled", return_type
->type
);
2672 g_assert_not_reached ();
2675 mono_mb_emit_byte (mb
, CEE_RET
);
2679 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
2681 MonoMethodSignature
*sig
;
2682 MonoMethodBuilder
*mb
;
2688 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
2689 !strcmp (method
->name
, "EndInvoke"));
2691 sig
= mono_signature_no_pinvoke (method
);
2693 cache
= get_cache (&method
->klass
->image
->delegate_end_invoke_cache
,
2694 (GHashFunc
)mono_signature_hash
,
2695 (GCompareFunc
)mono_metadata_signature_equal
);
2696 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
2699 g_assert (sig
->hasthis
);
2701 name
= mono_signature_to_name (sig
, "end_invoke");
2702 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
2705 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
2707 mono_mb_emit_ldarg (mb
, 0);
2708 mono_mb_emit_ldloc (mb
, params_var
);
2709 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
2711 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
2712 mono_mb_emit_byte (mb
, CEE_POP
);
2713 mono_mb_emit_byte (mb
, CEE_RET
);
2715 mono_mb_emit_restore_result (mb
, sig
->ret
);
2717 res
= mono_mb_create_and_cache (cache
, sig
,
2718 mb
, sig
, sig
->param_count
+ 16);
2725 mono_remoting_wrapper (MonoMethod
*method
, gpointer
*params
)
2727 MonoMethodMessage
*msg
;
2728 MonoTransparentProxy
*this;
2729 MonoObject
*res
, *exc
;
2730 MonoArray
*out_args
;
2732 this = *((MonoTransparentProxy
**)params
[0]);
2735 g_assert (((MonoObject
*)this)->vtable
->klass
== mono_defaults
.transparent_proxy_class
);
2737 /* skip the this pointer */
2740 if (this->remote_class
->proxy_class
->contextbound
&& this->rp
->context
== (MonoObject
*) mono_context_get ())
2743 MonoMethodSignature
*sig
= mono_method_signature (method
);
2744 int count
= sig
->param_count
;
2745 gpointer
* mparams
= (gpointer
*) alloca(count
*sizeof(gpointer
));
2747 for (i
=0; i
<count
; i
++) {
2748 MonoClass
*class = mono_class_from_mono_type (sig
->params
[i
]);
2749 if (class->valuetype
) {
2750 if (sig
->params
[i
]->byref
) {
2751 mparams
[i
] = *((gpointer
*)params
[i
]);
2753 /* runtime_invoke expects a boxed instance */
2754 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->params
[i
])))
2755 mparams
[i
] = mono_nullable_box (params
[i
], class);
2757 mparams
[i
] = params
[i
];
2760 mparams
[i
] = *((gpointer
**)params
[i
]);
2764 return mono_runtime_invoke (method
, method
->klass
->valuetype
? mono_object_unbox ((MonoObject
*)this): this, mparams
, NULL
);
2767 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
);
2769 res
= mono_remoting_invoke ((MonoObject
*)this->rp
, msg
, &exc
, &out_args
);
2772 mono_raise_exception ((MonoException
*)exc
);
2774 mono_method_return_message_restore (method
, params
, out_args
);
2780 mono_marshal_get_remoting_invoke (MonoMethod
*method
)
2782 MonoMethodSignature
*sig
;
2783 MonoMethodBuilder
*mb
;
2789 if (method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
|| method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
)
2792 /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
2793 if (method
->klass
->is_com_object
|| method
->klass
== mono_defaults
.com_object_class
) {
2794 MonoVTable
*vtable
= mono_class_vtable (mono_domain_get (), method
->klass
);
2795 g_assert (vtable
); /*FIXME do proper error handling*/
2797 if (!vtable
->remote
) {
2799 return mono_cominterop_get_invoke (method
);
2801 g_assert_not_reached ();
2806 sig
= mono_signature_no_pinvoke (method
);
2808 /* we cant remote methods without this pointer */
2812 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_REMOTING_INVOKE
)))
2815 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_REMOTING_INVOKE
);
2816 mb
->method
->save_lmf
= 1;
2818 params_var
= mono_mb_emit_save_args (mb
, sig
, TRUE
);
2820 mono_mb_emit_ptr (mb
, method
);
2821 mono_mb_emit_ldloc (mb
, params_var
);
2822 mono_mb_emit_icall (mb
, mono_remoting_wrapper
);
2823 emit_thread_interrupt_checkpoint (mb
);
2825 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
2826 mono_mb_emit_byte (mb
, CEE_POP
);
2827 mono_mb_emit_byte (mb
, CEE_RET
);
2829 mono_mb_emit_restore_result (mb
, sig
->ret
);
2832 res
= mono_remoting_mb_create_and_cache (method
, mb
, sig
, sig
->param_count
+ 16);
2838 /* mono_get_xdomain_marshal_type()
2839 * Returns the kind of marshalling that a type needs for cross domain calls.
2841 static MonoXDomainMarshalType
2842 mono_get_xdomain_marshal_type (MonoType
*t
)
2845 case MONO_TYPE_VOID
:
2846 g_assert_not_reached ();
2850 case MONO_TYPE_BOOLEAN
:
2853 case MONO_TYPE_CHAR
:
2860 return MONO_MARSHAL_NONE
;
2861 case MONO_TYPE_STRING
:
2862 return MONO_MARSHAL_COPY
;
2863 case MONO_TYPE_ARRAY
:
2864 case MONO_TYPE_SZARRAY
: {
2865 MonoClass
*elem_class
= mono_class_from_mono_type (t
)->element_class
;
2866 if (mono_get_xdomain_marshal_type (&(elem_class
->byval_arg
)) != MONO_MARSHAL_SERIALIZE
)
2867 return MONO_MARSHAL_COPY
;
2872 return MONO_MARSHAL_SERIALIZE
;
2876 /* mono_marshal_xdomain_copy_value
2877 * Makes a copy of "val" suitable for the current domain.
2880 mono_marshal_xdomain_copy_value (MonoObject
*val
)
2883 if (val
== NULL
) return NULL
;
2885 domain
= mono_domain_get ();
2887 switch (mono_object_class (val
)->byval_arg
.type
) {
2888 case MONO_TYPE_VOID
:
2889 g_assert_not_reached ();
2893 case MONO_TYPE_BOOLEAN
:
2896 case MONO_TYPE_CHAR
:
2902 case MONO_TYPE_R8
: {
2903 return mono_value_box (domain
, mono_object_class (val
), ((char*)val
) + sizeof(MonoObject
));
2905 case MONO_TYPE_STRING
: {
2906 MonoString
*str
= (MonoString
*) val
;
2907 return (MonoObject
*) mono_string_new_utf16 (domain
, mono_string_chars (str
), mono_string_length (str
));
2909 case MONO_TYPE_ARRAY
:
2910 case MONO_TYPE_SZARRAY
: {
2912 MonoXDomainMarshalType mt
= mono_get_xdomain_marshal_type (&(mono_object_class (val
)->element_class
->byval_arg
));
2913 if (mt
== MONO_MARSHAL_SERIALIZE
) return NULL
;
2914 acopy
= mono_array_clone_in_domain (domain
, (MonoArray
*) val
);
2915 if (mt
== MONO_MARSHAL_COPY
) {
2916 int i
, len
= mono_array_length (acopy
);
2917 for (i
= 0; i
< len
; i
++) {
2918 MonoObject
*item
= mono_array_get (acopy
, gpointer
, i
);
2919 mono_array_setref (acopy
, i
, mono_marshal_xdomain_copy_value (item
));
2922 return (MonoObject
*) acopy
;
2926 if (mono_object_class (val
) == mono_defaults
.stringbuilder_class
) {
2927 MonoStringBuilder
*oldsb
= (MonoStringBuilder
*) val
;
2928 MonoStringBuilder
*newsb
= (MonoStringBuilder
*) mono_object_new (domain
, mono_defaults
.stringbuilder_class
);
2929 MONO_OBJECT_SETREF (newsb
, str
, mono_string_new_utf16 (domain
, mono_string_chars (oldsb
->str
), mono_string_length (oldsb
->str
)));
2930 newsb
->length
= oldsb
->length
;
2931 newsb
->max_capacity
= (gint32
)0x7fffffff;
2932 return (MonoObject
*) newsb
;
2937 /* mono_marshal_xdomain_copy_out_value()
2938 * Copies the contents of the src instance into the dst instance. src and dst
2939 * must have the same type, and if they are arrays, the same size.
2942 mono_marshal_xdomain_copy_out_value (MonoObject
*src
, MonoObject
*dst
)
2944 if (src
== NULL
|| dst
== NULL
) return;
2946 g_assert (mono_object_class (src
) == mono_object_class (dst
));
2948 switch (mono_object_class (src
)->byval_arg
.type
) {
2949 case MONO_TYPE_ARRAY
:
2950 case MONO_TYPE_SZARRAY
: {
2951 int mt
= mono_get_xdomain_marshal_type (&(mono_object_class (src
)->element_class
->byval_arg
));
2952 if (mt
== MONO_MARSHAL_SERIALIZE
) return;
2953 if (mt
== MONO_MARSHAL_COPY
) {
2954 int i
, len
= mono_array_length ((MonoArray
*)dst
);
2955 for (i
= 0; i
< len
; i
++) {
2956 MonoObject
*item
= mono_array_get ((MonoArray
*)src
, gpointer
, i
);
2957 mono_array_setref ((MonoArray
*)dst
, i
, mono_marshal_xdomain_copy_value (item
));
2960 mono_array_full_copy ((MonoArray
*)src
, (MonoArray
*)dst
);
2966 if (mono_object_class (src
) == mono_defaults
.stringbuilder_class
) {
2967 MonoStringBuilder
*src_sb
= (MonoStringBuilder
*) src
;
2968 MonoStringBuilder
*dst_sb
= (MonoStringBuilder
*) dst
;
2970 MONO_OBJECT_SETREF (dst_sb
, str
, mono_string_new_utf16 (mono_object_domain (dst
), mono_string_chars (src_sb
->str
), mono_string_length (src_sb
->str
)));
2971 dst_sb
->cached_str
= NULL
;
2972 dst_sb
->length
= src_sb
->length
;
2977 mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder
*mb
, MonoClass
*pclass
)
2979 mono_mb_emit_icall (mb
, mono_marshal_xdomain_copy_value
);
2980 mono_mb_emit_op (mb
, CEE_CASTCLASS
, pclass
);
2984 mono_marshal_emit_xdomain_copy_out_value (MonoMethodBuilder
*mb
, MonoClass
*pclass
)
2986 mono_mb_emit_icall (mb
, mono_marshal_xdomain_copy_out_value
);
2989 /* mono_marshal_supports_fast_xdomain()
2990 * Returns TRUE if the method can use the fast xdomain wrapper.
2993 mono_marshal_supports_fast_xdomain (MonoMethod
*method
)
2995 return !method
->klass
->contextbound
&&
2996 !((method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) && (strcmp (".ctor", method
->name
) == 0));
3000 mono_marshal_set_domain_by_id (gint32 id
, MonoBoolean push
)
3002 MonoDomain
*current_domain
= mono_domain_get ();
3003 MonoDomain
*domain
= mono_domain_get_by_id (id
);
3005 if (!domain
|| !mono_domain_set (domain
, FALSE
))
3006 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
3009 mono_thread_push_appdomain_ref (domain
);
3011 mono_thread_pop_appdomain_ref ();
3013 return current_domain
->domain_id
;
3017 mono_marshal_emit_switch_domain (MonoMethodBuilder
*mb
)
3019 mono_mb_emit_icall (mb
, mono_marshal_set_domain_by_id
);
3022 /* mono_marshal_emit_load_domain_method ()
3023 * Loads into the stack a pointer to the code of the provided method for
3024 * the current domain.
3027 mono_marshal_emit_load_domain_method (MonoMethodBuilder
*mb
, MonoMethod
*method
)
3029 /* We need a pointer to the method for the running domain (not the domain
3030 * that compiles the method).
3032 mono_mb_emit_ptr (mb
, method
);
3033 mono_mb_emit_icall (mb
, mono_compile_method
);
3036 /* mono_marshal_check_domain_image ()
3037 * Returns TRUE if the image is loaded in the specified
3038 * application domain.
3041 mono_marshal_check_domain_image (gint32 domain_id
, MonoImage
*image
)
3046 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
3050 mono_domain_assemblies_lock (domain
);
3051 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
3053 if (ass
->image
== image
)
3056 mono_domain_assemblies_unlock (domain
);
3061 /* mono_marshal_get_xappdomain_dispatch ()
3062 * Generates a method that dispatches a method call from another domain into
3063 * the current domain.
3066 mono_marshal_get_xappdomain_dispatch (MonoMethod
*method
, int *marshal_types
, int complex_count
, int complex_out_count
, int ret_marshal_type
)
3068 MonoMethodSignature
*sig
, *csig
;
3069 MonoMethodBuilder
*mb
;
3071 int i
, j
, param_index
, copy_locals_base
;
3072 MonoClass
*ret_class
= NULL
;
3073 int loc_array
=0, loc_return
=0, loc_serialized_exc
=0;
3074 MonoExceptionClause
*main_clause
;
3076 gboolean copy_return
;
3078 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_XDOMAIN_DISPATCH
)))
3081 sig
= mono_method_signature (method
);
3082 copy_return
= (sig
->ret
->type
!= MONO_TYPE_VOID
&& ret_marshal_type
!= MONO_MARSHAL_SERIALIZE
);
3085 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3 + sig
->param_count
- complex_count
);
3086 csig
->params
[j
++] = &mono_defaults
.object_class
->byval_arg
;
3087 csig
->params
[j
++] = &byte_array_class
->this_arg
;
3088 csig
->params
[j
++] = &byte_array_class
->this_arg
;
3089 for (i
= 0; i
< sig
->param_count
; i
++) {
3090 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
)
3091 csig
->params
[j
++] = sig
->params
[i
];
3094 csig
->ret
= sig
->ret
;
3096 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
3098 csig
->hasthis
= FALSE
;
3100 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_XDOMAIN_DISPATCH
);
3101 mb
->method
->save_lmf
= 1;
3105 loc_serialized_exc
= mono_mb_add_local (mb
, &byte_array_class
->byval_arg
);
3106 if (complex_count
> 0)
3107 loc_array
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3108 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3109 loc_return
= mono_mb_add_local (mb
, sig
->ret
);
3110 ret_class
= mono_class_from_mono_type (sig
->ret
);
3115 main_clause
= mono_image_alloc0 (method
->klass
->image
, sizeof (MonoExceptionClause
));
3116 main_clause
->try_offset
= mono_mb_get_label (mb
);
3118 /* Clean the call context */
3120 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3121 mono_mb_emit_managed_call (mb
, method_set_call_context
, NULL
);
3122 mono_mb_emit_byte (mb
, CEE_POP
);
3124 /* Deserialize call data */
3126 mono_mb_emit_ldarg (mb
, 1);
3127 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3128 mono_mb_emit_byte (mb
, CEE_DUP
);
3129 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3131 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
3132 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
3134 if (complex_count
> 0)
3135 mono_mb_emit_stloc (mb
, loc_array
);
3137 mono_mb_emit_byte (mb
, CEE_POP
);
3139 mono_mb_patch_short_branch (mb
, pos
);
3141 /* Get the target object */
3143 mono_mb_emit_ldarg (mb
, 0);
3144 mono_mb_emit_managed_call (mb
, method_rs_appdomain_target
, NULL
);
3146 /* Load the arguments */
3148 copy_locals_base
= mb
->locals
;
3149 param_index
= 3; // Index of the first non-serialized parameter of this wrapper
3151 for (i
= 0; i
< sig
->param_count
; i
++) {
3152 MonoType
*pt
= sig
->params
[i
];
3153 MonoClass
*pclass
= mono_class_from_mono_type (pt
);
3154 switch (marshal_types
[i
]) {
3155 case MONO_MARSHAL_SERIALIZE
: {
3156 /* take the value from the serialized array */
3157 mono_mb_emit_ldloc (mb
, loc_array
);
3158 mono_mb_emit_icon (mb
, j
++);
3160 if (pclass
->valuetype
) {
3161 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3162 mono_mb_emit_op (mb
, CEE_UNBOX
, pclass
);
3164 mono_mb_emit_op (mb
, CEE_LDELEMA
, pclass
);
3167 if (pclass
->valuetype
) {
3168 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3169 mono_mb_emit_op (mb
, CEE_UNBOX
, pclass
);
3170 mono_mb_emit_op (mb
, CEE_LDOBJ
, pclass
);
3172 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3173 if (pclass
!= mono_defaults
.object_class
) {
3174 mono_mb_emit_op (mb
, CEE_CASTCLASS
, pclass
);
3180 case MONO_MARSHAL_COPY_OUT
: {
3181 /* Keep a local copy of the value since we need to copy it back after the call */
3182 int copy_local
= mono_mb_add_local (mb
, &(pclass
->byval_arg
));
3183 mono_mb_emit_ldarg (mb
, param_index
++);
3184 mono_marshal_emit_xdomain_copy_value (mb
, pclass
);
3185 mono_mb_emit_byte (mb
, CEE_DUP
);
3186 mono_mb_emit_stloc (mb
, copy_local
);
3189 case MONO_MARSHAL_COPY
: {
3190 mono_mb_emit_ldarg (mb
, param_index
);
3192 mono_mb_emit_byte (mb
, CEE_DUP
);
3193 mono_mb_emit_byte (mb
, CEE_DUP
);
3194 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3195 mono_marshal_emit_xdomain_copy_value (mb
, pclass
);
3196 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3198 mono_marshal_emit_xdomain_copy_value (mb
, pclass
);
3203 case MONO_MARSHAL_NONE
:
3204 mono_mb_emit_ldarg (mb
, param_index
++);
3209 /* Make the call to the real object */
3211 emit_thread_force_interrupt_checkpoint (mb
);
3213 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
3215 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
3216 mono_mb_emit_stloc (mb
, loc_return
);
3218 /* copy back MONO_MARSHAL_COPY_OUT parameters */
3222 for (i
= 0; i
< sig
->param_count
; i
++) {
3223 if (marshal_types
[i
] == MONO_MARSHAL_SERIALIZE
) continue;
3224 if (marshal_types
[i
] == MONO_MARSHAL_COPY_OUT
) {
3225 mono_mb_emit_ldloc (mb
, copy_locals_base
+ (j
++));
3226 mono_mb_emit_ldarg (mb
, param_index
);
3227 mono_marshal_emit_xdomain_copy_out_value (mb
, mono_class_from_mono_type (sig
->params
[i
]));
3232 /* Serialize the return values */
3234 if (complex_out_count
> 0) {
3235 /* Reset parameters in the array that don't need to be serialized back */
3237 for (i
= 0; i
< sig
->param_count
; i
++) {
3238 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
) continue;
3239 if (!sig
->params
[i
]->byref
) {
3240 mono_mb_emit_ldloc (mb
, loc_array
);
3241 mono_mb_emit_icon (mb
, j
);
3242 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3243 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
3248 /* Add the return value to the array */
3250 if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
3251 mono_mb_emit_ldloc (mb
, loc_array
);
3252 mono_mb_emit_icon (mb
, complex_count
); /* The array has an additional slot to hold the ret value */
3253 mono_mb_emit_ldloc (mb
, loc_return
);
3255 g_assert (ret_class
); /*FIXME properly fail here*/
3256 if (ret_class
->valuetype
) {
3257 mono_mb_emit_op (mb
, CEE_BOX
, ret_class
);
3259 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
3264 mono_mb_emit_ldarg (mb
, 1);
3265 mono_mb_emit_ldloc (mb
, loc_array
);
3266 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
3267 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3268 } else if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
3269 mono_mb_emit_ldarg (mb
, 1);
3270 mono_mb_emit_ldloc (mb
, loc_return
);
3271 if (ret_class
->valuetype
) {
3272 mono_mb_emit_op (mb
, CEE_BOX
, ret_class
);
3274 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
3275 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3277 mono_mb_emit_ldarg (mb
, 1);
3278 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3279 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
3280 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3283 mono_mb_emit_ldarg (mb
, 2);
3284 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3285 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3286 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
3288 /* Main exception catch */
3289 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
3290 main_clause
->try_len
= mono_mb_get_pos (mb
) - main_clause
->try_offset
;
3291 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
3294 main_clause
->handler_offset
= mono_mb_get_label (mb
);
3295 mono_mb_emit_managed_call (mb
, method_rs_serialize_exc
, NULL
);
3296 mono_mb_emit_stloc (mb
, loc_serialized_exc
);
3297 mono_mb_emit_ldarg (mb
, 2);
3298 mono_mb_emit_ldloc (mb
, loc_serialized_exc
);
3299 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3300 mono_mb_emit_branch (mb
, CEE_LEAVE
);
3301 main_clause
->handler_len
= mono_mb_get_pos (mb
) - main_clause
->handler_offset
;
3304 mono_mb_patch_branch (mb
, pos_leave
);
3307 mono_mb_emit_ldloc (mb
, loc_return
);
3309 mono_mb_emit_byte (mb
, CEE_RET
);
3311 mono_mb_set_clauses (mb
, 1, main_clause
);
3313 res
= mono_remoting_mb_create_and_cache (method
, mb
, csig
, csig
->param_count
+ 16);
3319 /* mono_marshal_get_xappdomain_invoke ()
3320 * Generates a fast remoting wrapper for cross app domain calls.
3323 mono_marshal_get_xappdomain_invoke (MonoMethod
*method
)
3325 MonoMethodSignature
*sig
;
3326 MonoMethodBuilder
*mb
;
3328 int i
, j
, complex_count
, complex_out_count
, copy_locals_base
;
3330 MonoClass
*ret_class
= NULL
;
3331 MonoMethod
*xdomain_method
;
3332 int ret_marshal_type
= MONO_MARSHAL_NONE
;
3333 int loc_array
=0, loc_serialized_data
=-1, loc_real_proxy
;
3334 int loc_old_domainid
, loc_domainid
, loc_return
=0, loc_serialized_exc
=0, loc_context
;
3335 int pos
, pos_dispatch
, pos_noex
;
3336 gboolean copy_return
= FALSE
;
3340 if (method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
|| method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
)
3343 /* we cant remote methods without this pointer */
3344 if (!mono_method_signature (method
)->hasthis
)
3347 if (!mono_marshal_supports_fast_xdomain (method
))
3348 return mono_marshal_get_remoting_invoke (method
);
3350 mono_remoting_marshal_init ();
3352 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_XDOMAIN_INVOKE
)))
3355 sig
= mono_signature_no_pinvoke (method
);
3357 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_XDOMAIN_INVOKE
);
3358 mb
->method
->save_lmf
= 1;
3360 /* Count the number of parameters that need to be serialized */
3362 marshal_types
= alloca (sizeof (int) * sig
->param_count
);
3363 complex_count
= complex_out_count
= 0;
3364 for (i
= 0; i
< sig
->param_count
; i
++) {
3365 MonoType
*ptype
= sig
->params
[i
];
3366 int mt
= mono_get_xdomain_marshal_type (ptype
);
3368 /* If the [Out] attribute is applied to a parameter that can be internally copied,
3369 * the copy will be made by reusing the original object instance
3371 if ((ptype
->attrs
& PARAM_ATTRIBUTE_OUT
) != 0 && mt
== MONO_MARSHAL_COPY
&& !ptype
->byref
)
3372 mt
= MONO_MARSHAL_COPY_OUT
;
3373 else if (mt
== MONO_MARSHAL_SERIALIZE
) {
3375 if (ptype
->byref
) complex_out_count
++;
3377 marshal_types
[i
] = mt
;
3380 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
3381 ret_marshal_type
= mono_get_xdomain_marshal_type (sig
->ret
);
3382 ret_class
= mono_class_from_mono_type (sig
->ret
);
3383 copy_return
= ret_marshal_type
!= MONO_MARSHAL_SERIALIZE
;
3388 if (complex_count
> 0)
3389 loc_array
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3390 loc_serialized_data
= mono_mb_add_local (mb
, &byte_array_class
->byval_arg
);
3391 loc_real_proxy
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3393 loc_return
= mono_mb_add_local (mb
, sig
->ret
);
3394 loc_old_domainid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
3395 loc_domainid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
3396 loc_serialized_exc
= mono_mb_add_local (mb
, &byte_array_class
->byval_arg
);
3397 loc_context
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3399 /* Save thread domain data */
3401 mono_mb_emit_icall (mb
, mono_context_get
);
3402 mono_mb_emit_byte (mb
, CEE_DUP
);
3403 mono_mb_emit_stloc (mb
, loc_context
);
3405 /* If the thread is not running in the default context, it needs to go
3406 * through the whole remoting sink, since the context is going to change
3408 mono_mb_emit_managed_call (mb
, method_needs_context_sink
, NULL
);
3409 pos
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3411 /* Another case in which the fast path can't be used: when the target domain
3412 * has a different image for the same assembly.
3415 /* Get the target domain id */
3417 mono_mb_emit_ldarg (mb
, 0);
3418 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
3419 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3420 mono_mb_emit_byte (mb
, CEE_DUP
);
3421 mono_mb_emit_stloc (mb
, loc_real_proxy
);
3423 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRealProxy
, target_domain_id
));
3424 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3425 mono_mb_emit_stloc (mb
, loc_domainid
);
3427 /* Check if the target domain has the same image for the required assembly */
3429 mono_mb_emit_ldloc (mb
, loc_domainid
);
3430 mono_mb_emit_ptr (mb
, method
->klass
->image
);
3431 mono_mb_emit_icall (mb
, mono_marshal_check_domain_image
);
3432 pos_dispatch
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3434 /* Use the whole remoting sink to dispatch this message */
3436 mono_mb_patch_short_branch (mb
, pos
);
3438 mono_mb_emit_ldarg (mb
, 0);
3439 for (i
= 0; i
< sig
->param_count
; i
++)
3440 mono_mb_emit_ldarg (mb
, i
+ 1);
3442 mono_mb_emit_managed_call (mb
, mono_marshal_get_remoting_invoke (method
), NULL
);
3443 mono_mb_emit_byte (mb
, CEE_RET
);
3444 mono_mb_patch_short_branch (mb
, pos_dispatch
);
3446 /* Create the array that will hold the parameters to be serialized */
3448 if (complex_count
> 0) {
3449 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 */
3450 mono_mb_emit_op (mb
, CEE_NEWARR
, mono_defaults
.object_class
);
3453 for (i
= 0; i
< sig
->param_count
; i
++) {
3455 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
) continue;
3456 pclass
= mono_class_from_mono_type (sig
->params
[i
]);
3457 mono_mb_emit_byte (mb
, CEE_DUP
);
3458 mono_mb_emit_icon (mb
, j
);
3459 mono_mb_emit_ldarg (mb
, i
+ 1); /* 0=this */
3460 if (sig
->params
[i
]->byref
) {
3461 if (pclass
->valuetype
)
3462 mono_mb_emit_op (mb
, CEE_LDOBJ
, pclass
);
3464 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3466 if (pclass
->valuetype
)
3467 mono_mb_emit_op (mb
, CEE_BOX
, pclass
);
3468 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
3471 mono_mb_emit_stloc (mb
, loc_array
);
3473 /* Serialize parameters */
3475 mono_mb_emit_ldloc (mb
, loc_array
);
3476 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
3477 mono_mb_emit_stloc (mb
, loc_serialized_data
);
3479 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3480 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
3481 mono_mb_emit_stloc (mb
, loc_serialized_data
);
3486 mono_mb_emit_ldloc (mb
, loc_domainid
);
3487 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3488 mono_marshal_emit_switch_domain (mb
);
3489 mono_mb_emit_stloc (mb
, loc_old_domainid
);
3491 /* Load the arguments */
3493 mono_mb_emit_ldloc (mb
, loc_real_proxy
);
3494 mono_mb_emit_ldloc_addr (mb
, loc_serialized_data
);
3495 mono_mb_emit_ldloc_addr (mb
, loc_serialized_exc
);
3497 copy_locals_base
= mb
->locals
;
3498 for (i
= 0; i
< sig
->param_count
; i
++) {
3499 switch (marshal_types
[i
]) {
3500 case MONO_MARSHAL_SERIALIZE
:
3502 case MONO_MARSHAL_COPY
: {
3503 mono_mb_emit_ldarg (mb
, i
+1);
3504 if (sig
->params
[i
]->byref
) {
3505 /* make a local copy of the byref parameter. The real parameter
3506 * will be updated after the xdomain call
3508 MonoClass
*pclass
= mono_class_from_mono_type (sig
->params
[i
]);
3509 int copy_local
= mono_mb_add_local (mb
, &(pclass
->byval_arg
));
3510 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3511 mono_mb_emit_stloc (mb
, copy_local
);
3512 mono_mb_emit_ldloc_addr (mb
, copy_local
);
3516 case MONO_MARSHAL_COPY_OUT
:
3517 case MONO_MARSHAL_NONE
:
3518 mono_mb_emit_ldarg (mb
, i
+1);
3523 /* Make the call to the invoke wrapper in the target domain */
3525 xdomain_method
= mono_marshal_get_xappdomain_dispatch (method
, marshal_types
, complex_count
, complex_out_count
, ret_marshal_type
);
3526 mono_marshal_emit_load_domain_method (mb
, xdomain_method
);
3527 mono_mb_emit_calli (mb
, mono_method_signature (xdomain_method
));
3530 mono_mb_emit_stloc (mb
, loc_return
);
3534 mono_mb_emit_ldloc (mb
, loc_old_domainid
);
3535 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3536 mono_marshal_emit_switch_domain (mb
);
3537 mono_mb_emit_byte (mb
, CEE_POP
);
3539 /* Restore thread domain data */
3541 mono_mb_emit_ldloc (mb
, loc_context
);
3542 mono_mb_emit_icall (mb
, mono_context_set
);
3544 /* if (loc_serialized_exc != null) ... */
3546 mono_mb_emit_ldloc (mb
, loc_serialized_exc
);
3547 pos_noex
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3549 mono_mb_emit_ldloc (mb
, loc_serialized_exc
);
3550 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
3551 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
3552 mono_mb_emit_op (mb
, CEE_CASTCLASS
, mono_defaults
.exception_class
);
3553 mono_mb_emit_managed_call (mb
, method_exc_fixexc
, NULL
);
3554 mono_mb_emit_byte (mb
, CEE_THROW
);
3555 mono_mb_patch_short_branch (mb
, pos_noex
);
3557 /* copy back non-serialized output parameters */
3560 for (i
= 0; i
< sig
->param_count
; i
++) {
3561 if (!sig
->params
[i
]->byref
|| marshal_types
[i
] != MONO_MARSHAL_COPY
) continue;
3562 mono_mb_emit_ldarg (mb
, i
+ 1);
3563 mono_mb_emit_ldloc (mb
, copy_locals_base
+ (j
++));
3564 mono_marshal_emit_xdomain_copy_value (mb
, mono_class_from_mono_type (sig
->params
[i
]));
3565 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3568 /* Deserialize out parameters */
3570 if (complex_out_count
> 0) {
3571 mono_mb_emit_ldloc (mb
, loc_serialized_data
);
3572 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
3573 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
3574 mono_mb_emit_stloc (mb
, loc_array
);
3576 /* Copy back output parameters and return type */
3579 for (i
= 0; i
< sig
->param_count
; i
++) {
3580 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
) continue;
3581 if (sig
->params
[i
]->byref
) {
3582 MonoClass
*pclass
= mono_class_from_mono_type (sig
->params
[i
]);
3583 mono_mb_emit_ldarg (mb
, i
+ 1);
3584 mono_mb_emit_ldloc (mb
, loc_array
);
3585 mono_mb_emit_icon (mb
, j
);
3586 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3587 if (pclass
->valuetype
) {
3588 mono_mb_emit_op (mb
, CEE_UNBOX
, pclass
);
3589 mono_mb_emit_op (mb
, CEE_LDOBJ
, pclass
);
3590 mono_mb_emit_op (mb
, CEE_STOBJ
, pclass
);
3592 if (pclass
!= mono_defaults
.object_class
)
3593 mono_mb_emit_op (mb
, CEE_CASTCLASS
, pclass
);
3594 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3600 if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
3601 mono_mb_emit_ldloc (mb
, loc_array
);
3602 mono_mb_emit_icon (mb
, complex_count
);
3603 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3604 if (ret_class
->valuetype
) {
3605 mono_mb_emit_op (mb
, CEE_UNBOX
, ret_class
);
3606 mono_mb_emit_op (mb
, CEE_LDOBJ
, ret_class
);
3609 } else if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
3610 mono_mb_emit_ldloc (mb
, loc_serialized_data
);
3611 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
3612 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
3613 if (ret_class
->valuetype
) {
3614 mono_mb_emit_op (mb
, CEE_UNBOX
, ret_class
);
3615 mono_mb_emit_op (mb
, CEE_LDOBJ
, ret_class
);
3616 } else if (ret_class
!= mono_defaults
.object_class
) {
3617 mono_mb_emit_op (mb
, CEE_CASTCLASS
, ret_class
);
3620 mono_mb_emit_ldloc (mb
, loc_serialized_data
);
3621 mono_mb_emit_byte (mb
, CEE_DUP
);
3622 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3623 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
3625 mono_mb_patch_short_branch (mb
, pos
);
3626 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
3627 mono_mb_emit_byte (mb
, CEE_POP
);
3631 mono_mb_emit_ldloc (mb
, loc_return
);
3632 if (ret_marshal_type
== MONO_MARSHAL_COPY
)
3633 mono_marshal_emit_xdomain_copy_value (mb
, ret_class
);
3636 mono_mb_emit_byte (mb
, CEE_RET
);
3638 res
= mono_remoting_mb_create_and_cache (method
, mb
, sig
, sig
->param_count
+ 16);
3645 mono_marshal_get_remoting_invoke_for_target (MonoMethod
*method
, MonoRemotingTarget target_type
)
3647 if (target_type
== MONO_REMOTING_TARGET_APPDOMAIN
) {
3648 return mono_marshal_get_xappdomain_invoke (method
);
3649 } else if (target_type
== MONO_REMOTING_TARGET_COMINTEROP
) {
3651 return mono_cominterop_get_invoke (method
);
3653 g_assert_not_reached ();
3656 return mono_marshal_get_remoting_invoke (method
);
3662 G_GNUC_UNUSED
static gpointer
3663 mono_marshal_load_remoting_wrapper (MonoRealProxy
*rp
, MonoMethod
*method
)
3665 if (rp
->target_domain_id
!= -1)
3666 return mono_compile_method (mono_marshal_get_xappdomain_invoke (method
));
3668 return mono_compile_method (mono_marshal_get_remoting_invoke (method
));
3672 mono_marshal_get_remoting_invoke_with_check (MonoMethod
*method
)
3674 MonoMethodSignature
*sig
;
3675 MonoMethodBuilder
*mb
;
3676 MonoMethod
*res
, *native
;
3677 int i
, pos
, pos_rem
;
3681 if (method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)
3684 /* we cant remote methods without this pointer */
3685 g_assert (mono_method_signature (method
)->hasthis
);
3687 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)))
3690 sig
= mono_signature_no_pinvoke (method
);
3692 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
);
3694 for (i
= 0; i
<= sig
->param_count
; i
++)
3695 mono_mb_emit_ldarg (mb
, i
);
3697 mono_mb_emit_ldarg (mb
, 0);
3698 pos
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
3700 if (mono_marshal_supports_fast_xdomain (method
)) {
3701 mono_mb_emit_ldarg (mb
, 0);
3702 pos_rem
= mono_mb_emit_xdomain_check (mb
, CEE_BEQ
);
3704 /* wrapper for cross app domain calls */
3705 native
= mono_marshal_get_xappdomain_invoke (method
);
3706 mono_mb_emit_managed_call (mb
, native
, mono_method_signature (native
));
3707 mono_mb_emit_byte (mb
, CEE_RET
);
3709 mono_mb_patch_branch (mb
, pos_rem
);
3711 /* wrapper for normal remote calls */
3712 native
= mono_marshal_get_remoting_invoke (method
);
3713 mono_mb_emit_managed_call (mb
, native
, mono_method_signature (native
));
3714 mono_mb_emit_byte (mb
, CEE_RET
);
3717 mono_mb_patch_branch (mb
, pos
);
3718 mono_mb_emit_managed_call (mb
, method
, mono_method_signature (method
));
3719 mono_mb_emit_byte (mb
, CEE_RET
);
3721 res
= mono_remoting_mb_create_and_cache (method
, mb
, sig
, sig
->param_count
+ 16);
3729 MonoMethodSignature
*sig
;
3731 } SignatureMethodPair
;
3734 signature_method_pair_hash (gconstpointer data
)
3736 SignatureMethodPair
*pair
= (SignatureMethodPair
*)data
;
3738 return mono_signature_hash (pair
->sig
) ^ mono_aligned_addr_hash (pair
->method
);
3742 signature_method_pair_equal (SignatureMethodPair
*pair1
, SignatureMethodPair
*pair2
)
3744 return mono_metadata_signature_equal (pair1
->sig
, pair2
->sig
) && (pair1
->method
== pair2
->method
);
3748 signature_method_pair_matches_method (gpointer key
, gpointer value
, gpointer user_data
)
3750 SignatureMethodPair
*pair
= (SignatureMethodPair
*)key
;
3751 MonoMethod
*method
= (MonoMethod
*)user_data
;
3753 return pair
->method
== method
;
3757 free_signature_method_pair (SignatureMethodPair
*pair
)
3763 * the returned method invokes all methods in a multicast delegate.
3766 mono_marshal_get_delegate_invoke (MonoMethod
*method
, MonoDelegate
*del
)
3768 MonoMethodSignature
*sig
, *static_sig
, *invoke_sig
;
3770 MonoMethodBuilder
*mb
;
3771 MonoMethod
*res
, *newm
;
3773 SignatureMethodPair key
;
3774 SignatureMethodPair
*new_key
;
3775 int local_prev
, local_target
;
3778 MonoMethod
*target_method
= NULL
;
3779 MonoClass
*target_class
= NULL
;
3780 gboolean callvirt
= FALSE
;
3781 gboolean closed_over_null
= FALSE
;
3782 gboolean static_method_with_first_arg_bound
= FALSE
;
3785 * If the delegate target is null, and the target method is not static, a virtual
3786 * call is made to that method with the first delegate argument as this. This is
3787 * a non-documented .NET feature.
3789 if (del
&& !del
->target
&& del
->method
&& mono_method_signature (del
->method
)->hasthis
) {
3791 target_method
= del
->method
;
3792 if (target_method
->is_inflated
) {
3793 MonoType
*target_type
;
3795 g_assert (method
->signature
->hasthis
);
3796 target_type
= mono_class_inflate_generic_type (method
->signature
->params
[0],
3797 mono_method_get_context (method
));
3798 target_class
= mono_class_from_mono_type (target_type
);
3800 target_class
= del
->method
->klass
;
3804 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3805 !strcmp (method
->name
, "Invoke"));
3807 invoke_sig
= sig
= mono_signature_no_pinvoke (method
);
3810 closed_over_null
= sig
->param_count
== mono_method_signature (del
->method
)->param_count
;
3812 if (del
&& del
->method
&& mono_method_signature (del
->method
)->param_count
== sig
->param_count
+ 1 && (del
->method
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
3813 invoke_sig
= mono_method_signature (del
->method
);
3814 target_method
= del
->method
;
3815 static_method_with_first_arg_bound
= TRUE
;
3818 if (callvirt
|| static_method_with_first_arg_bound
) {
3819 GHashTable
**cache_ptr
;
3820 if (static_method_with_first_arg_bound
)
3821 cache_ptr
= &method
->klass
->image
->delegate_bound_static_invoke_cache
;
3823 cache_ptr
= &method
->klass
->image
->delegate_abstract_invoke_cache
;
3825 /* We need to cache the signature+method pair */
3826 mono_marshal_lock ();
3828 *cache_ptr
= g_hash_table_new_full (signature_method_pair_hash
, (GEqualFunc
)signature_method_pair_equal
, (GDestroyNotify
)free_signature_method_pair
, NULL
);
3830 key
.sig
= invoke_sig
;
3831 key
.method
= target_method
;
3832 res
= g_hash_table_lookup (cache
, &key
);
3833 mono_marshal_unlock ();
3837 cache
= get_cache (&method
->klass
->image
->delegate_invoke_cache
,
3838 (GHashFunc
)mono_signature_hash
,
3839 (GCompareFunc
)mono_metadata_signature_equal
);
3840 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
3844 static_sig
= signature_dup (method
->klass
->image
, sig
);
3845 static_sig
->hasthis
= 0;
3846 if (!static_method_with_first_arg_bound
)
3847 invoke_sig
= static_sig
;
3849 name
= mono_signature_to_name (sig
, "invoke");
3850 mb
= mono_mb_new (get_wrapper_target_class (method
->klass
->image
), name
, MONO_WRAPPER_DELEGATE_INVOKE
);
3853 /* allocate local 0 (object) */
3854 local_target
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3855 local_prev
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3857 g_assert (sig
->hasthis
);
3861 * prev.Invoke( args .. );
3862 * return this.<target>( args .. );
3865 /* this wrapper can be used in unmanaged-managed transitions */
3866 emit_thread_interrupt_checkpoint (mb
);
3868 /* get this->prev */
3869 mono_mb_emit_ldarg (mb
, 0);
3870 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoMulticastDelegate
, prev
));
3871 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3872 mono_mb_emit_stloc (mb
, local_prev
);
3873 mono_mb_emit_ldloc (mb
, local_prev
);
3875 /* if prev != null */
3876 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3880 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3881 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
3883 mono_mb_emit_ldloc (mb
, local_prev
);
3884 for (i
= 0; i
< sig
->param_count
; i
++)
3885 mono_mb_emit_ldarg (mb
, i
+ 1);
3886 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
3887 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
3888 mono_mb_emit_byte (mb
, CEE_POP
);
3890 /* continued or prev == null */
3891 mono_mb_patch_branch (mb
, pos0
);
3893 /* get this->target */
3894 mono_mb_emit_ldarg (mb
, 0);
3895 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoDelegate
, target
));
3896 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3897 mono_mb_emit_stloc (mb
, local_target
);
3899 /*static methods with bound first arg can have null target and still be bound*/
3900 if (!static_method_with_first_arg_bound
) {
3901 /* if target != null */
3902 mono_mb_emit_ldloc (mb
, local_target
);
3903 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3905 /* then call this->method_ptr nonstatic */
3908 mono_mb_emit_exception_full (mb
, "System", "NotImplementedException", "");
3910 mono_mb_emit_ldloc (mb
, local_target
);
3911 for (i
= 0; i
< sig
->param_count
; ++i
)
3912 mono_mb_emit_ldarg (mb
, i
+ 1);
3913 mono_mb_emit_ldarg (mb
, 0);
3914 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
3915 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3916 mono_mb_emit_op (mb
, CEE_CALLI
, sig
);
3918 mono_mb_emit_byte (mb
, CEE_RET
);
3921 /* else [target == null] call this->method_ptr static */
3922 mono_mb_patch_branch (mb
, pos0
);
3926 if (!closed_over_null
) {
3927 mono_mb_emit_ldarg (mb
, 1);
3928 mono_mb_emit_op (mb
, CEE_CASTCLASS
, target_class
);
3929 for (i
= 1; i
< sig
->param_count
; ++i
)
3930 mono_mb_emit_ldarg (mb
, i
+ 1);
3931 mono_mb_emit_op (mb
, CEE_CALLVIRT
, target_method
);
3933 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3934 for (i
= 0; i
< sig
->param_count
; ++i
)
3935 mono_mb_emit_ldarg (mb
, i
+ 1);
3936 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3939 if (static_method_with_first_arg_bound
) {
3940 mono_mb_emit_ldloc (mb
, local_target
);
3941 if (!MONO_TYPE_IS_REFERENCE (invoke_sig
->params
[0]))
3942 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type (invoke_sig
->params
[0]));
3944 for (i
= 0; i
< sig
->param_count
; ++i
)
3945 mono_mb_emit_ldarg (mb
, i
+ 1);
3946 mono_mb_emit_ldarg (mb
, 0);
3947 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
3948 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3949 mono_mb_emit_op (mb
, CEE_CALLI
, invoke_sig
);
3952 mono_mb_emit_byte (mb
, CEE_RET
);
3954 if (static_method_with_first_arg_bound
|| callvirt
) {
3955 // From mono_mb_create_and_cache
3956 mb
->skip_visibility
= 1;
3957 newm
= mono_mb_create_method (mb
, sig
, sig
->param_count
+ 16);
3958 /*We perform double checked locking, so must fence before publishing*/
3959 mono_memory_barrier ();
3960 mono_marshal_lock ();
3961 res
= g_hash_table_lookup (cache
, &key
);
3964 new_key
= g_new0 (SignatureMethodPair
, 1);
3966 g_hash_table_insert (cache
, new_key
, res
);
3967 mono_marshal_set_wrapper_info (res
, new_key
);
3968 mono_marshal_unlock ();
3970 mono_marshal_unlock ();
3971 mono_free_method (newm
);
3974 mb
->skip_visibility
= 1;
3975 res
= mono_mb_create_and_cache (cache
, sig
, mb
, sig
, sig
->param_count
+ 16);
3983 * signature_dup_add_this:
3985 * Make a copy of @sig, adding an explicit this argument.
3987 static MonoMethodSignature
*
3988 signature_dup_add_this (MonoMethodSignature
*sig
, MonoClass
*klass
)
3990 MonoMethodSignature
*res
;
3993 res
= mono_metadata_signature_alloc (klass
->image
, sig
->param_count
+ 1);
3994 memcpy (res
, sig
, MONO_SIZEOF_METHOD_SIGNATURE
);
3995 res
->param_count
= sig
->param_count
+ 1;
3996 res
->hasthis
= FALSE
;
3997 for (i
= sig
->param_count
- 1; i
>= 0; i
--)
3998 res
->params
[i
+ 1] = sig
->params
[i
];
3999 res
->params
[0] = &mono_ptr_class_get (&klass
->byval_arg
)->byval_arg
;
4005 MonoMethodSignature
*ctor_sig
;
4006 MonoMethodSignature
*sig
;
4009 /* protected by the marshal lock, contains CtorSigPair pointers */
4010 static GSList
*strsig_list
= NULL
;
4012 static MonoMethodSignature
*
4013 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
4015 MonoMethodSignature
*callsig
;
4019 mono_marshal_lock ();
4021 for (item
= strsig_list
; item
; item
= item
->next
) {
4023 /* mono_metadata_signature_equal () is safe to call with the marshal lock
4024 * because it is lock-free.
4026 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
4031 mono_marshal_unlock ();
4035 static MonoMethodSignature
*
4036 add_string_ctor_signature (MonoMethod
*method
)
4038 MonoMethodSignature
*callsig
;
4041 callsig
= signature_dup (method
->klass
->image
, mono_method_signature (method
));
4042 callsig
->ret
= &mono_defaults
.string_class
->byval_arg
;
4043 cs
= g_new (CtorSigPair
, 1);
4045 cs
->ctor_sig
= mono_method_signature (method
);
4047 mono_marshal_lock ();
4048 strsig_list
= g_slist_prepend (strsig_list
, cs
);
4049 mono_marshal_unlock ();
4054 * mono_marshal_get_string_ctor_signature:
4056 * Return the modified signature used by string ctors (they return the newly created
4059 MonoMethodSignature
*
4060 mono_marshal_get_string_ctor_signature (MonoMethod
*method
)
4062 MonoMethodSignature
*sig
= lookup_string_ctor_signature (mono_method_signature (method
));
4064 sig
= add_string_ctor_signature (method
);
4070 get_runtime_invoke_type (MonoType
*t
, gboolean ret
)
4073 /* Can't share this with 'I' as that needs another indirection */
4076 if (MONO_TYPE_IS_REFERENCE (t
))
4077 return &mono_defaults
.object_class
->byval_arg
;
4080 /* The result needs to be boxed */
4086 return &mono_defaults
.sbyte_class
->byval_arg
;
4088 return &mono_defaults
.int16_class
->byval_arg
;
4090 return &mono_defaults
.int32_class
->byval_arg
;
4092 return &mono_defaults
.int64_class
->byval_arg
;
4093 case MONO_TYPE_BOOLEAN
:
4094 return &mono_defaults
.sbyte_class
->byval_arg
;
4095 case MONO_TYPE_CHAR
:
4096 return &mono_defaults
.int16_class
->byval_arg
;
4099 return &mono_defaults
.int_class
->byval_arg
;
4100 case MONO_TYPE_VALUETYPE
:
4101 if (t
->data
.klass
->enumtype
) {
4102 t
= mono_class_enum_basetype (t
->data
.klass
);
4112 * mono_marshal_get_runtime_invoke_sig:
4114 * Return a common signature used for sharing runtime invoke wrappers.
4116 static MonoMethodSignature
*
4117 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature
*sig
)
4119 MonoMethodSignature
*res
= mono_metadata_signature_dup (sig
);
4122 res
->ret
= get_runtime_invoke_type (sig
->ret
, TRUE
);
4123 for (i
= 0; i
< res
->param_count
; ++i
)
4124 res
->params
[i
] = get_runtime_invoke_type (sig
->params
[i
], FALSE
);
4130 runtime_invoke_signature_equal (MonoMethodSignature
*sig1
, MonoMethodSignature
*sig2
)
4132 /* Can't share wrappers which return a vtype since it needs to be boxed */
4133 if (sig1
->ret
!= sig2
->ret
&& !(MONO_TYPE_IS_REFERENCE (sig1
->ret
) && MONO_TYPE_IS_REFERENCE (sig2
->ret
)) && !mono_metadata_type_equal (sig1
->ret
, sig2
->ret
))
4136 return mono_metadata_signature_equal (sig1
, sig2
);
4142 * Emit the call to the wrapper method from a runtime invoke wrapper.
4145 emit_invoke_call (MonoMethodBuilder
*mb
, MonoMethod
*method
,
4146 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
4148 gboolean
virtual, gboolean need_direct_wrapper
)
4150 static MonoString
*string_dummy
= NULL
;
4152 int *tmp_nullable_locals
;
4153 gboolean void_ret
= FALSE
;
4155 /* to make it work with our special string constructors */
4156 if (!string_dummy
) {
4157 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy
);
4158 string_dummy
= mono_string_new_wrapper ("dummy");
4162 g_assert (sig
->hasthis
);
4163 g_assert (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
);
4167 if (method
->string_ctor
) {
4168 mono_mb_emit_ptr (mb
, string_dummy
);
4170 mono_mb_emit_ldarg (mb
, 0);
4174 tmp_nullable_locals
= g_new0 (int, sig
->param_count
);
4176 for (i
= 0; i
< sig
->param_count
; i
++) {
4177 MonoType
*t
= sig
->params
[i
];
4180 mono_mb_emit_ldarg (mb
, 1);
4182 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
4183 mono_mb_emit_byte (mb
, CEE_ADD
);
4187 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4188 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
4189 * So to make this work we unbox it to a local variablee and push a reference to that.
4191 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
4192 tmp_nullable_locals
[i
] = mono_mb_add_local (mb
, &mono_class_from_mono_type (t
)->byval_arg
);
4194 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type (t
));
4195 mono_mb_emit_stloc (mb
, tmp_nullable_locals
[i
]);
4196 mono_mb_emit_ldloc_addr (mb
, tmp_nullable_locals
[i
]);
4201 /*FIXME 'this doesn't handle generic enums. Shouldn't we?*/
4202 type
= sig
->params
[i
]->type
;
4206 case MONO_TYPE_BOOLEAN
:
4210 case MONO_TYPE_CHAR
:
4219 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4220 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4222 case MONO_TYPE_STRING
:
4223 case MONO_TYPE_CLASS
:
4224 case MONO_TYPE_ARRAY
:
4226 case MONO_TYPE_SZARRAY
:
4227 case MONO_TYPE_OBJECT
:
4228 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4230 case MONO_TYPE_GENERICINST
:
4231 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
4232 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4237 case MONO_TYPE_VALUETYPE
:
4238 if (type
== MONO_TYPE_VALUETYPE
&& t
->data
.klass
->enumtype
) {
4239 type
= mono_class_enum_basetype (t
->data
.klass
)->type
;
4242 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4243 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->params
[i
]))) {
4244 /* Need to convert a boxed vtype to an mp to a Nullable struct */
4245 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (sig
->params
[i
]));
4246 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
4248 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
4252 g_assert_not_reached ();
4257 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4258 } else if (need_direct_wrapper
) {
4259 mono_mb_emit_op (mb
, CEE_CALL
, method
);
4261 mono_mb_emit_ldarg (mb
, 3);
4262 mono_mb_emit_calli (mb
, callsig
);
4265 if (sig
->ret
->byref
) {
4267 g_assert_not_reached ();
4270 switch (sig
->ret
->type
) {
4271 case MONO_TYPE_VOID
:
4272 if (!method
->string_ctor
)
4275 case MONO_TYPE_BOOLEAN
:
4276 case MONO_TYPE_CHAR
:
4289 case MONO_TYPE_VALUETYPE
:
4290 case MONO_TYPE_TYPEDBYREF
:
4291 case MONO_TYPE_GENERICINST
:
4292 /* box value types */
4293 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
4295 case MONO_TYPE_STRING
:
4296 case MONO_TYPE_CLASS
:
4297 case MONO_TYPE_ARRAY
:
4298 case MONO_TYPE_SZARRAY
:
4299 case MONO_TYPE_OBJECT
:
4303 /* The result is an IntPtr */
4304 mono_mb_emit_op (mb
, CEE_BOX
, mono_defaults
.int_class
);
4307 g_assert_not_reached ();
4311 mono_mb_emit_stloc (mb
, loc_res
);
4313 /* Convert back nullable-byref arguments */
4314 for (i
= 0; i
< sig
->param_count
; i
++) {
4315 MonoType
*t
= sig
->params
[i
];
4318 * Box the result and put it back into the array, the caller will have
4319 * to obtain it from there.
4321 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
4322 mono_mb_emit_ldarg (mb
, 1);
4323 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
4324 mono_mb_emit_byte (mb
, CEE_ADD
);
4326 mono_mb_emit_ldloc (mb
, tmp_nullable_locals
[i
]);
4327 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
4329 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4333 g_free (tmp_nullable_locals
);
4337 emit_runtime_invoke_body (MonoMethodBuilder
*mb
, MonoClass
*target_klass
, MonoMethod
*method
,
4338 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
4339 gboolean
virtual, gboolean need_direct_wrapper
)
4342 MonoExceptionClause
*clause
;
4343 int loc_res
, loc_exc
;
4345 /* The wrapper looks like this:
4351 * } catch (Exception e) {
4359 /* allocate local 0 (object) tmp */
4360 loc_res
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4361 /* allocate local 1 (object) exc */
4362 loc_exc
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4364 /* *exc is assumed to be initialized to NULL by the caller */
4366 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4367 labels
[0] = mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4372 labels
[1] = mono_mb_get_label (mb
);
4373 emit_thread_force_interrupt_checkpoint (mb
);
4374 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual, need_direct_wrapper
);
4376 labels
[2] = mono_mb_emit_branch (mb
, CEE_LEAVE
);
4378 /* Add a try clause around the call */
4379 clause
= mono_image_alloc0 (target_klass
->image
, sizeof (MonoExceptionClause
));
4380 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4381 clause
->data
.catch_class
= mono_defaults
.exception_class
;
4382 clause
->try_offset
= labels
[1];
4383 clause
->try_len
= mono_mb_get_label (mb
) - labels
[1];
4385 clause
->handler_offset
= mono_mb_get_label (mb
);
4388 mono_mb_emit_stloc (mb
, loc_exc
);
4389 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4390 mono_mb_emit_ldloc (mb
, loc_exc
);
4391 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4393 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4395 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4397 mono_mb_set_clauses (mb
, 1, clause
);
4399 mono_mb_patch_branch (mb
, labels
[2]);
4400 mono_mb_emit_ldloc (mb
, loc_res
);
4401 mono_mb_emit_byte (mb
, CEE_RET
);
4406 mono_mb_patch_branch (mb
, labels
[0]);
4407 emit_thread_force_interrupt_checkpoint (mb
);
4408 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual, need_direct_wrapper
);
4410 mono_mb_emit_ldloc (mb
, 0);
4411 mono_mb_emit_byte (mb
, CEE_RET
);
4415 * generates IL code for the runtime invoke function
4416 * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
4418 * we also catch exceptions if exc != null
4419 * If VIRTUAL is TRUE, then METHOD is invoked virtually on THIS. This is useful since
4420 * it means that the compiled code for METHOD does not have to be looked up
4421 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
4422 * its METHOD argument.
4425 mono_marshal_get_runtime_invoke (MonoMethod
*method
, gboolean
virtual)
4427 MonoMethodSignature
*sig
, *csig
, *callsig
;
4428 MonoMethodBuilder
*mb
;
4429 GHashTable
*cache
= NULL
;
4430 MonoClass
*target_klass
;
4431 MonoMethod
*res
= NULL
;
4432 static MonoMethodSignature
*cctor_signature
= NULL
;
4433 static MonoMethodSignature
*finalize_signature
= NULL
;
4435 gboolean need_direct_wrapper
= FALSE
;
4439 if (!cctor_signature
) {
4440 cctor_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4441 cctor_signature
->ret
= &mono_defaults
.void_class
->byval_arg
;
4443 if (!finalize_signature
) {
4444 finalize_signature
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4445 finalize_signature
->ret
= &mono_defaults
.void_class
->byval_arg
;
4446 finalize_signature
->hasthis
= 1;
4450 need_direct_wrapper
= TRUE
;
4453 * Use a separate cache indexed by methods to speed things up and to avoid the
4454 * boundless mempool growth caused by the signature_dup stuff below.
4457 cache
= get_cache (&method
->klass
->image
->runtime_invoke_vcall_cache
, mono_aligned_addr_hash
, NULL
);
4459 cache
= get_cache (&method
->klass
->image
->runtime_invoke_direct_cache
, mono_aligned_addr_hash
, NULL
);
4460 res
= mono_marshal_find_in_cache (cache
, method
);
4464 if (method
->klass
->rank
&& (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
4465 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)) {
4467 * Array Get/Set/Address methods. The JIT implements them using inline code
4468 * so we need to create an invoke wrapper which calls the method directly.
4470 need_direct_wrapper
= TRUE
;
4473 if (method
->string_ctor
) {
4474 callsig
= lookup_string_ctor_signature (mono_method_signature (method
));
4476 callsig
= add_string_ctor_signature (method
);
4477 /* Can't share this as we push a string as this */
4478 need_direct_wrapper
= TRUE
;
4480 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
) {
4482 * Valuetype methods receive a managed pointer as the this argument.
4483 * Create a new signature to reflect this.
4485 callsig
= signature_dup_add_this (mono_method_signature (method
), method
->klass
);
4486 /* Can't share this as it would be shared with static methods taking an IntPtr argument */
4487 need_direct_wrapper
= TRUE
;
4489 if (method
->dynamic
)
4490 callsig
= signature_dup (method
->klass
->image
, mono_method_signature (method
));
4492 callsig
= mono_method_signature (method
);
4496 target_klass
= get_wrapper_target_class (method
->klass
->image
);
4498 /* Try to share wrappers for non-corlib methods with simple signatures */
4499 if (mono_metadata_signature_equal (callsig
, cctor_signature
)) {
4500 callsig
= cctor_signature
;
4501 target_klass
= mono_defaults
.object_class
;
4502 } else if (mono_metadata_signature_equal (callsig
, finalize_signature
)) {
4503 callsig
= finalize_signature
;
4504 target_klass
= mono_defaults
.object_class
;
4507 if (need_direct_wrapper
) {
4508 /* Already searched at the start */
4510 MonoMethodSignature
*tmp_sig
;
4512 callsig
= mono_marshal_get_runtime_invoke_sig (callsig
);
4514 cache
= get_cache (&target_klass
->image
->runtime_invoke_cache
,
4515 (GHashFunc
)mono_signature_hash
,
4516 (GCompareFunc
)runtime_invoke_signature_equal
);
4518 /* from mono_marshal_find_in_cache */
4519 mono_marshal_lock ();
4520 res
= g_hash_table_lookup (cache
, callsig
);
4521 mono_marshal_unlock ();
4528 /* Make a copy of the signature from the image mempool */
4530 callsig
= mono_metadata_signature_dup_full (target_klass
->image
, callsig
);
4534 sig
= mono_method_signature (method
);
4536 csig
= mono_metadata_signature_alloc (target_klass
->image
, 4);
4538 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4539 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
)
4540 csig
->params
[0] = callsig
->params
[0];
4542 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4543 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4544 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4545 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4547 name
= mono_signature_to_name (callsig
, virtual ? "runtime_invoke_virtual" : "runtime_invoke");
4548 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4551 emit_runtime_invoke_body (mb
, target_klass
, method
, sig
, callsig
, virtual, need_direct_wrapper
);
4553 if (need_direct_wrapper
) {
4554 mb
->skip_visibility
= 1;
4555 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, sig
->param_count
+ 16);
4557 /* taken from mono_mb_create_and_cache */
4558 mono_marshal_lock ();
4559 res
= g_hash_table_lookup (cache
, callsig
);
4560 mono_marshal_unlock ();
4562 /* Somebody may have created it before us */
4565 newm
= mono_mb_create_method (mb
, csig
, sig
->param_count
+ 16);
4567 mono_marshal_lock ();
4568 res
= g_hash_table_lookup (cache
, callsig
);
4571 g_hash_table_insert (cache
, callsig
, res
);
4572 /* Can't insert it into wrapper_hash since the key is a signature */
4573 g_hash_table_insert (method
->klass
->image
->runtime_invoke_direct_cache
, method
, res
);
4575 mono_free_method (newm
);
4577 mono_marshal_unlock ();
4580 /* end mono_mb_create_and_cache */
4589 * mono_marshal_get_runtime_invoke_dynamic:
4591 * Return a method which can be used to invoke managed methods from native code
4593 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
4594 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
4595 * ARGS should point to an architecture specific structure containing
4596 * the arguments and space for the return value.
4597 * The other arguments are the same as for runtime_invoke (), except that
4598 * ARGS should contain the this argument too.
4599 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
4600 * is only one copy of it, which is useful in full-aot.
4603 mono_marshal_get_runtime_invoke_dynamic (void)
4605 static MonoMethod
*method
;
4606 MonoMethodSignature
*csig
;
4607 MonoExceptionClause
*clause
;
4608 MonoMethodBuilder
*mb
;
4615 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
4617 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
4618 csig
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
4619 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4620 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4621 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4623 name
= g_strdup ("runtime_invoke_dynamic");
4624 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4627 /* allocate local 0 (object) tmp */
4628 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4629 /* allocate local 1 (object) exc */
4630 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4632 /* cond set *exc to null */
4633 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4634 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
4635 mono_mb_emit_byte (mb
, 3);
4636 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4637 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4638 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4640 emit_thread_force_interrupt_checkpoint (mb
);
4642 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
4643 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4644 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4645 mono_mb_emit_byte (mb
, CEE_MONO_DYN_CALL
);
4647 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4649 clause
= mono_image_alloc0 (mono_defaults
.corlib
, sizeof (MonoExceptionClause
));
4650 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
4651 clause
->try_len
= mono_mb_get_label (mb
);
4654 clause
->data
.filter_offset
= mono_mb_get_label (mb
);
4656 mono_mb_emit_byte (mb
, CEE_POP
);
4657 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4658 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
4659 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4660 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
4661 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4662 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
4664 clause
->handler_offset
= mono_mb_get_label (mb
);
4667 /* store exception */
4668 mono_mb_emit_stloc (mb
, 1);
4670 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
4671 mono_mb_emit_ldloc (mb
, 1);
4672 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4674 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4675 mono_mb_emit_stloc (mb
, 0);
4677 /* Check for the abort exception */
4678 mono_mb_emit_ldloc (mb
, 1);
4679 mono_mb_emit_op (mb
, CEE_ISINST
, mono_defaults
.threadabortexception_class
);
4680 posna
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
4682 /* Delay the abort exception */
4683 mono_mb_emit_icall (mb
, ves_icall_System_Threading_Thread_ResetAbort
);
4685 mono_mb_patch_short_branch (mb
, posna
);
4686 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4688 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4690 mono_mb_set_clauses (mb
, 1, clause
);
4693 mono_mb_patch_branch (mb
, pos
);
4694 //mono_mb_emit_ldloc (mb, 0);
4695 mono_mb_emit_byte (mb
, CEE_RET
);
4697 mono_loader_lock ();
4698 /* double-checked locking */
4700 method
= mono_mb_create_method (mb
, csig
, 16);
4702 mono_loader_unlock ();
4710 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
4712 char *msg
= g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
4713 klass
->name_space
, klass
->name
);
4715 mono_mb_emit_exception_marshal_directive (mb
, msg
);
4719 * mono_marshal_get_ldfld_remote_wrapper:
4720 * @klass: The return type
4722 * This method generates a wrapper for calling mono_load_remote_field_new.
4723 * The return type is ignored for now, as mono_load_remote_field_new () always
4724 * returns an object. In the future, to optimize some codepaths, we might
4725 * call a different function that takes a pointer to a valuetype, instead.
4728 mono_marshal_get_ldfld_remote_wrapper (MonoClass
*klass
)
4730 MonoMethodSignature
*sig
, *csig
;
4731 MonoMethodBuilder
*mb
;
4733 static MonoMethod
* cached
= NULL
;
4735 mono_marshal_lock ();
4737 mono_marshal_unlock ();
4740 mono_marshal_unlock ();
4742 mb
= mono_mb_new_no_dup_name (mono_defaults
.object_class
, "__mono_load_remote_field_new_wrapper", MONO_WRAPPER_LDFLD_REMOTE
);
4744 mb
->method
->save_lmf
= 1;
4746 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4747 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4748 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4749 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4750 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4752 mono_mb_emit_ldarg (mb
, 0);
4753 mono_mb_emit_ldarg (mb
, 1);
4754 mono_mb_emit_ldarg (mb
, 2);
4756 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
4757 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4758 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4759 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4760 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4763 mono_mb_emit_native_call (mb
, csig
, mono_load_remote_field_new
);
4764 emit_thread_interrupt_checkpoint (mb
);
4766 mono_mb_emit_byte (mb
, CEE_RET
);
4768 mono_marshal_lock ();
4770 mono_marshal_unlock ();
4773 newm
= mono_mb_create_method (mb
, sig
, 4);
4774 mono_marshal_lock ();
4779 mono_marshal_unlock ();
4781 mono_marshal_unlock ();
4782 mono_free_method (newm
);
4791 * mono_marshal_get_ldfld_wrapper:
4792 * @type: the type of the field
4794 * This method generates a function which can be use to load a field with type
4795 * @type from an object. The generated function has the following signature:
4796 * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
4799 mono_marshal_get_ldfld_wrapper (MonoType
*type
)
4801 MonoMethodSignature
*sig
;
4802 MonoMethodBuilder
*mb
;
4807 int t
, pos0
, pos1
= 0;
4809 type
= mono_type_get_underlying_type (type
);
4814 if (type
->type
== MONO_TYPE_SZARRAY
) {
4815 klass
= mono_defaults
.array_class
;
4816 } else if (type
->type
== MONO_TYPE_VALUETYPE
) {
4817 klass
= type
->data
.klass
;
4818 } else if (t
== MONO_TYPE_OBJECT
|| t
== MONO_TYPE_CLASS
|| t
== MONO_TYPE_STRING
) {
4819 klass
= mono_defaults
.object_class
;
4820 } else if (t
== MONO_TYPE_PTR
|| t
== MONO_TYPE_FNPTR
) {
4821 klass
= mono_defaults
.int_class
;
4822 } else if (t
== MONO_TYPE_GENERICINST
) {
4823 if (mono_type_generic_inst_is_valuetype (type
))
4824 klass
= mono_class_from_mono_type (type
);
4826 klass
= mono_defaults
.object_class
;
4828 klass
= mono_class_from_mono_type (type
);
4831 klass
= mono_defaults
.int_class
;
4834 cache
= get_cache (&klass
->image
->ldfld_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4835 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
4838 /* we add the %p pointer value of klass because class names are not unique */
4839 name
= g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass
, klass
->name_space
, klass
->name
);
4840 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_LDFLD
);
4843 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
4844 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4845 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4846 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4847 sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4848 sig
->ret
= &klass
->byval_arg
;
4850 mono_mb_emit_ldarg (mb
, 0);
4851 pos0
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
4853 mono_mb_emit_ldarg (mb
, 0);
4854 mono_mb_emit_ldarg (mb
, 1);
4855 mono_mb_emit_ldarg (mb
, 2);
4857 mono_mb_emit_managed_call (mb
, mono_marshal_get_ldfld_remote_wrapper (klass
), NULL
);
4860 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
4861 csig->params [0] = &mono_defaults.object_class->byval_arg;
4862 csig->params [1] = &mono_defaults.int_class->byval_arg;
4863 csig->params [2] = &mono_defaults.int_class->byval_arg;
4864 csig->ret = &klass->this_arg;
4867 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
4868 emit_thread_interrupt_checkpoint (mb);
4871 if (klass
->valuetype
) {
4872 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
4873 pos1
= mono_mb_emit_branch (mb
, CEE_BR
);
4875 mono_mb_emit_byte (mb
, CEE_RET
);
4879 mono_mb_patch_branch (mb
, pos0
);
4881 mono_mb_emit_ldarg (mb
, 0);
4882 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4883 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
4884 mono_mb_emit_ldarg (mb
, 3);
4885 mono_mb_emit_byte (mb
, CEE_ADD
);
4887 if (klass
->valuetype
)
4888 mono_mb_patch_branch (mb
, pos1
);
4893 case MONO_TYPE_BOOLEAN
:
4894 case MONO_TYPE_CHAR
:
4903 case MONO_TYPE_ARRAY
:
4904 case MONO_TYPE_SZARRAY
:
4905 case MONO_TYPE_OBJECT
:
4906 case MONO_TYPE_CLASS
:
4907 case MONO_TYPE_STRING
:
4911 case MONO_TYPE_FNPTR
:
4912 mono_mb_emit_byte (mb
, mono_type_to_ldind (type
));
4914 case MONO_TYPE_VALUETYPE
:
4915 g_assert (!klass
->enumtype
);
4916 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
4918 case MONO_TYPE_GENERICINST
:
4919 if (mono_type_generic_inst_is_valuetype (type
)) {
4920 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
4922 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4926 g_warning ("type %x not implemented", type
->type
);
4927 g_assert_not_reached ();
4930 mono_mb_emit_byte (mb
, CEE_RET
);
4932 res
= mono_mb_create_and_cache (cache
, klass
,
4933 mb
, sig
, sig
->param_count
+ 16);
4940 * mono_marshal_get_ldflda_wrapper:
4941 * @type: the type of the field
4943 * This method generates a function which can be used to load a field address
4944 * from an object. The generated function has the following signature:
4945 * gpointer ldflda_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset);
4948 mono_marshal_get_ldflda_wrapper (MonoType
*type
)
4950 MonoMethodSignature
*sig
;
4951 MonoMethodBuilder
*mb
;
4956 int t
, pos0
, pos1
, pos2
, pos3
;
4958 type
= mono_type_get_underlying_type (type
);
4962 if (type
->type
== MONO_TYPE_SZARRAY
) {
4963 klass
= mono_defaults
.array_class
;
4964 } else if (type
->type
== MONO_TYPE_VALUETYPE
) {
4965 klass
= type
->data
.klass
;
4966 } else if (t
== MONO_TYPE_OBJECT
|| t
== MONO_TYPE_CLASS
|| t
== MONO_TYPE_STRING
||
4967 t
== MONO_TYPE_CLASS
) {
4968 klass
= mono_defaults
.object_class
;
4969 } else if (t
== MONO_TYPE_PTR
|| t
== MONO_TYPE_FNPTR
) {
4970 klass
= mono_defaults
.int_class
;
4971 } else if (t
== MONO_TYPE_GENERICINST
) {
4972 if (mono_type_generic_inst_is_valuetype (type
))
4973 klass
= mono_class_from_mono_type (type
);
4975 klass
= mono_defaults
.object_class
;
4977 klass
= mono_class_from_mono_type (type
);
4980 klass
= mono_defaults
.int_class
;
4983 cache
= get_cache (&klass
->image
->ldflda_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
4984 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
4987 /* we add the %p pointer value of klass because class names are not unique */
4988 name
= g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass
, klass
->name_space
, klass
->name
);
4989 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_LDFLDA
);
4992 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
4993 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4994 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4995 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4996 sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4997 sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
4999 /* if typeof (this) != transparent_proxy goto pos0 */
5000 mono_mb_emit_ldarg (mb
, 0);
5001 pos0
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
5003 /* if same_appdomain goto pos1 */
5004 mono_mb_emit_ldarg (mb
, 0);
5005 pos1
= mono_mb_emit_xdomain_check (mb
, CEE_BEQ
);
5007 mono_mb_emit_exception_full (mb
, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain.");
5009 /* same app domain */
5010 mono_mb_patch_branch (mb
, pos1
);
5012 /* if typeof (this) != contextbound goto pos2 */
5013 mono_mb_emit_ldarg (mb
, 0);
5014 pos2
= mono_mb_emit_contextbound_check (mb
, CEE_BEQ
);
5016 /* if this->rp->context == mono_context_get goto pos3 */
5017 mono_mb_emit_ldarg (mb
, 0);
5018 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
5019 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5020 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRealProxy
, context
));
5021 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5022 mono_mb_emit_icall (mb
, mono_context_get
);
5023 pos3
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5025 mono_mb_emit_exception_full (mb
, "System", "InvalidOperationException", "Attempt to load field address from object in another context.");
5027 mono_mb_patch_branch (mb
, pos2
);
5028 mono_mb_patch_branch (mb
, pos3
);
5030 /* return the address of the field from this->rp->unwrapped_server */
5031 mono_mb_emit_ldarg (mb
, 0);
5032 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
5033 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5034 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRealProxy
, unwrapped_server
));
5035 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5036 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5037 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5038 mono_mb_emit_ldarg (mb
, 3);
5039 mono_mb_emit_byte (mb
, CEE_ADD
);
5040 mono_mb_emit_byte (mb
, CEE_RET
);
5042 /* not a proxy: return the address of the field directly */
5043 mono_mb_patch_branch (mb
, pos0
);
5045 mono_mb_emit_ldarg (mb
, 0);
5046 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5047 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5048 mono_mb_emit_ldarg (mb
, 3);
5049 mono_mb_emit_byte (mb
, CEE_ADD
);
5051 mono_mb_emit_byte (mb
, CEE_RET
);
5053 res
= mono_mb_create_and_cache (cache
, klass
,
5054 mb
, sig
, sig
->param_count
+ 16);
5061 * mono_marshal_get_stfld_remote_wrapper:
5062 * klass: The type of the field
5064 * This function generates a wrapper for calling mono_store_remote_field_new
5065 * with the appropriate signature.
5066 * Similarly to mono_marshal_get_ldfld_remote_wrapper () this doesn't depend on the
5067 * klass argument anymore.
5070 mono_marshal_get_stfld_remote_wrapper (MonoClass
*klass
)
5072 MonoMethodSignature
*sig
, *csig
;
5073 MonoMethodBuilder
*mb
;
5075 static MonoMethod
*cached
= NULL
;
5077 mono_marshal_lock ();
5079 mono_marshal_unlock ();
5082 mono_marshal_unlock ();
5084 mb
= mono_mb_new_no_dup_name (mono_defaults
.object_class
, "__mono_store_remote_field_new_wrapper", MONO_WRAPPER_STFLD_REMOTE
);
5086 mb
->method
->save_lmf
= 1;
5088 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
5089 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5090 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5091 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5092 sig
->params
[3] = &mono_defaults
.object_class
->byval_arg
;
5093 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
5095 mono_mb_emit_ldarg (mb
, 0);
5096 mono_mb_emit_ldarg (mb
, 1);
5097 mono_mb_emit_ldarg (mb
, 2);
5098 mono_mb_emit_ldarg (mb
, 3);
5100 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
5101 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5102 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5103 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5104 csig
->params
[3] = &mono_defaults
.object_class
->byval_arg
;
5105 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
5108 mono_mb_emit_native_call (mb
, csig
, mono_store_remote_field_new
);
5109 emit_thread_interrupt_checkpoint (mb
);
5111 mono_mb_emit_byte (mb
, CEE_RET
);
5113 mono_marshal_lock ();
5115 mono_marshal_unlock ();
5118 newm
= mono_mb_create_method (mb
, sig
, 6);
5119 mono_marshal_lock ();
5124 mono_marshal_unlock ();
5126 mono_marshal_unlock ();
5127 mono_free_method (newm
);
5136 * mono_marshal_get_stfld_wrapper:
5137 * @type: the type of the field
5139 * This method generates a function which can be use to store a field with type
5140 * @type. The generated function has the following signature:
5141 * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
5144 mono_marshal_get_stfld_wrapper (MonoType
*type
)
5146 MonoMethodSignature
*sig
;
5147 MonoMethodBuilder
*mb
;
5154 type
= mono_type_get_underlying_type (type
);
5158 if (type
->type
== MONO_TYPE_SZARRAY
) {
5159 klass
= mono_defaults
.array_class
;
5160 } else if (type
->type
== MONO_TYPE_VALUETYPE
) {
5161 klass
= type
->data
.klass
;
5162 } else if (t
== MONO_TYPE_OBJECT
|| t
== MONO_TYPE_CLASS
|| t
== MONO_TYPE_STRING
) {
5163 klass
= mono_defaults
.object_class
;
5164 } else if (t
== MONO_TYPE_PTR
|| t
== MONO_TYPE_FNPTR
) {
5165 klass
= mono_defaults
.int_class
;
5166 } else if (t
== MONO_TYPE_GENERICINST
) {
5167 if (mono_type_generic_inst_is_valuetype (type
))
5168 klass
= mono_class_from_mono_type (type
);
5170 klass
= mono_defaults
.object_class
;
5172 klass
= mono_class_from_mono_type (type
);
5175 klass
= mono_defaults
.int_class
;
5178 cache
= get_cache (&klass
->image
->stfld_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
5179 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
5182 /* we add the %p pointer value of klass because class names are not unique */
5183 name
= g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass
, klass
->name_space
, klass
->name
);
5184 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STFLD
);
5187 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 5);
5188 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5189 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5190 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5191 sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
5192 sig
->params
[4] = &klass
->byval_arg
;
5193 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
5195 mono_mb_emit_ldarg (mb
, 0);
5196 pos
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
5198 mono_mb_emit_ldarg (mb
, 0);
5199 mono_mb_emit_ldarg (mb
, 1);
5200 mono_mb_emit_ldarg (mb
, 2);
5201 mono_mb_emit_ldarg (mb
, 4);
5202 if (klass
->valuetype
)
5203 mono_mb_emit_op (mb
, CEE_BOX
, klass
);
5205 mono_mb_emit_managed_call (mb
, mono_marshal_get_stfld_remote_wrapper (klass
), NULL
);
5207 mono_mb_emit_byte (mb
, CEE_RET
);
5209 mono_mb_patch_branch (mb
, pos
);
5211 mono_mb_emit_ldarg (mb
, 0);
5212 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5213 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5214 mono_mb_emit_ldarg (mb
, 3);
5215 mono_mb_emit_byte (mb
, CEE_ADD
);
5216 mono_mb_emit_ldarg (mb
, 4);
5221 case MONO_TYPE_BOOLEAN
:
5222 case MONO_TYPE_CHAR
:
5231 case MONO_TYPE_ARRAY
:
5232 case MONO_TYPE_SZARRAY
:
5233 case MONO_TYPE_OBJECT
:
5234 case MONO_TYPE_CLASS
:
5235 case MONO_TYPE_STRING
:
5239 case MONO_TYPE_FNPTR
:
5240 mono_mb_emit_byte (mb
, mono_type_to_stind (type
));
5242 case MONO_TYPE_VALUETYPE
:
5243 g_assert (!klass
->enumtype
);
5244 mono_mb_emit_op (mb
, CEE_STOBJ
, klass
);
5246 case MONO_TYPE_GENERICINST
:
5247 mono_mb_emit_op (mb
, CEE_STOBJ
, klass
);
5250 g_warning ("type %x not implemented", type
->type
);
5251 g_assert_not_reached ();
5254 mono_mb_emit_byte (mb
, CEE_RET
);
5256 res
= mono_mb_create_and_cache (cache
, klass
,
5257 mb
, sig
, sig
->param_count
+ 16);
5264 * generates IL code for the icall wrapper (the generated method
5265 * calls the unmanaged code in func)
5268 mono_marshal_get_icall_wrapper (MonoMethodSignature
*sig
, const char *name
, gconstpointer func
, gboolean check_exceptions
)
5270 MonoMethodSignature
*csig
, *csig2
;
5271 MonoMethodBuilder
*mb
;
5275 g_assert (sig
->pinvoke
);
5277 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
5279 mb
->method
->save_lmf
= 1;
5281 /* Add an explicit this argument */
5283 csig2
= signature_dup_add_this (sig
, mono_defaults
.object_class
);
5285 csig2
= signature_dup (mono_defaults
.corlib
, sig
);
5288 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
5290 for (i
= 0; i
< sig
->param_count
; i
++)
5291 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
5293 mono_mb_emit_native_call (mb
, csig2
, (gpointer
) func
);
5294 if (check_exceptions
)
5295 emit_thread_interrupt_checkpoint (mb
);
5296 mono_mb_emit_byte (mb
, CEE_RET
);
5298 csig
= signature_dup (mono_defaults
.corlib
, sig
);
5300 if (csig
->call_convention
== MONO_CALL_VARARG
)
5301 csig
->call_convention
= 0;
5303 res
= mono_mb_create_method (mb
, csig
, csig
->param_count
+ 16);
5310 emit_marshal_custom (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5311 MonoMarshalSpec
*spec
,
5312 int conv_arg
, MonoType
**conv_arg_type
,
5313 MarshalAction action
)
5317 static MonoClass
*ICustomMarshaler
= NULL
;
5318 static MonoMethod
*cleanup_native
, *cleanup_managed
;
5319 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
5320 MonoMethod
*get_instance
;
5321 MonoMethodBuilder
*mb
= m
->mb
;
5322 char *exception_msg
= NULL
;
5326 if (!ICustomMarshaler
) {
5327 ICustomMarshaler
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "ICustomMarshaler");
5328 g_assert (ICustomMarshaler
);
5330 cleanup_native
= mono_class_get_method_from_name (ICustomMarshaler
, "CleanUpNativeData", 1);
5331 g_assert (cleanup_native
);
5332 cleanup_managed
= mono_class_get_method_from_name (ICustomMarshaler
, "CleanUpManagedData", 1);
5333 g_assert (cleanup_managed
);
5334 marshal_managed_to_native
= mono_class_get_method_from_name (ICustomMarshaler
, "MarshalManagedToNative", 1);
5335 g_assert (marshal_managed_to_native
);
5336 marshal_native_to_managed
= mono_class_get_method_from_name (ICustomMarshaler
, "MarshalNativeToManaged", 1);
5337 g_assert (marshal_native_to_managed
);
5340 mtype
= mono_reflection_type_from_name (spec
->data
.custom_data
.custom_name
, m
->image
);
5341 g_assert (mtype
!= NULL
);
5342 mklass
= mono_class_from_mono_type (mtype
);
5343 g_assert (mklass
!= NULL
);
5345 if (!mono_class_is_assignable_from (ICustomMarshaler
, mklass
))
5346 exception_msg
= g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass
->name
);
5348 get_instance
= mono_class_get_method_from_name_flags (mklass
, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC
);
5350 MonoMethodSignature
*get_sig
= mono_method_signature (get_instance
);
5351 if ((get_sig
->ret
->type
!= MONO_TYPE_CLASS
) ||
5352 (mono_class_from_mono_type (get_sig
->ret
) != ICustomMarshaler
) ||
5353 (get_sig
->params
[0]->type
!= MONO_TYPE_STRING
))
5354 get_instance
= NULL
;
5358 exception_msg
= g_strdup_printf ("Custom marshaler '%s' does not implement a static GetInstance method that takes a single string parameter and returns an ICustomMarshaler.", mklass
->name
);
5360 /* Throw exception and emit compensation code if neccesary */
5361 if (exception_msg
) {
5363 case MARSHAL_ACTION_CONV_IN
:
5364 case MARSHAL_ACTION_CONV_RESULT
:
5365 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5366 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
5367 mono_mb_emit_byte (mb
, CEE_POP
);
5369 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
5370 g_free (exception_msg
);
5373 case MARSHAL_ACTION_PUSH
:
5374 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5382 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
5383 /* FIXME: MS.NET throws an exception if GetInstance returns null */
5386 case MARSHAL_ACTION_CONV_IN
:
5388 case MONO_TYPE_CLASS
:
5389 case MONO_TYPE_OBJECT
:
5390 case MONO_TYPE_STRING
:
5391 case MONO_TYPE_ARRAY
:
5392 case MONO_TYPE_SZARRAY
:
5393 case MONO_TYPE_VALUETYPE
:
5397 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
5398 g_assert_not_reached ();
5402 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5404 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5405 mono_mb_emit_stloc (mb
, conv_arg
);
5407 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5410 /* Minic MS.NET behavior */
5411 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
5414 /* Check for null */
5415 mono_mb_emit_ldarg (mb
, argnum
);
5417 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5418 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5420 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5422 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5424 mono_mb_emit_ldarg (mb
, argnum
);
5426 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5428 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5430 * Since we can't determine the type of the argument, we
5431 * will assume the unmanaged function takes a pointer.
5433 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5435 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
5438 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
5439 mono_mb_emit_stloc (mb
, conv_arg
);
5441 mono_mb_patch_branch (mb
, pos2
);
5444 case MARSHAL_ACTION_CONV_OUT
:
5445 /* Check for null */
5446 mono_mb_emit_ldloc (mb
, conv_arg
);
5447 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5450 mono_mb_emit_ldarg (mb
, argnum
);
5452 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5454 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5456 mono_mb_emit_ldloc (mb
, conv_arg
);
5457 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5458 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5459 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
5460 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5462 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5464 mono_mb_emit_ldloc (mb
, conv_arg
);
5465 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5467 /* We have nowhere to store the result */
5468 mono_mb_emit_byte (mb
, CEE_POP
);
5471 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5473 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5475 mono_mb_emit_ldloc (mb
, conv_arg
);
5477 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
5479 mono_mb_patch_branch (mb
, pos2
);
5482 case MARSHAL_ACTION_PUSH
:
5484 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5486 mono_mb_emit_ldloc (mb
, conv_arg
);
5489 case MARSHAL_ACTION_CONV_RESULT
:
5490 loc1
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5492 mono_mb_emit_stloc (mb
, 3);
5494 mono_mb_emit_ldloc (mb
, 3);
5495 mono_mb_emit_stloc (mb
, loc1
);
5497 /* Check for null */
5498 mono_mb_emit_ldloc (mb
, 3);
5499 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5501 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5503 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5504 mono_mb_emit_byte (mb
, CEE_DUP
);
5506 mono_mb_emit_ldloc (mb
, 3);
5507 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5508 mono_mb_emit_stloc (mb
, 3);
5510 mono_mb_emit_ldloc (mb
, loc1
);
5511 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
5513 mono_mb_patch_branch (mb
, pos2
);
5516 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5517 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
5519 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5520 mono_mb_emit_stloc (mb
, conv_arg
);
5522 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5525 /* Check for null */
5526 mono_mb_emit_ldarg (mb
, argnum
);
5528 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5529 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5531 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5532 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5534 mono_mb_emit_ldarg (mb
, argnum
);
5536 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5538 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5539 mono_mb_emit_stloc (mb
, conv_arg
);
5541 mono_mb_patch_branch (mb
, pos2
);
5544 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5545 g_assert (!t
->byref
);
5547 loc1
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
5549 mono_mb_emit_stloc (mb
, 3);
5551 mono_mb_emit_ldloc (mb
, 3);
5552 mono_mb_emit_stloc (mb
, loc1
);
5554 /* Check for null */
5555 mono_mb_emit_ldloc (mb
, 3);
5556 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5558 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5559 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5560 mono_mb_emit_byte (mb
, CEE_DUP
);
5562 mono_mb_emit_ldloc (mb
, 3);
5563 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
5564 mono_mb_emit_stloc (mb
, 3);
5566 mono_mb_emit_ldloc (mb
, loc1
);
5567 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
5569 mono_mb_patch_branch (mb
, pos2
);
5572 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5574 /* Check for null */
5575 mono_mb_emit_ldloc (mb
, conv_arg
);
5576 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5579 mono_mb_emit_ldarg (mb
, argnum
);
5581 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5583 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5585 mono_mb_emit_ldloc (mb
, conv_arg
);
5586 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
5587 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5590 /* Call CleanUpManagedData */
5591 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5593 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5595 mono_mb_emit_ldloc (mb
, conv_arg
);
5596 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
5598 mono_mb_patch_branch (mb
, pos2
);
5602 g_assert_not_reached ();
5609 emit_marshal_asany (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5610 MonoMarshalSpec
*spec
,
5611 int conv_arg
, MonoType
**conv_arg_type
,
5612 MarshalAction action
)
5614 MonoMethodBuilder
*mb
= m
->mb
;
5617 case MARSHAL_ACTION_CONV_IN
: {
5618 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
5620 g_assert (t
->type
== MONO_TYPE_OBJECT
);
5621 g_assert (!t
->byref
);
5623 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5624 mono_mb_emit_ldarg (mb
, argnum
);
5625 mono_mb_emit_icon (mb
, encoding
);
5626 mono_mb_emit_icon (mb
, t
->attrs
);
5627 mono_mb_emit_icall (mb
, mono_marshal_asany
);
5628 mono_mb_emit_stloc (mb
, conv_arg
);
5632 case MARSHAL_ACTION_PUSH
:
5633 mono_mb_emit_ldloc (mb
, conv_arg
);
5636 case MARSHAL_ACTION_CONV_OUT
: {
5637 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
5639 mono_mb_emit_ldarg (mb
, argnum
);
5640 mono_mb_emit_ldloc (mb
, conv_arg
);
5641 mono_mb_emit_icon (mb
, encoding
);
5642 mono_mb_emit_icon (mb
, t
->attrs
);
5643 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
5648 g_assert_not_reached ();
5655 emit_marshal_vtype (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5656 MonoMarshalSpec
*spec
,
5657 int conv_arg
, MonoType
**conv_arg_type
,
5658 MarshalAction action
)
5660 MonoMethodBuilder
*mb
= m
->mb
;
5661 MonoClass
*klass
, *date_time_class
;
5664 klass
= mono_class_from_mono_type (t
);
5666 date_time_class
= mono_class_from_name_cached (mono_defaults
.corlib
, "System", "DateTime");
5669 case MARSHAL_ACTION_CONV_IN
:
5670 if (klass
== date_time_class
) {
5671 /* Convert it to an OLE DATE type */
5672 static MonoMethod
*to_oadate
;
5675 to_oadate
= mono_class_get_method_from_name (date_time_class
, "ToOADate", 0);
5676 g_assert (to_oadate
);
5678 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.double_class
->byval_arg
);
5681 mono_mb_emit_ldarg (mb
, argnum
);
5682 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5685 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5687 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.double_class
->byval_arg
;
5689 mono_mb_emit_ldarg_addr (mb
, argnum
);
5690 mono_mb_emit_managed_call (mb
, to_oadate
, NULL
);
5691 mono_mb_emit_stloc (mb
, conv_arg
);
5695 mono_mb_patch_branch (mb
, pos
);
5699 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5700 klass
->blittable
|| klass
->enumtype
)
5703 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5705 /* store the address of the source into local variable 0 */
5707 mono_mb_emit_ldarg (mb
, argnum
);
5709 mono_mb_emit_ldarg_addr (mb
, argnum
);
5711 mono_mb_emit_stloc (mb
, 0);
5713 /* allocate space for the native struct and
5714 * store the address into local variable 1 (dest) */
5715 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5716 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5717 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5718 mono_mb_emit_stloc (mb
, conv_arg
);
5721 mono_mb_emit_ldloc (mb
, 0);
5722 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5725 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5727 mono_mb_emit_ldloc (mb
, conv_arg
);
5728 mono_mb_emit_stloc (mb
, 1);
5730 /* emit valuetype conversion code */
5731 emit_struct_conv (mb
, klass
, FALSE
);
5735 mono_mb_patch_branch (mb
, pos
);
5738 case MARSHAL_ACTION_PUSH
:
5739 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
5741 g_assert (!t
->byref
);
5743 /* Have to change the signature since the vtype is passed byref */
5744 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.int_class
->byval_arg
;
5746 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5747 klass
->blittable
|| klass
->enumtype
)
5748 mono_mb_emit_ldarg_addr (mb
, argnum
);
5750 mono_mb_emit_ldloc (mb
, conv_arg
);
5754 if (klass
== date_time_class
) {
5756 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5758 mono_mb_emit_ldloc (mb
, conv_arg
);
5762 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5763 klass
->blittable
|| klass
->enumtype
) {
5764 mono_mb_emit_ldarg (mb
, argnum
);
5767 mono_mb_emit_ldloc (mb
, conv_arg
);
5769 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5770 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
5774 case MARSHAL_ACTION_CONV_OUT
:
5775 if (klass
== date_time_class
) {
5776 /* Convert from an OLE DATE type */
5777 static MonoMethod
*from_oadate
;
5782 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5784 from_oadate
= mono_class_get_method_from_name (date_time_class
, "FromOADate", 1);
5785 g_assert (from_oadate
);
5787 mono_mb_emit_ldarg (mb
, argnum
);
5788 mono_mb_emit_ldloc (mb
, conv_arg
);
5789 mono_mb_emit_managed_call (mb
, from_oadate
, NULL
);
5790 mono_mb_emit_op (mb
, CEE_STOBJ
, date_time_class
);
5795 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5796 klass
->blittable
|| klass
->enumtype
)
5800 /* dst = argument */
5801 mono_mb_emit_ldarg (mb
, argnum
);
5802 mono_mb_emit_stloc (mb
, 1);
5804 mono_mb_emit_ldloc (mb
, 1);
5805 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5807 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5808 /* src = tmp_locals [i] */
5809 mono_mb_emit_ldloc (mb
, conv_arg
);
5810 mono_mb_emit_stloc (mb
, 0);
5812 /* emit valuetype conversion code */
5813 emit_struct_conv (mb
, klass
, TRUE
);
5817 emit_struct_free (mb
, klass
, conv_arg
);
5820 mono_mb_patch_branch (mb
, pos
);
5823 case MARSHAL_ACTION_CONV_RESULT
:
5824 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5826 mono_mb_emit_stloc (mb
, 3);
5830 /* load pointer to returned value type */
5831 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5832 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
5833 /* store the address of the source into local variable 0 */
5834 mono_mb_emit_stloc (mb
, 0);
5836 mono_mb_emit_ldloc_addr (mb
, 3);
5837 mono_mb_emit_stloc (mb
, 1);
5839 /* emit valuetype conversion code */
5840 emit_struct_conv (mb
, klass
, TRUE
);
5843 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5844 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5845 klass
->blittable
|| klass
->enumtype
) {
5850 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
5852 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5856 mono_mb_emit_ldarg (mb
, argnum
);
5858 mono_mb_emit_ldarg_addr (mb
, argnum
);
5859 mono_mb_emit_stloc (mb
, 0);
5862 mono_mb_emit_ldloc (mb
, 0);
5863 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5866 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5867 mono_mb_emit_stloc (mb
, 1);
5869 /* emit valuetype conversion code */
5870 emit_struct_conv (mb
, klass
, TRUE
);
5873 mono_mb_patch_branch (mb
, pos
);
5876 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5877 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5878 klass
->blittable
|| klass
->enumtype
) {
5882 /* Check for null */
5883 mono_mb_emit_ldarg (mb
, argnum
);
5884 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5887 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5888 mono_mb_emit_stloc (mb
, 0);
5891 mono_mb_emit_ldarg (mb
, argnum
);
5892 mono_mb_emit_stloc (mb
, 1);
5894 /* emit valuetype conversion code */
5895 emit_struct_conv (mb
, klass
, FALSE
);
5897 mono_mb_patch_branch (mb
, pos2
);
5900 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5901 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
5902 klass
->blittable
|| klass
->enumtype
) {
5903 mono_mb_emit_stloc (mb
, 3);
5908 /* load pointer to returned value type */
5909 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5910 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
5912 /* store the address of the source into local variable 0 */
5913 mono_mb_emit_stloc (mb
, 0);
5914 /* allocate space for the native struct and
5915 * store the address into dst_ptr */
5916 m
->retobj_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5917 m
->retobj_class
= klass
;
5918 g_assert (m
->retobj_var
);
5919 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5920 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5921 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
5922 mono_mb_emit_stloc (mb
, 1);
5923 mono_mb_emit_ldloc (mb
, 1);
5924 mono_mb_emit_stloc (mb
, m
->retobj_var
);
5926 /* emit valuetype conversion code */
5927 emit_struct_conv (mb
, klass
, FALSE
);
5931 g_assert_not_reached ();
5938 emit_marshal_string (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5939 MonoMarshalSpec
*spec
,
5940 int conv_arg
, MonoType
**conv_arg_type
,
5941 MarshalAction action
)
5943 MonoMethodBuilder
*mb
= m
->mb
;
5944 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5945 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
5949 case MARSHAL_ACTION_CONV_IN
:
5950 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5951 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5954 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5957 mono_mb_emit_ldarg (mb
, argnum
);
5958 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5960 mono_mb_emit_ldarg (mb
, argnum
);
5964 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5965 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
5966 g_warning ("%s", msg
);
5968 mono_raise_exception (exc
);
5971 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
5973 mono_mb_emit_stloc (mb
, conv_arg
);
5976 case MARSHAL_ACTION_CONV_OUT
:
5977 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5979 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5980 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5984 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5985 mono_mb_emit_ldarg (mb
, argnum
);
5986 mono_mb_emit_ldloc (mb
, conv_arg
);
5987 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
5988 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5991 if (need_free
|| (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5992 mono_mb_emit_ldloc (mb
, conv_arg
);
5993 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5994 mono_mb_emit_icall (mb
, mono_free_bstr
);
5996 mono_mb_emit_icall (mb
, mono_marshal_free
);
6000 case MARSHAL_ACTION_PUSH
:
6002 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6004 mono_mb_emit_ldloc (mb
, conv_arg
);
6007 case MARSHAL_ACTION_CONV_RESULT
:
6008 mono_mb_emit_stloc (mb
, 0);
6010 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
6012 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
6013 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6017 mono_mb_emit_ldloc (mb
, 0);
6018 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6019 mono_mb_emit_stloc (mb
, 3);
6021 /* free the string */
6022 mono_mb_emit_ldloc (mb
, 0);
6023 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
6024 mono_mb_emit_icall (mb
, mono_free_bstr
);
6026 mono_mb_emit_icall (mb
, mono_marshal_free
);
6029 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6030 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6032 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6034 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
6036 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
6037 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6041 mono_mb_emit_ldarg (mb
, argnum
);
6043 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6044 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6045 mono_mb_emit_stloc (mb
, conv_arg
);
6048 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6051 mono_mb_emit_ldarg (mb
, argnum
);
6052 mono_mb_emit_ldloc (mb
, conv_arg
);
6053 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6054 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6059 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6060 if (conv_to_icall (conv
) == mono_marshal_string_to_utf16
)
6061 /* We need to make a copy so the caller is able to free it */
6062 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
6064 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6065 mono_mb_emit_stloc (mb
, 3);
6069 g_assert_not_reached ();
6076 emit_marshal_safehandle (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6077 MonoMarshalSpec
*spec
, int conv_arg
,
6078 MonoType
**conv_arg_type
, MarshalAction action
)
6080 MonoMethodBuilder
*mb
= m
->mb
;
6083 case MARSHAL_ACTION_CONV_IN
: {
6084 MonoType
*intptr_type
;
6085 int dar_release_slot
, pos
;
6087 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
6088 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
6089 *conv_arg_type
= intptr_type
;
6091 if (!sh_dangerous_add_ref
)
6092 init_safe_handle ();
6094 mono_mb_emit_ldarg (mb
, argnum
);
6095 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6096 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
6098 mono_mb_patch_branch (mb
, pos
);
6101 * My tests in show that ref SafeHandles are not really
6102 * passed as ref objects. Instead a NULL is passed as the
6105 mono_mb_emit_icon (mb
, 0);
6106 mono_mb_emit_stloc (mb
, conv_arg
);
6110 /* Create local to hold the ref parameter to DangerousAddRef */
6111 dar_release_slot
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
6113 /* set release = false; */
6114 mono_mb_emit_icon (mb
, 0);
6115 mono_mb_emit_stloc (mb
, dar_release_slot
);
6117 /* safehandle.DangerousAddRef (ref release) */
6118 mono_mb_emit_ldarg (mb
, argnum
);
6119 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
6120 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
6122 /* Pull the handle field from SafeHandle */
6123 mono_mb_emit_ldarg (mb
, argnum
);
6124 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
6125 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6126 mono_mb_emit_stloc (mb
, conv_arg
);
6131 case MARSHAL_ACTION_PUSH
:
6133 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6135 mono_mb_emit_ldloc (mb
, conv_arg
);
6138 case MARSHAL_ACTION_CONV_OUT
: {
6139 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
6140 int dar_release_slot
= conv_arg
+ 1;
6143 if (!sh_dangerous_release
)
6144 init_safe_handle ();
6150 * My tests indicate that ref SafeHandles parameters are not actually
6151 * passed by ref, but instead a new Handle is created regardless of
6152 * whether a change happens in the unmanaged side.
6154 * Also, the Handle is created before calling into unmanaged code,
6155 * but we do not support that mechanism (getting to the original
6156 * handle) and it makes no difference where we create this
6158 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
6160 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
6163 /* refval = new SafeHandleDerived ()*/
6164 mono_mb_emit_ldarg (mb
, argnum
);
6165 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
6166 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6168 /* refval.handle = returned_handle */
6169 mono_mb_emit_ldarg (mb
, argnum
);
6170 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6171 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
6172 mono_mb_emit_ldloc (mb
, conv_arg
);
6173 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6175 mono_mb_emit_ldloc (mb
, dar_release_slot
);
6176 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6177 mono_mb_emit_ldarg (mb
, argnum
);
6178 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
6179 mono_mb_patch_branch (mb
, label_next
);
6184 case MARSHAL_ACTION_CONV_RESULT
: {
6185 MonoMethod
*ctor
= NULL
;
6186 int intptr_handle_slot
;
6188 if (t
->data
.klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
){
6189 mono_mb_emit_byte (mb
, CEE_POP
);
6190 mono_mb_emit_exception_marshal_directive (mb
, "Returned SafeHandles should not be abstract");
6194 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
6196 mono_mb_emit_byte (mb
, CEE_POP
);
6197 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
6200 /* Store the IntPtr results into a local */
6201 intptr_handle_slot
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6202 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
6204 /* Create return value */
6205 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
6206 mono_mb_emit_stloc (mb
, 3);
6208 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
6209 mono_mb_emit_ldloc (mb
, 3);
6210 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
6211 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
6212 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6216 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6217 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6220 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6221 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6224 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6225 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6228 printf ("Unhandled case for MarshalAction: %d\n", action
);
6235 emit_marshal_handleref (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6236 MonoMarshalSpec
*spec
, int conv_arg
,
6237 MonoType
**conv_arg_type
, MarshalAction action
)
6239 MonoMethodBuilder
*mb
= m
->mb
;
6242 case MARSHAL_ACTION_CONV_IN
: {
6243 MonoType
*intptr_type
;
6245 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
6246 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
6247 *conv_arg_type
= intptr_type
;
6250 mono_mb_emit_exception_marshal_directive (mb
,
6251 "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6254 mono_mb_emit_ldarg_addr (mb
, argnum
);
6255 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoHandleRef
, handle
));
6256 mono_mb_emit_byte (mb
, CEE_ADD
);
6257 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6258 mono_mb_emit_stloc (mb
, conv_arg
);
6262 case MARSHAL_ACTION_PUSH
:
6263 mono_mb_emit_ldloc (mb
, conv_arg
);
6266 case MARSHAL_ACTION_CONV_OUT
: {
6267 /* no resource release required */
6271 case MARSHAL_ACTION_CONV_RESULT
: {
6272 mono_mb_emit_exception_marshal_directive (mb
,
6273 "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6277 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6278 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6281 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6282 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6285 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6286 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6289 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
6296 emit_marshal_object (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6297 MonoMarshalSpec
*spec
,
6298 int conv_arg
, MonoType
**conv_arg_type
,
6299 MarshalAction action
)
6301 MonoMethodBuilder
*mb
= m
->mb
;
6302 MonoClass
*klass
= mono_class_from_mono_type (t
);
6306 case MARSHAL_ACTION_CONV_IN
:
6307 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6308 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6310 m
->orig_conv_args
[argnum
] = 0;
6312 if (mono_class_from_mono_type (t
) == mono_defaults
.object_class
) {
6313 char *msg
= g_strdup_printf ("Marshalling of type object is not implemented");
6314 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6318 if (klass
->delegate
) {
6320 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6321 char *msg
= g_strdup_printf ("Byref marshalling of delegates is not implemented.");
6322 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6324 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6325 mono_mb_emit_stloc (mb
, conv_arg
);
6327 mono_mb_emit_ldarg (mb
, argnum
);
6328 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
));
6329 mono_mb_emit_stloc (mb
, conv_arg
);
6331 } else if (klass
== mono_defaults
.stringbuilder_class
) {
6332 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6333 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6336 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6337 char *msg
= g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
6338 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6343 mono_mb_emit_ldarg (mb
, argnum
);
6346 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6348 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
6349 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
6350 g_warning ("%s", msg
);
6352 mono_raise_exception (exc
);
6355 mono_mb_emit_stloc (mb
, conv_arg
);
6356 } else if (klass
->blittable
) {
6357 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6358 mono_mb_emit_stloc (mb
, conv_arg
);
6360 mono_mb_emit_ldarg (mb
, argnum
);
6361 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6363 mono_mb_emit_ldarg (mb
, argnum
);
6364 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6365 mono_mb_emit_stloc (mb
, conv_arg
);
6367 mono_mb_patch_branch (mb
, pos
);
6370 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6371 mono_mb_emit_stloc (mb
, conv_arg
);
6374 /* we dont need any conversions for out parameters */
6375 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6378 mono_mb_emit_ldarg (mb
, argnum
);
6379 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6382 mono_mb_emit_ldarg (mb
, argnum
);
6383 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6384 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
6387 /* store the address of the source into local variable 0 */
6388 mono_mb_emit_stloc (mb
, 0);
6389 mono_mb_emit_ldloc (mb
, 0);
6390 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6392 /* allocate space for the native struct and store the address */
6393 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6394 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6395 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
6396 mono_mb_emit_stloc (mb
, conv_arg
);
6399 /* Need to store the original buffer so we can free it later */
6400 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6401 mono_mb_emit_ldloc (mb
, conv_arg
);
6402 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
6405 /* set the src_ptr */
6406 mono_mb_emit_ldloc (mb
, 0);
6407 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6408 mono_mb_emit_stloc (mb
, 0);
6411 mono_mb_emit_ldloc (mb
, conv_arg
);
6412 mono_mb_emit_stloc (mb
, 1);
6414 /* emit valuetype conversion code */
6415 emit_struct_conv (mb
, klass
, FALSE
);
6417 mono_mb_patch_branch (mb
, pos
);
6421 case MARSHAL_ACTION_CONV_OUT
:
6422 if (klass
== mono_defaults
.stringbuilder_class
) {
6424 MonoMarshalNative encoding
;
6425 MonoMarshalConv conv
;
6427 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6428 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
6430 g_assert (encoding
!= -1);
6433 g_assert ((t
->attrs
& PARAM_ATTRIBUTE_OUT
));
6437 mono_mb_emit_ldarg (mb
, argnum
);
6438 mono_mb_emit_ldloc (mb
, conv_arg
);
6441 case MONO_NATIVE_LPWSTR
:
6442 mono_mb_emit_icall (mb
, mono_string_utf16_to_builder2
);
6444 case MONO_NATIVE_LPSTR
:
6445 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
6448 g_assert_not_reached ();
6451 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6453 mono_mb_emit_ldarg (mb
, argnum
);
6454 mono_mb_emit_ldloc (mb
, conv_arg
);
6456 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6460 mono_mb_emit_ldloc (mb
, conv_arg
);
6461 mono_mb_emit_icall (mb
, mono_marshal_free
);
6466 if (klass
->delegate
) {
6468 mono_mb_emit_ldarg (mb
, argnum
);
6469 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6470 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6471 mono_mb_emit_ldloc (mb
, conv_arg
);
6472 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
));
6473 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6478 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6479 /* allocate a new object */
6480 mono_mb_emit_ldarg (mb
, argnum
);
6481 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6482 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6483 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6486 /* dst = *argument */
6487 mono_mb_emit_ldarg (mb
, argnum
);
6490 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6492 mono_mb_emit_stloc (mb
, 1);
6494 mono_mb_emit_ldloc (mb
, 1);
6495 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6497 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6498 mono_mb_emit_ldloc (mb
, 1);
6499 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
6500 mono_mb_emit_byte (mb
, CEE_ADD
);
6501 mono_mb_emit_stloc (mb
, 1);
6503 /* src = tmp_locals [i] */
6504 mono_mb_emit_ldloc (mb
, conv_arg
);
6505 mono_mb_emit_stloc (mb
, 0);
6507 /* emit valuetype conversion code */
6508 emit_struct_conv (mb
, klass
, TRUE
);
6510 /* Free the structure returned by the native code */
6511 emit_struct_free (mb
, klass
, conv_arg
);
6513 if (m
->orig_conv_args
[argnum
]) {
6515 * If the native function changed the pointer, then free
6516 * the original structure plus the new pointer.
6518 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
6519 mono_mb_emit_ldloc (mb
, conv_arg
);
6520 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
6522 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6523 g_assert (m
->orig_conv_args
[argnum
]);
6525 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
6528 mono_mb_emit_ldloc (mb
, conv_arg
);
6529 mono_mb_emit_icall (mb
, g_free
);
6531 mono_mb_patch_branch (mb
, pos2
);
6535 /* Free the original structure passed to native code */
6536 emit_struct_free (mb
, klass
, conv_arg
);
6538 mono_mb_patch_branch (mb
, pos
);
6541 case MARSHAL_ACTION_PUSH
:
6543 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6545 mono_mb_emit_ldloc (mb
, conv_arg
);
6548 case MARSHAL_ACTION_CONV_RESULT
:
6549 if (klass
->delegate
) {
6550 g_assert (!t
->byref
);
6551 mono_mb_emit_stloc (mb
, 0);
6552 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6553 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6554 mono_mb_emit_ldloc (mb
, 0);
6555 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
));
6556 mono_mb_emit_stloc (mb
, 3);
6559 mono_mb_emit_stloc (mb
, 0);
6561 /* Make a copy since emit_conv modifies local 0 */
6562 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6563 mono_mb_emit_ldloc (mb
, 0);
6564 mono_mb_emit_stloc (mb
, loc
);
6566 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6567 mono_mb_emit_stloc (mb
, 3);
6569 mono_mb_emit_ldloc (mb
, 0);
6570 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6572 /* allocate result object */
6574 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6575 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6576 mono_mb_emit_stloc (mb
, 3);
6580 mono_mb_emit_ldloc (mb
, 3);
6581 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6582 mono_mb_emit_stloc (mb
, 1);
6584 /* emit conversion code */
6585 emit_struct_conv (mb
, klass
, TRUE
);
6587 emit_struct_free (mb
, klass
, loc
);
6589 /* Free the pointer allocated by unmanaged code */
6590 mono_mb_emit_ldloc (mb
, loc
);
6591 mono_mb_emit_icall (mb
, g_free
);
6592 mono_mb_patch_branch (mb
, pos
);
6596 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6597 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
6599 if (klass
->delegate
) {
6600 g_assert (!t
->byref
);
6601 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6602 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6603 mono_mb_emit_ldarg (mb
, argnum
);
6604 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
));
6605 mono_mb_emit_stloc (mb
, conv_arg
);
6609 if (klass
== mono_defaults
.stringbuilder_class
) {
6610 MonoMarshalNative encoding
;
6612 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6615 g_assert (encoding
== MONO_NATIVE_LPSTR
);
6617 g_assert (!t
->byref
);
6618 g_assert (encoding
!= -1);
6620 mono_mb_emit_ldarg (mb
, argnum
);
6621 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
6622 mono_mb_emit_stloc (mb
, conv_arg
);
6626 /* The class can not have an automatic layout */
6627 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
6628 mono_mb_emit_auto_layout_exception (mb
, klass
);
6632 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
6633 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6634 mono_mb_emit_stloc (mb
, conv_arg
);
6639 mono_mb_emit_ldarg (mb
, argnum
);
6643 /* Check for NULL and raise an exception */
6644 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6646 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
6648 mono_mb_patch_branch (mb
, pos2
);
6649 mono_mb_emit_ldarg (mb
, argnum
);
6650 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6653 mono_mb_emit_stloc (mb
, 0);
6655 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6656 mono_mb_emit_stloc (mb
, conv_arg
);
6658 mono_mb_emit_ldloc (mb
, 0);
6659 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6661 /* Create and set dst */
6662 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6663 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6664 mono_mb_emit_stloc (mb
, conv_arg
);
6665 mono_mb_emit_ldloc (mb
, conv_arg
);
6666 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6667 mono_mb_emit_stloc (mb
, 1);
6669 /* emit valuetype conversion code */
6670 emit_struct_conv (mb
, klass
, TRUE
);
6672 mono_mb_patch_branch (mb
, pos
);
6675 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6677 /* Check for null */
6678 mono_mb_emit_ldloc (mb
, conv_arg
);
6679 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6680 mono_mb_emit_ldarg (mb
, argnum
);
6681 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6682 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6683 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6685 mono_mb_patch_branch (mb
, pos
);
6688 mono_mb_emit_ldloc (mb
, conv_arg
);
6689 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6690 mono_mb_emit_stloc (mb
, 0);
6692 /* Allocate and set dest */
6693 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6694 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6695 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
6696 mono_mb_emit_stloc (mb
, 1);
6698 /* Update argument pointer */
6699 mono_mb_emit_ldarg (mb
, argnum
);
6700 mono_mb_emit_ldloc (mb
, 1);
6701 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6703 /* emit valuetype conversion code */
6704 emit_struct_conv (mb
, klass
, FALSE
);
6706 mono_mb_patch_branch (mb
, pos2
);
6708 /* byval [Out] marshalling */
6710 /* FIXME: Handle null */
6713 mono_mb_emit_ldloc (mb
, conv_arg
);
6714 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6715 mono_mb_emit_stloc (mb
, 0);
6718 mono_mb_emit_ldarg (mb
, argnum
);
6719 mono_mb_emit_stloc (mb
, 1);
6721 /* emit valuetype conversion code */
6722 emit_struct_conv (mb
, klass
, FALSE
);
6726 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6727 if (klass
->delegate
) {
6728 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
));
6729 mono_mb_emit_stloc (mb
, 3);
6733 /* The class can not have an automatic layout */
6734 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
6735 mono_mb_emit_auto_layout_exception (mb
, klass
);
6739 mono_mb_emit_stloc (mb
, 0);
6740 /* Check for null */
6741 mono_mb_emit_ldloc (mb
, 0);
6742 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6743 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6744 mono_mb_emit_stloc (mb
, 3);
6745 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6747 mono_mb_patch_branch (mb
, pos
);
6750 mono_mb_emit_ldloc (mb
, 0);
6751 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6752 mono_mb_emit_stloc (mb
, 0);
6754 /* Allocate and set dest */
6755 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6756 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6757 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
6758 mono_mb_emit_byte (mb
, CEE_DUP
);
6759 mono_mb_emit_stloc (mb
, 1);
6760 mono_mb_emit_stloc (mb
, 3);
6762 emit_struct_conv (mb
, klass
, FALSE
);
6764 mono_mb_patch_branch (mb
, pos2
);
6768 g_assert_not_reached ();
6775 emit_marshal_variant (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6776 MonoMarshalSpec
*spec
,
6777 int conv_arg
, MonoType
**conv_arg_type
,
6778 MarshalAction action
)
6780 MonoMethodBuilder
*mb
= m
->mb
;
6781 static MonoMethod
*get_object_for_native_variant
= NULL
;
6782 static MonoMethod
*get_native_variant_for_object
= NULL
;
6784 mono_init_com_types ();
6786 if (!get_object_for_native_variant
)
6787 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
6788 g_assert (get_object_for_native_variant
);
6790 if (!get_native_variant_for_object
)
6791 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
6792 g_assert (get_native_variant_for_object
);
6795 case MARSHAL_ACTION_CONV_IN
: {
6796 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.variant_class
->byval_arg
);
6799 *conv_arg_type
= &mono_defaults
.variant_class
->this_arg
;
6801 *conv_arg_type
= &mono_defaults
.variant_class
->byval_arg
;
6803 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6806 mono_mb_emit_ldarg (mb
, argnum
);
6808 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
6809 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6810 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
6814 case MARSHAL_ACTION_CONV_OUT
: {
6815 static MonoMethod
*variant_clear
= NULL
;
6818 variant_clear
= mono_class_get_method_from_name (mono_defaults
.variant_class
, "Clear", 0);
6819 g_assert (variant_clear
);
6822 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6823 mono_mb_emit_ldarg (mb
, argnum
);
6824 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6825 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
6826 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6829 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6830 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
6834 case MARSHAL_ACTION_PUSH
:
6836 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6838 mono_mb_emit_ldloc (mb
, conv_arg
);
6841 case MARSHAL_ACTION_CONV_RESULT
: {
6842 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6843 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6847 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
6848 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6851 *conv_arg_type
= &mono_defaults
.variant_class
->this_arg
;
6853 *conv_arg_type
= &mono_defaults
.variant_class
->byval_arg
;
6855 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6859 mono_mb_emit_ldarg (mb
, argnum
);
6861 mono_mb_emit_ldarg_addr (mb
, argnum
);
6862 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
6863 mono_mb_emit_stloc (mb
, conv_arg
);
6867 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
6868 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6869 mono_mb_emit_ldloc (mb
, conv_arg
);
6870 mono_mb_emit_ldarg (mb
, argnum
);
6871 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
6876 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
6877 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6878 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6883 g_assert_not_reached ();
6890 emit_marshal_array (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6891 MonoMarshalSpec
*spec
,
6892 int conv_arg
, MonoType
**conv_arg_type
,
6893 MarshalAction action
)
6895 MonoMethodBuilder
*mb
= m
->mb
;
6896 MonoClass
*klass
= mono_class_from_mono_type (t
);
6897 gboolean need_convert
, need_free
;
6898 MonoMarshalNative encoding
;
6900 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6903 case MARSHAL_ACTION_CONV_IN
:
6904 *conv_arg_type
= &mono_defaults
.object_class
->byval_arg
;
6905 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6907 if (klass
->element_class
->blittable
) {
6908 mono_mb_emit_ldarg (mb
, argnum
);
6910 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6911 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
));
6912 mono_mb_emit_stloc (mb
, conv_arg
);
6915 guint32 label1
, label2
, label3
;
6916 int index_var
, src_var
, dest_ptr
, esize
;
6917 MonoMarshalConv conv
;
6918 gboolean is_string
= FALSE
;
6920 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6922 eklass
= klass
->element_class
;
6924 if (eklass
== mono_defaults
.string_class
) {
6926 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6928 else if (eklass
== mono_defaults
.stringbuilder_class
) {
6930 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6935 src_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6936 mono_mb_emit_ldarg (mb
, argnum
);
6938 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6939 mono_mb_emit_stloc (mb
, src_var
);
6942 mono_mb_emit_ldloc (mb
, src_var
);
6943 mono_mb_emit_stloc (mb
, conv_arg
);
6944 mono_mb_emit_ldloc (mb
, src_var
);
6945 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6949 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
6950 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
6951 g_warning ("%s", msg
);
6953 mono_raise_exception (exc
);
6958 esize
= sizeof (gpointer
);
6960 esize
= mono_class_native_size (eklass
, NULL
);
6962 /* allocate space for the native struct and store the address */
6963 mono_mb_emit_icon (mb
, esize
);
6964 mono_mb_emit_ldloc (mb
, src_var
);
6965 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6967 if (eklass
== mono_defaults
.string_class
) {
6968 /* Make the array bigger for the terminating null */
6969 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
6970 mono_mb_emit_byte (mb
, CEE_ADD
);
6972 mono_mb_emit_byte (mb
, CEE_MUL
);
6973 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6974 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
6975 mono_mb_emit_stloc (mb
, conv_arg
);
6977 mono_mb_emit_ldloc (mb
, conv_arg
);
6978 mono_mb_emit_stloc (mb
, dest_ptr
);
6980 /* Emit marshalling loop */
6981 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6982 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6983 mono_mb_emit_stloc (mb
, index_var
);
6984 label2
= mono_mb_get_label (mb
);
6985 mono_mb_emit_ldloc (mb
, index_var
);
6986 mono_mb_emit_ldloc (mb
, src_var
);
6987 mono_mb_emit_byte (mb
, CEE_LDLEN
);
6988 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
6990 /* Emit marshalling code */
6993 mono_mb_emit_ldloc (mb
, dest_ptr
);
6994 mono_mb_emit_ldloc (mb
, src_var
);
6995 mono_mb_emit_ldloc (mb
, index_var
);
6996 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
6997 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6998 mono_mb_emit_byte (mb
, CEE_STIND_I
);
7000 /* set the src_ptr */
7001 mono_mb_emit_ldloc (mb
, src_var
);
7002 mono_mb_emit_ldloc (mb
, index_var
);
7003 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
7004 mono_mb_emit_stloc (mb
, 0);
7007 mono_mb_emit_ldloc (mb
, dest_ptr
);
7008 mono_mb_emit_stloc (mb
, 1);
7010 /* emit valuetype conversion code */
7011 emit_struct_conv (mb
, eklass
, FALSE
);
7014 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7015 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
7017 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7019 mono_mb_patch_branch (mb
, label3
);
7021 if (eklass
== mono_defaults
.string_class
) {
7022 /* Null terminate */
7023 mono_mb_emit_ldloc (mb
, dest_ptr
);
7024 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7025 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
7028 mono_mb_patch_branch (mb
, label1
);
7033 case MARSHAL_ACTION_CONV_OUT
:
7034 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
7035 need_convert
= ((klass
->element_class
== mono_defaults
.char_class
) && (encoding
== MONO_NATIVE_LPWSTR
)) || (klass
->element_class
== mono_defaults
.stringbuilder_class
) || (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
7036 need_free
= mono_marshal_need_free (&klass
->element_class
->byval_arg
,
7039 if (need_convert
|| need_free
) {
7040 /* FIXME: Optimize blittable case */
7042 guint32 label1
, label2
, label3
;
7043 int index_var
, src_ptr
, loc
, esize
;
7045 eklass
= klass
->element_class
;
7046 if ((eklass
== mono_defaults
.stringbuilder_class
) || (eklass
== mono_defaults
.string_class
))
7047 esize
= sizeof (gpointer
);
7049 esize
= mono_class_native_size (eklass
, NULL
);
7050 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7051 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7054 mono_mb_emit_ldarg (mb
, argnum
);
7056 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7057 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7059 mono_mb_emit_ldloc (mb
, conv_arg
);
7060 mono_mb_emit_stloc (mb
, src_ptr
);
7062 /* Emit marshalling loop */
7063 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7064 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7065 mono_mb_emit_stloc (mb
, index_var
);
7066 label2
= mono_mb_get_label (mb
);
7067 mono_mb_emit_ldloc (mb
, index_var
);
7068 mono_mb_emit_ldarg (mb
, argnum
);
7070 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7071 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7072 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7074 /* Emit marshalling code */
7076 if (eklass
== mono_defaults
.stringbuilder_class
) {
7077 gboolean need_free2
;
7078 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
7080 g_assert (conv
!= -1);
7083 mono_mb_emit_ldarg (mb
, argnum
);
7085 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7086 mono_mb_emit_ldloc (mb
, index_var
);
7087 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
7090 mono_mb_emit_ldloc (mb
, src_ptr
);
7091 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7093 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7097 mono_mb_emit_ldloc (mb
, src_ptr
);
7098 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7100 mono_mb_emit_icall (mb
, mono_marshal_free
);
7103 else if (eklass
== mono_defaults
.string_class
) {
7106 mono_mb_emit_ldloc (mb
, src_ptr
);
7107 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7109 mono_mb_emit_icall (mb
, mono_marshal_free
);
7114 /* set the src_ptr */
7115 mono_mb_emit_ldloc (mb
, src_ptr
);
7116 mono_mb_emit_stloc (mb
, 0);
7119 mono_mb_emit_ldarg (mb
, argnum
);
7121 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7122 mono_mb_emit_ldloc (mb
, index_var
);
7123 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
7124 mono_mb_emit_stloc (mb
, 1);
7126 /* emit valuetype conversion code */
7127 emit_struct_conv (mb
, eklass
, TRUE
);
7131 mono_mb_emit_ldloc (mb
, src_ptr
);
7132 mono_mb_emit_stloc (mb
, loc
);
7133 mono_mb_emit_ldloc (mb
, loc
);
7135 emit_struct_free (mb
, eklass
, loc
);
7139 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7140 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
7142 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7144 mono_mb_patch_branch (mb
, label1
);
7145 mono_mb_patch_branch (mb
, label3
);
7148 if (klass
->element_class
->blittable
) {
7149 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
7151 mono_mb_emit_ldarg (mb
, argnum
);
7152 mono_mb_emit_ldloc (mb
, conv_arg
);
7153 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY
));
7158 case MARSHAL_ACTION_PUSH
:
7160 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7162 mono_mb_emit_ldloc (mb
, conv_arg
);
7165 case MARSHAL_ACTION_CONV_RESULT
:
7166 /* fixme: we need conversions here */
7167 mono_mb_emit_stloc (mb
, 3);
7170 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7172 guint32 label1
, label2
, label3
;
7173 int index_var
, src_ptr
, loc
, esize
, param_num
, num_elem
;
7174 MonoMarshalConv conv
;
7175 gboolean is_string
= FALSE
;
7177 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7178 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7181 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
7182 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7186 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
7187 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7190 if (spec
->native
!= MONO_NATIVE_LPARRAY
) {
7191 char *msg
= g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
7192 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7196 /* FIXME: t is from the method which is wrapped, not the delegate type */
7197 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
7199 param_num
= spec
->data
.array_data
.param_num
;
7200 num_elem
= spec
->data
.array_data
.num_elem
;
7201 if (spec
->data
.array_data
.elem_mult
== 0)
7202 /* param_num is not specified */
7205 if (param_num
== -1) {
7206 if (num_elem
<= 0) {
7207 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
7208 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7213 /* FIXME: Optimize blittable case */
7215 eklass
= klass
->element_class
;
7216 if (eklass
== mono_defaults
.string_class
) {
7218 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
7220 else if (eklass
== mono_defaults
.stringbuilder_class
) {
7222 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
7227 mono_marshal_load_type_info (eklass
);
7230 esize
= sizeof (gpointer
);
7232 esize
= mono_class_native_size (eklass
, NULL
);
7233 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7234 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7236 mono_mb_emit_byte (mb
, CEE_LDNULL
);
7237 mono_mb_emit_stloc (mb
, conv_arg
);
7239 /* Check param index */
7240 if (param_num
!= -1) {
7241 if (param_num
>= m
->sig
->param_count
) {
7242 char *msg
= g_strdup ("Array size control parameter index is out of range.");
7243 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7246 switch (m
->sig
->params
[param_num
]->type
) {
7259 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
7260 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7267 mono_mb_emit_ldarg (mb
, argnum
);
7268 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7270 mono_mb_emit_ldarg (mb
, argnum
);
7271 mono_mb_emit_stloc (mb
, src_ptr
);
7273 /* Create managed array */
7275 * The LPArray marshalling spec says that sometimes param_num starts
7276 * from 1, sometimes it starts from 0. But MS seems to allways start
7280 if (param_num
== -1) {
7281 mono_mb_emit_icon (mb
, num_elem
);
7283 mono_mb_emit_ldarg (mb
, param_num
);
7285 mono_mb_emit_icon (mb
, num_elem
);
7286 mono_mb_emit_byte (mb
, CEE_ADD
);
7288 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
7291 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
7292 mono_mb_emit_stloc (mb
, conv_arg
);
7294 if (eklass
->blittable
) {
7295 mono_mb_emit_ldloc (mb
, conv_arg
);
7296 mono_mb_emit_byte (mb
, CEE_CONV_I
);
7297 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
7298 mono_mb_emit_byte (mb
, CEE_ADD
);
7299 mono_mb_emit_ldarg (mb
, argnum
);
7300 mono_mb_emit_ldloc (mb
, conv_arg
);
7301 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7302 mono_mb_emit_icon (mb
, esize
);
7303 mono_mb_emit_byte (mb
, CEE_MUL
);
7304 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
7305 mono_mb_emit_byte (mb
, CEE_CPBLK
);
7309 /* Emit marshalling loop */
7310 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7311 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7312 mono_mb_emit_stloc (mb
, index_var
);
7313 label2
= mono_mb_get_label (mb
);
7314 mono_mb_emit_ldloc (mb
, index_var
);
7315 mono_mb_emit_ldloc (mb
, conv_arg
);
7316 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7317 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7319 /* Emit marshalling code */
7321 g_assert (conv
!= -1);
7323 mono_mb_emit_ldloc (mb
, conv_arg
);
7324 mono_mb_emit_ldloc (mb
, index_var
);
7326 mono_mb_emit_ldloc (mb
, src_ptr
);
7327 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7329 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7330 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
7333 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7334 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7338 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7339 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
7341 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7343 mono_mb_patch_branch (mb
, label1
);
7344 mono_mb_patch_branch (mb
, label3
);
7348 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7350 guint32 label1
, label2
, label3
;
7351 int index_var
, dest_ptr
, loc
, esize
, param_num
, num_elem
;
7352 MonoMarshalConv conv
;
7353 gboolean is_string
= FALSE
;
7356 /* Already handled in CONV_IN */
7359 /* These are already checked in CONV_IN */
7360 g_assert (!t
->byref
);
7361 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
7362 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
7364 param_num
= spec
->data
.array_data
.param_num
;
7365 num_elem
= spec
->data
.array_data
.num_elem
;
7367 if (spec
->data
.array_data
.elem_mult
== 0)
7368 /* param_num is not specified */
7371 if (param_num
== -1) {
7372 if (num_elem
<= 0) {
7373 g_assert_not_reached ();
7377 /* FIXME: Optimize blittable case */
7379 eklass
= klass
->element_class
;
7380 if (eklass
== mono_defaults
.string_class
) {
7382 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
7384 else if (eklass
== mono_defaults
.stringbuilder_class
) {
7386 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
7391 mono_marshal_load_type_info (eklass
);
7394 esize
= sizeof (gpointer
);
7396 esize
= mono_class_native_size (eklass
, NULL
);
7398 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7399 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7402 mono_mb_emit_ldloc (mb
, conv_arg
);
7403 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7405 mono_mb_emit_ldarg (mb
, argnum
);
7406 mono_mb_emit_stloc (mb
, dest_ptr
);
7408 if (eklass
->blittable
) {
7410 mono_mb_emit_ldarg (mb
, argnum
);
7412 mono_mb_emit_ldloc (mb
, conv_arg
);
7413 mono_mb_emit_byte (mb
, CEE_CONV_I
);
7414 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
7415 mono_mb_emit_byte (mb
, CEE_ADD
);
7417 mono_mb_emit_ldloc (mb
, conv_arg
);
7418 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7419 mono_mb_emit_icon (mb
, esize
);
7420 mono_mb_emit_byte (mb
, CEE_MUL
);
7421 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
7422 mono_mb_emit_byte (mb
, CEE_CPBLK
);
7426 /* Emit marshalling loop */
7427 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7428 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7429 mono_mb_emit_stloc (mb
, index_var
);
7430 label2
= mono_mb_get_label (mb
);
7431 mono_mb_emit_ldloc (mb
, index_var
);
7432 mono_mb_emit_ldloc (mb
, conv_arg
);
7433 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7434 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7436 /* Emit marshalling code */
7438 g_assert (conv
!= -1);
7441 mono_mb_emit_ldloc (mb
, dest_ptr
);
7444 mono_mb_emit_ldloc (mb
, conv_arg
);
7445 mono_mb_emit_ldloc (mb
, index_var
);
7447 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
7449 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7450 mono_mb_emit_byte (mb
, CEE_STIND_I
);
7453 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7454 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7458 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7459 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
7461 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7463 mono_mb_patch_branch (mb
, label1
);
7464 mono_mb_patch_branch (mb
, label3
);
7468 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
7470 guint32 label1
, label2
, label3
;
7471 int index_var
, src
, dest
, esize
;
7472 MonoMarshalConv conv
= -1;
7473 gboolean is_string
= FALSE
;
7475 g_assert (!t
->byref
);
7477 eklass
= klass
->element_class
;
7479 mono_marshal_load_type_info (eklass
);
7481 if (eklass
== mono_defaults
.string_class
) {
7483 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
7486 g_assert_not_reached ();
7490 esize
= sizeof (gpointer
);
7492 esize
= mono_class_native_size (eklass
, NULL
);
7494 src
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7495 dest
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7497 mono_mb_emit_stloc (mb
, src
);
7498 mono_mb_emit_ldloc (mb
, src
);
7499 mono_mb_emit_stloc (mb
, 3);
7501 /* Check for null */
7502 mono_mb_emit_ldloc (mb
, src
);
7503 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7505 /* Allocate native array */
7506 mono_mb_emit_icon (mb
, esize
);
7507 mono_mb_emit_ldloc (mb
, src
);
7508 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7510 if (eklass
== mono_defaults
.string_class
) {
7511 /* Make the array bigger for the terminating null */
7512 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7513 mono_mb_emit_byte (mb
, CEE_ADD
);
7515 mono_mb_emit_byte (mb
, CEE_MUL
);
7516 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
7517 mono_mb_emit_stloc (mb
, dest
);
7518 mono_mb_emit_ldloc (mb
, dest
);
7519 mono_mb_emit_stloc (mb
, 3);
7521 /* Emit marshalling loop */
7522 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7523 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7524 mono_mb_emit_stloc (mb
, index_var
);
7525 label2
= mono_mb_get_label (mb
);
7526 mono_mb_emit_ldloc (mb
, index_var
);
7527 mono_mb_emit_ldloc (mb
, src
);
7528 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7529 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7531 /* Emit marshalling code */
7533 g_assert (conv
!= -1);
7536 mono_mb_emit_ldloc (mb
, dest
);
7539 mono_mb_emit_ldloc (mb
, src
);
7540 mono_mb_emit_ldloc (mb
, index_var
);
7542 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
7544 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7545 mono_mb_emit_byte (mb
, CEE_STIND_I
);
7548 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
7549 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7553 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7554 mono_mb_emit_add_to_local (mb
, dest
, esize
);
7556 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
7558 mono_mb_patch_branch (mb
, label3
);
7559 mono_mb_patch_branch (mb
, label1
);
7563 g_assert_not_reached ();
7570 emit_marshal_boolean (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7571 MonoMarshalSpec
*spec
,
7572 int conv_arg
, MonoType
**conv_arg_type
,
7573 MarshalAction action
)
7575 MonoMethodBuilder
*mb
= m
->mb
;
7578 case MARSHAL_ACTION_CONV_IN
: {
7579 MonoType
*local_type
;
7581 guint8 ldc_op
= CEE_LDC_I4_1
;
7584 local_type
= &mono_defaults
.int32_class
->byval_arg
;
7586 switch (spec
->native
) {
7587 case MONO_NATIVE_I1
:
7588 case MONO_NATIVE_U1
:
7589 local_type
= &mono_defaults
.byte_class
->byval_arg
;
7591 case MONO_NATIVE_VARIANTBOOL
:
7592 local_type
= &mono_defaults
.int16_class
->byval_arg
;
7593 ldc_op
= CEE_LDC_I4_M1
;
7595 case MONO_NATIVE_BOOLEAN
:
7596 local_type
= &mono_defaults
.int32_class
->byval_arg
;
7599 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
7600 local_type
= &mono_defaults
.int32_class
->byval_arg
;
7605 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7607 *conv_arg_type
= local_type
;
7608 conv_arg
= mono_mb_add_local (mb
, local_type
);
7610 mono_mb_emit_ldarg (mb
, argnum
);
7612 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
7613 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7614 mono_mb_emit_byte (mb
, ldc_op
);
7615 mono_mb_emit_stloc (mb
, conv_arg
);
7616 mono_mb_patch_branch (mb
, label_false
);
7621 case MARSHAL_ACTION_CONV_OUT
:
7623 int label_false
, label_end
;
7627 mono_mb_emit_ldarg (mb
, argnum
);
7628 mono_mb_emit_ldloc (mb
, conv_arg
);
7630 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7631 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7633 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
7634 mono_mb_patch_branch (mb
, label_false
);
7635 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7636 mono_mb_patch_branch (mb
, label_end
);
7638 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
7642 case MARSHAL_ACTION_PUSH
:
7644 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7646 mono_mb_emit_ldloc (mb
, conv_arg
);
7648 mono_mb_emit_ldarg (mb
, argnum
);
7651 case MARSHAL_ACTION_CONV_RESULT
:
7652 /* maybe we need to make sure that it fits within 8 bits */
7653 mono_mb_emit_stloc (mb
, 3);
7656 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7657 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
7658 guint8 ldop
= CEE_LDIND_I4
;
7659 int label_null
, label_false
;
7661 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
7664 switch (spec
->native
) {
7665 case MONO_NATIVE_I1
:
7666 case MONO_NATIVE_U1
:
7667 conv_arg_class
= mono_defaults
.byte_class
;
7668 ldop
= CEE_LDIND_I1
;
7670 case MONO_NATIVE_VARIANTBOOL
:
7671 conv_arg_class
= mono_defaults
.int16_class
;
7672 ldop
= CEE_LDIND_I2
;
7674 case MONO_NATIVE_BOOLEAN
:
7677 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
7682 *conv_arg_type
= &conv_arg_class
->this_arg
;
7684 *conv_arg_type
= &conv_arg_class
->byval_arg
;
7687 mono_mb_emit_ldarg (mb
, argnum
);
7691 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7692 mono_mb_emit_ldarg (mb
, argnum
);
7693 mono_mb_emit_byte (mb
, ldop
);
7697 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7698 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7699 mono_mb_emit_stloc (mb
, conv_arg
);
7700 mono_mb_patch_branch (mb
, label_false
);
7703 mono_mb_patch_branch (mb
, label_null
);
7707 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7708 guint8 stop
= CEE_STIND_I4
;
7709 guint8 ldc_op
= CEE_LDC_I4_1
;
7710 int label_null
,label_false
, label_end
;;
7715 switch (spec
->native
) {
7716 case MONO_NATIVE_I1
:
7717 case MONO_NATIVE_U1
:
7718 stop
= CEE_STIND_I1
;
7720 case MONO_NATIVE_VARIANTBOOL
:
7721 stop
= CEE_STIND_I2
;
7722 ldc_op
= CEE_LDC_I4_M1
;
7730 mono_mb_emit_ldarg (mb
, argnum
);
7731 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7733 mono_mb_emit_ldarg (mb
, argnum
);
7734 mono_mb_emit_ldloc (mb
, conv_arg
);
7736 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7737 mono_mb_emit_byte (mb
, ldc_op
);
7738 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
7740 mono_mb_patch_branch (mb
, label_false
);
7741 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7742 mono_mb_patch_branch (mb
, label_end
);
7744 mono_mb_emit_byte (mb
, stop
);
7745 mono_mb_patch_branch (mb
, label_null
);
7750 g_assert_not_reached ();
7757 emit_marshal_ptr (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7758 MonoMarshalSpec
*spec
, int conv_arg
,
7759 MonoType
**conv_arg_type
, MarshalAction action
)
7761 MonoMethodBuilder
*mb
= m
->mb
;
7764 case MARSHAL_ACTION_CONV_IN
:
7765 if (MONO_TYPE_ISSTRUCT (t
->data
.type
) && !mono_class_from_mono_type (t
->data
.type
)->blittable
) {
7766 char *msg
= g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum
+ 1);
7767 mono_mb_emit_exception_marshal_directive (m
->mb
, msg
);
7771 case MARSHAL_ACTION_PUSH
:
7772 mono_mb_emit_ldarg (mb
, argnum
);
7775 case MARSHAL_ACTION_CONV_RESULT
:
7776 /* no conversions necessary */
7777 mono_mb_emit_stloc (mb
, 3);
7788 emit_marshal_char (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7789 MonoMarshalSpec
*spec
, int conv_arg
,
7790 MonoType
**conv_arg_type
, MarshalAction action
)
7792 MonoMethodBuilder
*mb
= m
->mb
;
7795 case MARSHAL_ACTION_PUSH
:
7796 /* fixme: dont know how to marshal that. We cant simply
7797 * convert it to a one byte UTF8 character, because an
7798 * unicode character may need more that one byte in UTF8 */
7799 mono_mb_emit_ldarg (mb
, argnum
);
7802 case MARSHAL_ACTION_CONV_RESULT
:
7803 /* fixme: we need conversions here */
7804 mono_mb_emit_stloc (mb
, 3);
7815 emit_marshal_scalar (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7816 MonoMarshalSpec
*spec
, int conv_arg
,
7817 MonoType
**conv_arg_type
, MarshalAction action
)
7819 MonoMethodBuilder
*mb
= m
->mb
;
7822 case MARSHAL_ACTION_PUSH
:
7823 mono_mb_emit_ldarg (mb
, argnum
);
7826 case MARSHAL_ACTION_CONV_RESULT
:
7827 /* no conversions necessary */
7828 mono_mb_emit_stloc (mb
, 3);
7839 emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7840 MonoMarshalSpec
*spec
, int conv_arg
,
7841 MonoType
**conv_arg_type
, MarshalAction action
)
7843 /* Ensure that we have marshalling info for this param */
7844 mono_marshal_load_type_info (mono_class_from_mono_type (t
));
7846 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
7847 return emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7849 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
7850 return emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7853 case MONO_TYPE_VALUETYPE
:
7854 if (t
->data
.klass
== mono_defaults
.handleref_class
)
7855 return emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7857 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7858 case MONO_TYPE_STRING
:
7859 return emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7860 case MONO_TYPE_CLASS
:
7861 case MONO_TYPE_OBJECT
:
7862 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
7863 return emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7866 if (spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
7867 spec
->native
== MONO_NATIVE_IDISPATCH
||
7868 spec
->native
== MONO_NATIVE_INTERFACE
))
7869 return mono_cominterop_emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7870 if (spec
&& (spec
->native
== MONO_NATIVE_SAFEARRAY
) &&
7871 (spec
->data
.safearray_data
.elem_type
== MONO_VARIANT_VARIANT
) &&
7872 ((action
== MARSHAL_ACTION_CONV_OUT
) || (action
== MARSHAL_ACTION_CONV_IN
) || (action
== MARSHAL_ACTION_PUSH
)))
7873 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7876 if (mono_defaults
.safehandle_class
!= NULL
&& t
->data
.klass
&&
7877 mono_class_is_subclass_of (t
->data
.klass
, mono_defaults
.safehandle_class
, FALSE
))
7878 return emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7880 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7881 case MONO_TYPE_ARRAY
:
7882 case MONO_TYPE_SZARRAY
:
7883 return emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7884 case MONO_TYPE_BOOLEAN
:
7885 return emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7887 return emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7888 case MONO_TYPE_CHAR
:
7889 return emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7902 case MONO_TYPE_FNPTR
:
7903 return emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7904 case MONO_TYPE_GENERICINST
:
7905 if (mono_type_generic_inst_is_valuetype (t
))
7906 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7908 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
7915 * mono_marshal_emit_native_wrapper:
7916 * @image: the image to use for looking up custom marshallers
7917 * @sig: The signature of the native function
7918 * @piinfo: Marshalling information
7919 * @mspecs: Marshalling information
7920 * @aot: whenever the created method will be compiled by the AOT compiler
7921 * @method: if non-NULL, the pinvoke method to call
7922 * @check_exceptions: Whenever to check for pending exceptions after the native call
7924 * generates IL code for the pinvoke wrapper, the generated code calls @func.
7927 mono_marshal_emit_native_wrapper (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
)
7929 EmitMarshalContext m
;
7930 MonoMethodSignature
*csig
;
7932 int i
, argnum
, *tmp_locals
;
7934 static MonoMethodSignature
*get_last_error_sig
= NULL
;
7939 /* we copy the signature, so that we can set pinvoke to 0 */
7940 csig
= signature_dup (mb
->method
->klass
->image
, sig
);
7945 /* we allocate local for use with emit_struct_conv() */
7946 /* allocate local 0 (pointer) src_ptr */
7947 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7948 /* allocate local 1 (pointer) dst_ptr */
7949 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7950 /* allocate local 2 (boolean) delete_old */
7951 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
7953 /* delete_old = FALSE */
7954 mono_mb_emit_icon (mb
, 0);
7955 mono_mb_emit_stloc (mb
, 2);
7957 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
7958 /* allocate local 3 to store the return value */
7959 mono_mb_add_local (mb
, sig
->ret
);
7962 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
7963 /* Return type custom marshaling */
7965 * Since we can't determine the return type of the unmanaged function,
7966 * we assume it returns a pointer, and pass that pointer to
7967 * MarshalNativeToManaged.
7969 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
7972 /* we first do all conversions */
7973 tmp_locals
= alloca (sizeof (int) * sig
->param_count
);
7974 m
.orig_conv_args
= alloca (sizeof (int) * (sig
->param_count
+ 1));
7976 for (i
= 0; i
< sig
->param_count
; i
++) {
7977 tmp_locals
[i
] = emit_marshal (&m
, i
+ sig
->hasthis
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
7980 /* push all arguments */
7983 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
7985 for (i
= 0; i
< sig
->param_count
; i
++) {
7986 emit_marshal (&m
, i
+ sig
->hasthis
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
7989 /* call the native method */
7990 if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
7992 mono_mb_emit_cominterop_call (mb
, csig
, &piinfo
->method
);
7994 g_assert_not_reached ();
7999 /* Reuse the ICALL_ADDR opcode for pinvokes too */
8000 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8001 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
8002 mono_mb_emit_calli (mb
, csig
);
8004 mono_mb_emit_native_call (mb
, csig
, func
);
8008 /* Set LastError if needed */
8009 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
8010 if (!get_last_error_sig
) {
8011 get_last_error_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
8012 get_last_error_sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8013 get_last_error_sig
->pinvoke
= 1;
8018 * Have to call GetLastError () early and without a wrapper, since various runtime components could
8019 * clobber its value.
8021 mono_mb_emit_native_call (mb
, get_last_error_sig
, GetLastError
);
8022 mono_mb_emit_icall (mb
, mono_marshal_set_last_error_windows
);
8024 mono_mb_emit_icall (mb
, mono_marshal_set_last_error
);
8028 /* convert the result */
8029 if (!sig
->ret
->byref
) {
8030 MonoMarshalSpec
*spec
= mspecs
[0];
8031 type
= sig
->ret
->type
;
8033 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
8034 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
8039 case MONO_TYPE_VOID
:
8041 case MONO_TYPE_VALUETYPE
:
8042 klass
= sig
->ret
->data
.klass
;
8043 if (klass
->enumtype
) {
8044 type
= mono_class_enum_basetype (sig
->ret
->data
.klass
)->type
;
8047 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
8061 case MONO_TYPE_FNPTR
:
8062 case MONO_TYPE_STRING
:
8063 case MONO_TYPE_CLASS
:
8064 case MONO_TYPE_OBJECT
:
8065 case MONO_TYPE_BOOLEAN
:
8066 case MONO_TYPE_ARRAY
:
8067 case MONO_TYPE_SZARRAY
:
8068 case MONO_TYPE_CHAR
:
8070 case MONO_TYPE_GENERICINST
:
8071 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
8073 case MONO_TYPE_TYPEDBYREF
:
8075 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
8076 g_assert_not_reached ();
8080 mono_mb_emit_stloc (mb
, 3);
8084 * Need to call this after converting the result since MONO_VTADDR needs
8085 * to be adjacent to the call instruction.
8087 if (check_exceptions
)
8088 emit_thread_interrupt_checkpoint (mb
);
8090 /* we need to convert byref arguments back and free string arrays */
8091 for (i
= 0; i
< sig
->param_count
; i
++) {
8092 MonoType
*t
= sig
->params
[i
];
8093 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
8095 argnum
= i
+ sig
->hasthis
;
8097 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
8098 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
8103 case MONO_TYPE_STRING
:
8104 case MONO_TYPE_VALUETYPE
:
8105 case MONO_TYPE_CLASS
:
8106 case MONO_TYPE_OBJECT
:
8107 case MONO_TYPE_SZARRAY
:
8108 case MONO_TYPE_BOOLEAN
:
8109 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
8114 if (!MONO_TYPE_IS_VOID(sig
->ret
))
8115 mono_mb_emit_ldloc (mb
, 3);
8117 mono_mb_emit_byte (mb
, CEE_RET
);
8120 G_GNUC_UNUSED
static void
8121 code_for (MonoMethod
*method
) {
8122 MonoMethodHeader
*header
= mono_method_get_header (method
);
8123 printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (method
, TRUE
), mono_disasm_code (0, method
, header
->code
, header
->code
+ header
->code_size
));
8127 * mono_marshal_get_native_wrapper:
8128 * @method: The MonoMethod to wrap.
8129 * @check_exceptions: Whenever to check for pending exceptions
8131 * generates IL code for the pinvoke wrapper (the generated method
8132 * calls the unmanaged code in piinfo->addr)
8135 mono_marshal_get_native_wrapper (MonoMethod
*method
, gboolean check_exceptions
, gboolean aot
)
8137 MonoMethodSignature
*sig
, *csig
;
8138 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
8139 MonoMethodBuilder
*mb
;
8140 MonoMarshalSpec
**mspecs
;
8143 gboolean pinvoke
= FALSE
;
8146 const char *exc_class
= "MissingMethodException";
8147 const char *exc_arg
= NULL
;
8149 g_assert (method
!= NULL
);
8150 g_assert (mono_method_signature (method
)->pinvoke
);
8153 cache
= get_cache (&method
->klass
->image
->native_wrapper_aot_cache
, mono_aligned_addr_hash
, NULL
);
8155 cache
= get_cache (&method
->klass
->image
->native_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
8156 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
8159 if (MONO_CLASS_IS_IMPORT (method
->klass
)) {
8161 return mono_cominterop_get_native_wrapper (method
);
8163 g_assert_not_reached ();
8167 sig
= mono_method_signature (method
);
8169 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
8170 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
8173 if (!piinfo
->addr
) {
8175 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_NATIVE
)
8176 exc_arg
= "Method contains unsupported native code";
8178 mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
8180 piinfo
->addr
= mono_lookup_internal_call (method
);
8183 /* hack - redirect certain string constructors to CreateString */
8184 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
8185 g_assert (!pinvoke
);
8186 g_assert (method
->string_ctor
);
8187 g_assert (sig
->hasthis
);
8189 /* CreateString returns a value */
8190 csig
= signature_dup (method
->klass
->image
, sig
);
8191 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
8195 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
8196 if (!strcmp ("CreateString", res
->name
) &&
8197 mono_metadata_signature_equal (csig
, mono_method_signature (res
))) {
8199 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
8200 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
8202 /* create a wrapper to preserve .ctor in stack trace */
8203 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
8205 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8206 for (i
= 1; i
<= csig
->param_count
; i
++)
8207 mono_mb_emit_ldarg (mb
, i
);
8208 mono_mb_emit_managed_call (mb
, res
, NULL
);
8209 mono_mb_emit_byte (mb
, CEE_RET
);
8211 /* use native_wrapper_cache because internal calls are looked up there */
8212 res
= mono_mb_create_and_cache (cache
, method
,
8213 mb
, csig
, csig
->param_count
+ 1);
8221 /* exception will be thrown */
8222 piinfo
->addr
= NULL
;
8223 g_warning ("cannot find CreateString for .ctor");
8226 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8228 mb
->method
->save_lmf
= 1;
8231 * In AOT mode and embedding scenarios, it is possible that the icall is not
8232 * registered in the runtime doing the AOT compilation.
8234 if (!piinfo
->addr
&& !aot
) {
8235 mono_mb_emit_exception (mb
, exc_class
, exc_arg
);
8236 csig
= signature_dup (method
->klass
->image
, sig
);
8238 res
= mono_mb_create_and_cache (cache
, method
,
8239 mb
, csig
, csig
->param_count
+ 16);
8244 /* internal calls: we simply push all arguments and call the method (no conversions) */
8245 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
8247 csig
= signature_dup_add_this (sig
, method
->klass
);
8249 csig
= signature_dup (method
->klass
->image
, sig
);
8251 /* hack - string constructors returns a value */
8252 if (method
->string_ctor
)
8253 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
8259 * Add a null check since public icalls can be called with 'call' which
8260 * does no such check.
8262 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8263 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
8264 mono_mb_emit_exception (mb
, "NullReferenceException", NULL
);
8265 mono_mb_patch_branch (mb
, pos
);
8267 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8270 for (i
= 0; i
< sig
->param_count
; i
++)
8271 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
8274 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8275 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
8276 mono_mb_emit_calli (mb
, csig
);
8278 g_assert (piinfo
->addr
);
8279 mono_mb_emit_native_call (mb
, csig
, piinfo
->addr
);
8281 if (check_exceptions
)
8282 emit_thread_interrupt_checkpoint (mb
);
8283 mono_mb_emit_byte (mb
, CEE_RET
);
8285 csig
= signature_dup (method
->klass
->image
, csig
);
8287 res
= mono_mb_create_and_cache (cache
, method
,
8288 mb
, csig
, csig
->param_count
+ 16);
8295 g_assert (piinfo
->addr
);
8297 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
8298 mono_method_get_marshal_info (method
, mspecs
);
8300 mono_marshal_emit_native_wrapper (mb
->method
->klass
->image
, mb
, sig
, piinfo
, mspecs
, piinfo
->addr
, aot
, check_exceptions
);
8302 csig
= signature_dup (method
->klass
->image
, sig
);
8304 res
= mono_mb_create_and_cache (cache
, method
,
8305 mb
, csig
, csig
->param_count
+ 16);
8308 for (i
= sig
->param_count
; i
>= 0; i
--)
8310 mono_metadata_free_marshal_spec (mspecs
[i
]);
8313 /* code_for (res); */
8319 * mono_marshal_get_native_func_wrapper:
8320 * @image: The image to use for memory allocation and for looking up custom marshallers.
8321 * @sig: The signature of the function
8322 * @func: The native function to wrap
8324 * Returns a wrapper method around native functions, similar to the pinvoke
8328 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
8329 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
8331 MonoMethodSignature
*csig
;
8333 MonoMethodBuilder
*mb
;
8338 cache
= get_cache (&image
->native_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
8339 if ((res
= mono_marshal_find_in_cache (cache
, func
)))
8342 name
= g_strdup_printf ("wrapper_native_%p", func
);
8343 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8344 mb
->method
->save_lmf
= 1;
8346 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
, FALSE
, TRUE
);
8348 csig
= signature_dup (image
, sig
);
8350 res
= mono_mb_create_and_cache (cache
, func
,
8351 mb
, csig
, csig
->param_count
+ 16);
8354 mono_marshal_set_wrapper_info (res
, NULL
);
8356 /* code_for (res); */
8362 * mono_marshal_emit_managed_wrapper:
8364 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
8365 * the delegate which wraps the managed method to be called. For closed delegates,
8366 * it could have fewer parameters than the method it wraps.
8367 * THIS_LOC is the memory location where the target of the delegate is stored.
8370 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
8372 MonoMethodSignature
*sig
, *csig
;
8374 gboolean closed
= FALSE
;
8379 /* allocate local 0 (pointer) src_ptr */
8380 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8381 /* allocate local 1 (pointer) dst_ptr */
8382 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8383 /* allocate local 2 (boolean) delete_old */
8384 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
8386 if (!sig
->hasthis
&& sig
->param_count
!= invoke_sig
->param_count
) {
8387 /* Closed delegate */
8388 g_assert (sig
->param_count
== invoke_sig
->param_count
+ 1);
8390 /* Use a new signature without the first argument */
8391 sig
= mono_metadata_signature_dup (sig
);
8392 memmove (&sig
->params
[0], &sig
->params
[1], (sig
->param_count
- 1) * sizeof (MonoType
*));
8393 sig
->param_count
--;
8396 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
8397 /* allocate local 3 to store the return value */
8398 mono_mb_add_local (mb
, sig
->ret
);
8401 mono_mb_emit_icon (mb
, 0);
8402 mono_mb_emit_stloc (mb
, 2);
8404 /* we first do all conversions */
8405 tmp_locals
= alloca (sizeof (int) * sig
->param_count
);
8406 for (i
= 0; i
< sig
->param_count
; i
++) {
8407 MonoType
*t
= sig
->params
[i
];
8410 case MONO_TYPE_OBJECT
:
8411 case MONO_TYPE_CLASS
:
8412 case MONO_TYPE_VALUETYPE
:
8413 case MONO_TYPE_ARRAY
:
8414 case MONO_TYPE_SZARRAY
:
8415 case MONO_TYPE_STRING
:
8416 case MONO_TYPE_BOOLEAN
:
8417 tmp_locals
[i
] = emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
8426 emit_thread_interrupt_checkpoint (mb
);
8429 if (target_handle
) {
8430 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
8431 mono_mb_emit_icall (mb
, mono_gchandle_get_target
);
8434 g_assert_not_reached ();
8436 } else if (closed
) {
8437 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
8438 mono_mb_emit_icall (mb
, mono_gchandle_get_target
);
8441 for (i
= 0; i
< sig
->param_count
; i
++) {
8442 MonoType
*t
= sig
->params
[i
];
8444 if (tmp_locals
[i
]) {
8446 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
8448 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
8451 mono_mb_emit_ldarg (mb
, i
);
8454 mono_mb_emit_managed_call (mb
, method
, NULL
);
8456 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
8457 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8458 } else if (!sig
->ret
->byref
) {
8459 switch (sig
->ret
->type
) {
8460 case MONO_TYPE_VOID
:
8462 case MONO_TYPE_BOOLEAN
:
8465 case MONO_TYPE_CHAR
:
8477 case MONO_TYPE_OBJECT
:
8478 mono_mb_emit_stloc (mb
, 3);
8480 case MONO_TYPE_STRING
:
8481 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8482 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8484 case MONO_TYPE_VALUETYPE
:
8485 case MONO_TYPE_CLASS
:
8486 case MONO_TYPE_SZARRAY
:
8487 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8490 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
8491 g_assert_not_reached ();
8494 mono_mb_emit_stloc (mb
, 3);
8497 /* Convert byref arguments back */
8498 for (i
= 0; i
< sig
->param_count
; i
++) {
8499 MonoType
*t
= sig
->params
[i
];
8500 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
8502 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
8503 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8505 else if (t
->byref
) {
8507 case MONO_TYPE_CLASS
:
8508 case MONO_TYPE_VALUETYPE
:
8509 case MONO_TYPE_OBJECT
:
8510 case MONO_TYPE_STRING
:
8511 case MONO_TYPE_BOOLEAN
:
8512 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8516 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
8517 /* The [Out] information is encoded in the delegate signature */
8519 case MONO_TYPE_SZARRAY
:
8520 case MONO_TYPE_CLASS
:
8521 case MONO_TYPE_VALUETYPE
:
8522 emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8525 g_assert_not_reached ();
8530 if (m
->retobj_var
) {
8531 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
8532 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8533 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
8536 if (!MONO_TYPE_IS_VOID(sig
->ret
))
8537 mono_mb_emit_ldloc (mb
, 3);
8538 mono_mb_emit_byte (mb
, CEE_RET
);
8547 mono_marshal_set_callconv_from_modopt (MonoMethod
*method
, MonoMethodSignature
*csig
)
8549 MonoMethodSignature
*sig
;
8554 * Under windows, delegates passed to native code must use the STDCALL
8555 * calling convention.
8557 csig
->call_convention
= MONO_CALL_STDCALL
;
8560 sig
= mono_method_signature (method
);
8562 /* Change default calling convention if needed */
8563 /* Why is this a modopt ? */
8564 if (sig
->ret
&& sig
->ret
->num_mods
) {
8565 for (i
= 0; i
< sig
->ret
->num_mods
; ++i
) {
8566 MonoClass
*cmod_class
= mono_class_get (method
->klass
->image
, sig
->ret
->modifiers
[i
].token
);
8567 g_assert (cmod_class
);
8568 if ((cmod_class
->image
== mono_defaults
.corlib
) && !strcmp (cmod_class
->name_space
, "System.Runtime.CompilerServices")) {
8569 if (!strcmp (cmod_class
->name
, "CallConvCdecl"))
8570 csig
->call_convention
= MONO_CALL_C
;
8571 else if (!strcmp (cmod_class
->name
, "CallConvStdcall"))
8572 csig
->call_convention
= MONO_CALL_STDCALL
;
8573 else if (!strcmp (cmod_class
->name
, "CallConvFastcall"))
8574 csig
->call_convention
= MONO_CALL_FASTCALL
;
8575 else if (!strcmp (cmod_class
->name
, "CallConvThiscall"))
8576 csig
->call_convention
= MONO_CALL_THISCALL
;
8583 * generates IL code to call managed methods from unmanaged code
8586 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, uint32_t target_handle
)
8588 static MonoClass
*UnmanagedFunctionPointerAttribute
;
8589 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
8590 MonoMethodBuilder
*mb
;
8591 MonoMethod
*res
, *invoke
;
8592 MonoMarshalSpec
**mspecs
;
8593 MonoMethodPInvoke piinfo
;
8596 EmitMarshalContext m
;
8598 g_assert (method
!= NULL
);
8599 g_assert (!mono_method_signature (method
)->pinvoke
);
8602 * FIXME: Should cache the method+delegate type pair, since the same method
8603 * could be called with different delegates, thus different marshalling
8606 cache
= get_cache (&method
->klass
->image
->managed_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
8607 if (!target_handle
&& (res
= mono_marshal_find_in_cache (cache
, method
)))
8610 invoke
= mono_get_delegate_invoke (delegate_klass
);
8611 invoke_sig
= mono_method_signature (invoke
);
8613 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
8614 mono_method_get_marshal_info (invoke
, mspecs
);
8616 sig
= mono_method_signature (method
);
8618 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8620 /*the target gchandle must be the first entry after size and the wrapper itself.*/
8621 mono_mb_add_data (mb
, GUINT_TO_POINTER (target_handle
));
8623 /* we copy the signature, so that we can modify it */
8625 /* Need to free this later */
8626 csig
= mono_metadata_signature_dup (invoke_sig
);
8628 csig
= signature_dup (method
->klass
->image
, invoke_sig
);
8637 m
.image
= method
->klass
->image
;
8639 mono_marshal_set_callconv_from_modopt (invoke
, csig
);
8641 /* Handle the UnmanagedFunctionPointerAttribute */
8642 if (!UnmanagedFunctionPointerAttribute
)
8643 UnmanagedFunctionPointerAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
8645 /* The attribute is only available in Net 2.0 */
8646 if (UnmanagedFunctionPointerAttribute
) {
8647 MonoCustomAttrInfo
*cinfo
;
8648 MonoCustomAttrEntry
*attr
;
8651 * The pinvoke attributes are stored in a real custom attribute. Obtain the
8652 * contents of the attribute without constructing it, as that might not be
8653 * possible when running in cross-compiling mode.
8655 cinfo
= mono_custom_attrs_from_class (delegate_klass
);
8658 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
8659 if (mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, UnmanagedFunctionPointerAttribute
)) {
8660 attr
= &cinfo
->attrs
[i
];
8666 MonoArray
*typed_args
, *named_args
;
8667 CattrNamedArg
*arginfo
;
8671 MonoBoolean set_last_error
= 0;
8672 MonoBoolean best_fit_mapping
= 0;
8673 MonoBoolean throw_on_unmappable
= 0;
8675 mono_reflection_create_custom_attr_data_args (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
8677 g_assert (mono_array_length (typed_args
) == 1);
8680 o
= mono_array_get (typed_args
, MonoObject
*, 0);
8681 call_conv
= *(gint32
*)mono_object_unbox (o
);
8684 for (i
= 0; i
< mono_array_length (named_args
); ++i
) {
8685 CattrNamedArg
*narg
= &arginfo
[i
];
8687 o
= mono_array_get (named_args
, MonoObject
*, i
);
8689 g_assert (narg
->field
);
8690 if (!strcmp (narg
->field
->name
, "CharSet")) {
8691 charset
= *(gint32
*)mono_object_unbox (o
);
8692 } else if (!strcmp (narg
->field
->name
, "SetLastError")) {
8693 set_last_error
= *(MonoBoolean
*)mono_object_unbox (o
);
8694 } else if (!strcmp (narg
->field
->name
, "BestFitMapping")) {
8695 best_fit_mapping
= *(MonoBoolean
*)mono_object_unbox (o
);
8696 } else if (!strcmp (narg
->field
->name
, "ThrowOnUnmappableChar")) {
8697 throw_on_unmappable
= *(MonoBoolean
*)mono_object_unbox (o
);
8699 g_assert_not_reached ();
8705 memset (&piinfo
, 0, sizeof (piinfo
));
8707 piinfo
.piflags
= (call_conv
<< 8) | (charset
? (charset
- 1) * 2 : 1) | set_last_error
;
8709 csig
->call_convention
= call_conv
- 1;
8712 if (cinfo
&& !cinfo
->cached
)
8713 mono_custom_attrs_free (cinfo
);
8716 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, target_handle
);
8719 res
= mono_mb_create_and_cache (cache
, method
,
8720 mb
, csig
, sig
->param_count
+ 16);
8723 res
= mono_mb_create_method (mb
, csig
, sig
->param_count
+ 16);
8727 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
8729 mono_metadata_free_marshal_spec (mspecs
[i
]);
8732 /* code_for (res); */
8738 mono_marshal_get_vtfixup_ftnptr (MonoImage
*image
, guint32 token
, guint16 type
)
8741 MonoMethodSignature
*sig
;
8742 MonoMethodBuilder
*mb
;
8747 method
= mono_get_method (image
, token
, NULL
);
8750 if (type
& (VTFIXUP_TYPE_FROM_UNMANAGED
| VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN
)) {
8751 MonoMethodSignature
*csig
;
8752 MonoMarshalSpec
**mspecs
;
8753 EmitMarshalContext m
;
8755 sig
= mono_method_signature (method
);
8756 g_assert (!sig
->hasthis
);
8758 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
8759 mono_method_get_marshal_info (method
, mspecs
);
8761 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8762 csig
= signature_dup (image
, sig
);
8773 mono_marshal_set_callconv_from_modopt (method
, csig
);
8775 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
8777 mono_marshal_emit_managed_wrapper (mb
, sig
, mspecs
, &m
, method
, 0);
8780 method
= mono_mb_create_method (mb
, csig
, sig
->param_count
+ 16);
8783 for (i
= sig
->param_count
; i
>= 0; i
--)
8785 mono_metadata_free_marshal_spec (mspecs
[i
]);
8788 return mono_compile_method (method
);
8791 sig
= mono_method_signature (method
);
8792 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
8794 param_count
= sig
->param_count
+ sig
->hasthis
;
8795 for (i
= 0; i
< param_count
; i
++)
8796 mono_mb_emit_ldarg (mb
, i
);
8798 if (type
& VTFIXUP_TYPE_CALL_MOST_DERIVED
)
8799 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
8801 mono_mb_emit_op (mb
, CEE_CALL
, method
);
8802 mono_mb_emit_byte (mb
, CEE_RET
);
8805 method
= mono_mb_create_method (mb
, sig
, param_count
);
8808 return mono_compile_method (method
);
8811 static MonoReflectionType
*
8812 type_from_handle (MonoType
*handle
)
8814 MonoDomain
*domain
= mono_domain_get ();
8815 MonoClass
*klass
= mono_class_from_mono_type (handle
);
8817 MONO_ARCH_SAVE_REGS
;
8819 mono_class_init (klass
);
8820 return mono_type_get_object (domain
, handle
);
8824 * This does the equivalent of mono_object_castclass_with_cache.
8827 mono_marshal_get_castclass_with_cache (void)
8829 static MonoMethod
*cached
;
8831 MonoMethodBuilder
*mb
;
8832 MonoMethodSignature
*sig
;
8833 int return_null_pos
, cache_miss_pos
, invalid_cast_pos
;
8838 mb
= mono_mb_new (mono_defaults
.object_class
, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS
);
8839 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
8840 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
8841 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
8842 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
8843 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
8846 /* allocate local 0 (pointer) obj_vtable */
8847 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8850 mono_mb_emit_ldarg (mb
, 0);
8851 return_null_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8853 /*obj_vtable = obj->vtable;*/
8854 mono_mb_emit_ldarg (mb
, 0);
8855 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
8856 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
8857 mono_mb_emit_stloc (mb
, 0);
8860 mono_mb_emit_ldarg (mb
, 2);
8861 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
8862 mono_mb_emit_ldloc (mb
, 0);
8864 /*if (*cache == obj_vtable)*/
8865 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
8868 mono_mb_emit_ldarg (mb
, 0);
8869 mono_mb_emit_byte (mb
, CEE_RET
);
8871 mono_mb_patch_branch (mb
, cache_miss_pos
);
8872 /*if (mono_object_isinst (obj, klass)) */
8873 mono_mb_emit_ldarg (mb
, 0);
8874 mono_mb_emit_ldarg (mb
, 1);
8875 mono_mb_emit_icall (mb
, mono_object_isinst
);
8876 invalid_cast_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8878 /**cache = obj_vtable;*/
8879 mono_mb_emit_ldarg (mb
, 2);
8880 mono_mb_emit_ldloc (mb
, 0);
8881 mono_mb_emit_byte (mb
, CEE_STIND_I
);
8884 mono_mb_emit_ldarg (mb
, 0);
8885 mono_mb_emit_byte (mb
, CEE_RET
);
8888 mono_mb_patch_branch (mb
, invalid_cast_pos
);
8889 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
8892 mono_mb_patch_branch (mb
, return_null_pos
);
8893 mono_mb_emit_byte (mb
, CEE_LDNULL
);
8894 mono_mb_emit_byte (mb
, CEE_RET
);
8896 res
= mono_mb_create_method (mb
, sig
, 8);
8897 if (InterlockedCompareExchangePointer ((volatile gpointer
*)&cached
, res
, NULL
)) {
8898 mono_free_method (res
);
8899 mono_metadata_free_method_signature (sig
);
8907 * This does the equivalent of mono_object_isinst_with_cache.
8910 mono_marshal_get_isinst_with_cache (void)
8912 static MonoMethod
*cached
;
8914 MonoMethodBuilder
*mb
;
8915 MonoMethodSignature
*sig
;
8916 int return_null_pos
, cache_miss_pos
, cache_hit_pos
, not_an_instance_pos
, negative_cache_hit_pos
;
8921 mb
= mono_mb_new (mono_defaults
.object_class
, "__isisnt_with_cache", MONO_WRAPPER_CASTCLASS
);
8922 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
8923 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
8924 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
8925 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
8926 sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
8929 /* allocate local 0 (pointer) obj_vtable */
8930 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8931 /* allocate local 1 (pointer) cached_vtable */
8932 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8935 mono_mb_emit_ldarg (mb
, 0);
8936 return_null_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8938 /*obj_vtable = obj->vtable;*/
8939 mono_mb_emit_ldarg (mb
, 0);
8940 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
8941 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
8942 mono_mb_emit_stloc (mb
, 0);
8944 /* cached_vtable = *cache*/
8945 mono_mb_emit_ldarg (mb
, 2);
8946 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
8947 mono_mb_emit_stloc (mb
, 1);
8949 mono_mb_emit_ldloc (mb
, 1);
8950 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
8951 mono_mb_emit_i4 (mb
, ~0x1);
8952 mono_mb_emit_byte (mb
, CEE_CONV_U
);
8953 mono_mb_emit_byte (mb
, CEE_AND
);
8954 mono_mb_emit_ldloc (mb
, 0);
8955 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
8956 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
8958 /*return (cached_vtable & 0x1) ? NULL : obj;*/
8959 mono_mb_emit_ldloc (mb
, 1);
8960 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
8961 mono_mb_emit_byte (mb
, CEE_CONV_U
);
8962 mono_mb_emit_byte (mb
, CEE_AND
);
8963 negative_cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
8966 mono_mb_emit_ldarg (mb
, 0);
8967 cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BR
);
8970 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
8971 mono_mb_emit_byte (mb
, CEE_LDNULL
);
8973 mono_mb_patch_branch (mb
, cache_hit_pos
);
8974 mono_mb_emit_byte (mb
, CEE_RET
);
8976 mono_mb_patch_branch (mb
, cache_miss_pos
);
8977 /*if (mono_object_isinst (obj, klass)) */
8978 mono_mb_emit_ldarg (mb
, 0);
8979 mono_mb_emit_ldarg (mb
, 1);
8980 mono_mb_emit_icall (mb
, mono_object_isinst
);
8981 not_an_instance_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8983 /**cache = obj_vtable;*/
8984 mono_mb_emit_ldarg (mb
, 2);
8985 mono_mb_emit_ldloc (mb
, 0);
8986 mono_mb_emit_byte (mb
, CEE_STIND_I
);
8989 mono_mb_emit_ldarg (mb
, 0);
8990 mono_mb_emit_byte (mb
, CEE_RET
);
8993 mono_mb_patch_branch (mb
, not_an_instance_pos
);
8994 /* *cache = (gpointer)(obj_vtable | 0x1);*/
8995 mono_mb_emit_ldarg (mb
, 2);
8996 /*obj_vtable | 0x1*/
8997 mono_mb_emit_ldloc (mb
, 0);
8998 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
8999 mono_mb_emit_byte (mb
, CEE_CONV_U
);
9000 mono_mb_emit_byte (mb
, CEE_OR
);
9003 mono_mb_emit_byte (mb
, CEE_STIND_I
);
9006 mono_mb_patch_branch (mb
, return_null_pos
);
9007 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9008 mono_mb_emit_byte (mb
, CEE_RET
);
9010 res
= mono_mb_create_method (mb
, sig
, 8);
9011 if (InterlockedCompareExchangePointer ((volatile gpointer
*)&cached
, res
, NULL
)) {
9012 mono_free_method (res
);
9013 mono_metadata_free_method_signature (sig
);
9021 * mono_marshal_get_isinst:
9022 * @klass: the type of the field
9024 * This method generates a function which can be used to check if an object is
9025 * an instance of the given type, icluding the case where the object is a proxy.
9026 * The generated function has the following signature:
9027 * MonoObject* __isinst_wrapper_ (MonoObject *obj)
9030 mono_marshal_get_isinst (MonoClass
*klass
)
9032 static MonoMethodSignature
*isint_sig
= NULL
;
9035 int pos_was_ok
, pos_failed
, pos_end
, pos_end2
;
9037 MonoMethodBuilder
*mb
;
9039 cache
= get_cache (&klass
->image
->isinst_cache
, mono_aligned_addr_hash
, NULL
);
9040 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9044 isint_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9045 isint_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9046 isint_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9047 isint_sig
->pinvoke
= 0;
9050 name
= g_strdup_printf ("__isinst_wrapper_%s", klass
->name
);
9051 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_ISINST
);
9054 mb
->method
->save_lmf
= 1;
9056 /* check if the object is a proxy that needs special cast */
9057 mono_mb_emit_ldarg (mb
, 0);
9058 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
9059 mono_mb_emit_op (mb
, CEE_MONO_CISINST
, klass
);
9061 /* The result of MONO_ISINST can be:
9062 0) the type check succeeded
9063 1) the type check did not succeed
9064 2) a CanCastTo call is needed */
9066 mono_mb_emit_byte (mb
, CEE_DUP
);
9067 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9069 mono_mb_emit_byte (mb
, CEE_LDC_I4_2
);
9070 pos_failed
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9072 /* get the real proxy from the transparent proxy*/
9074 mono_mb_emit_ldarg (mb
, 0);
9075 mono_mb_emit_managed_call (mb
, mono_marshal_get_proxy_cancast (klass
), NULL
);
9076 pos_end
= mono_mb_emit_branch (mb
, CEE_BR
);
9080 mono_mb_patch_branch (mb
, pos_failed
);
9081 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9082 pos_end2
= mono_mb_emit_branch (mb
, CEE_BR
);
9086 mono_mb_patch_branch (mb
, pos_was_ok
);
9087 mono_mb_emit_byte (mb
, CEE_POP
);
9088 mono_mb_emit_ldarg (mb
, 0);
9092 mono_mb_patch_branch (mb
, pos_end
);
9093 mono_mb_patch_branch (mb
, pos_end2
);
9094 mono_mb_emit_byte (mb
, CEE_RET
);
9096 res
= mono_mb_create_and_cache (cache
, klass
, mb
, isint_sig
, isint_sig
->param_count
+ 16);
9103 * mono_marshal_get_castclass:
9104 * @klass: the type of the field
9106 * This method generates a function which can be used to cast an object to
9107 * an instance of the given type, icluding the case where the object is a proxy.
9108 * The generated function has the following signature:
9109 * MonoObject* __castclass_wrapper_ (MonoObject *obj)
9112 mono_marshal_get_castclass (MonoClass
*klass
)
9114 static MonoMethodSignature
*castclass_sig
= NULL
;
9117 int pos_was_ok
, pos_was_ok2
;
9119 MonoMethodBuilder
*mb
;
9121 cache
= get_cache (&klass
->image
->castclass_cache
, mono_aligned_addr_hash
, NULL
);
9122 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9125 if (!castclass_sig
) {
9126 castclass_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9127 castclass_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9128 castclass_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9129 castclass_sig
->pinvoke
= 0;
9132 name
= g_strdup_printf ("__castclass_wrapper_%s", klass
->name
);
9133 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_CASTCLASS
);
9136 mb
->method
->save_lmf
= 1;
9138 /* check if the object is a proxy that needs special cast */
9139 mono_mb_emit_ldarg (mb
, 0);
9140 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
9141 mono_mb_emit_op (mb
, CEE_MONO_CCASTCLASS
, klass
);
9143 /* The result of MONO_ISINST can be:
9144 0) the cast is valid
9145 1) cast of unknown proxy type
9146 or an exception if the cast is is invalid
9149 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9151 /* get the real proxy from the transparent proxy*/
9153 mono_mb_emit_ldarg (mb
, 0);
9154 mono_mb_emit_managed_call (mb
, mono_marshal_get_proxy_cancast (klass
), NULL
);
9155 pos_was_ok2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
9158 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
9161 mono_mb_patch_branch (mb
, pos_was_ok
);
9162 mono_mb_patch_branch (mb
, pos_was_ok2
);
9163 mono_mb_emit_ldarg (mb
, 0);
9166 mono_mb_emit_byte (mb
, CEE_RET
);
9168 res
= mono_mb_create_and_cache (cache
, klass
, mb
, castclass_sig
, castclass_sig
->param_count
+ 16);
9175 mono_marshal_get_proxy_cancast (MonoClass
*klass
)
9177 static MonoMethodSignature
*isint_sig
= NULL
;
9180 int pos_failed
, pos_end
;
9182 MonoMethod
*can_cast_to
;
9183 MonoMethodDesc
*desc
;
9184 MonoMethodBuilder
*mb
;
9186 cache
= get_cache (&klass
->image
->proxy_isinst_cache
, mono_aligned_addr_hash
, NULL
);
9187 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9191 isint_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9192 isint_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9193 isint_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9194 isint_sig
->pinvoke
= 0;
9197 name
= g_strdup_printf ("__proxy_isinst_wrapper_%s", klass
->name
);
9198 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_PROXY_ISINST
);
9201 mb
->method
->save_lmf
= 1;
9203 /* get the real proxy from the transparent proxy*/
9204 mono_mb_emit_ldarg (mb
, 0);
9205 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
9206 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
9208 /* get the reflection type from the type handle */
9209 mono_mb_emit_ptr (mb
, &klass
->byval_arg
);
9210 mono_mb_emit_icall (mb
, type_from_handle
);
9212 mono_mb_emit_ldarg (mb
, 0);
9214 /* make the call to CanCastTo (type, ob) */
9215 desc
= mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE
);
9216 can_cast_to
= mono_method_desc_search_in_class (desc
, mono_defaults
.iremotingtypeinfo_class
);
9217 g_assert (can_cast_to
);
9218 mono_method_desc_free (desc
);
9219 mono_mb_emit_op (mb
, CEE_CALLVIRT
, can_cast_to
);
9221 pos_failed
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9223 /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
9224 mono_mb_emit_ptr (mb
, &klass
->byval_arg
);
9225 mono_mb_emit_icall (mb
, type_from_handle
);
9226 mono_mb_emit_ldarg (mb
, 0);
9228 mono_mb_emit_icall (mb
, mono_upgrade_remote_class_wrapper
);
9229 emit_thread_interrupt_checkpoint (mb
);
9231 mono_mb_emit_ldarg (mb
, 0);
9232 pos_end
= mono_mb_emit_branch (mb
, CEE_BR
);
9236 mono_mb_patch_branch (mb
, pos_failed
);
9237 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9241 mono_mb_patch_branch (mb
, pos_end
);
9242 mono_mb_emit_byte (mb
, CEE_RET
);
9244 res
= mono_mb_create_and_cache (cache
, klass
, mb
, isint_sig
, isint_sig
->param_count
+ 16);
9251 mono_upgrade_remote_class_wrapper (MonoReflectionType
*rtype
, MonoTransparentProxy
*tproxy
)
9254 MonoDomain
*domain
= ((MonoObject
*)tproxy
)->vtable
->domain
;
9255 klass
= mono_class_from_mono_type (rtype
->type
);
9256 mono_upgrade_remote_class (domain
, (MonoObject
*)tproxy
, klass
);
9260 * mono_marshal_get_struct_to_ptr:
9263 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
9266 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
9268 MonoMethodBuilder
*mb
;
9269 static MonoMethod
*stoptr
= NULL
;
9272 g_assert (klass
!= NULL
);
9274 mono_marshal_load_type_info (klass
);
9276 if (klass
->marshal_info
->str_to_ptr
)
9277 return klass
->marshal_info
->str_to_ptr
;
9280 stoptr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "StructureToPtr", 3);
9283 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_UNKNOWN
);
9285 if (klass
->blittable
) {
9286 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9287 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9288 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9289 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9290 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9291 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9294 /* allocate local 0 (pointer) src_ptr */
9295 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9296 /* allocate local 1 (pointer) dst_ptr */
9297 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9298 /* allocate local 2 (boolean) delete_old */
9299 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
9300 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
9301 mono_mb_emit_stloc (mb
, 2);
9303 /* initialize src_ptr to point to the start of object data */
9304 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9305 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9306 mono_mb_emit_stloc (mb
, 0);
9308 /* initialize dst_ptr */
9309 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9310 mono_mb_emit_stloc (mb
, 1);
9312 emit_struct_conv (mb
, klass
, FALSE
);
9315 mono_mb_emit_byte (mb
, CEE_RET
);
9317 res
= mono_mb_create_method (mb
, mono_signature_no_pinvoke (stoptr
), 0);
9320 klass
->marshal_info
->str_to_ptr
= res
;
9325 * mono_marshal_get_ptr_to_struct:
9328 * generates IL code for PtrToStructure (IntPtr src, object structure)
9331 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
9333 MonoMethodBuilder
*mb
;
9334 static MonoMethodSignature
*ptostr
= NULL
;
9337 g_assert (klass
!= NULL
);
9339 mono_marshal_load_type_info (klass
);
9341 if (klass
->marshal_info
->ptr_to_str
)
9342 return klass
->marshal_info
->ptr_to_str
;
9345 MonoMethodSignature
*sig
;
9347 /* Create the signature corresponding to
9348 static void PtrToStructure (IntPtr ptr, object structure);
9349 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9350 sig
= mono_create_icall_signature ("void ptr object");
9351 sig
= signature_dup (mono_defaults
.corlib
, sig
);
9353 mono_memory_barrier ();
9357 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_UNKNOWN
);
9359 if (klass
->blittable
) {
9360 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9361 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9362 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9363 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9364 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9365 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9368 /* allocate local 0 (pointer) src_ptr */
9369 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9370 /* allocate local 1 (pointer) dst_ptr */
9371 mono_mb_add_local (mb
, &klass
->this_arg
);
9373 /* initialize src_ptr to point to the start of object data */
9374 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9375 mono_mb_emit_stloc (mb
, 0);
9377 /* initialize dst_ptr */
9378 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9379 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
9380 mono_mb_emit_stloc (mb
, 1);
9382 emit_struct_conv (mb
, klass
, TRUE
);
9385 mono_mb_emit_byte (mb
, CEE_RET
);
9387 res
= mono_mb_create_method (mb
, ptostr
, 0);
9390 klass
->marshal_info
->ptr_to_str
= res
;
9395 * generates IL code for the synchronized wrapper: the generated method
9396 * calls METHOD while locking 'this' or the parent type.
9399 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
9401 static MonoMethod
*enter_method
, *exit_method
, *gettypefromhandle_method
;
9402 MonoMethodSignature
*sig
;
9403 MonoExceptionClause
*clause
;
9404 MonoMethodBuilder
*mb
;
9407 int i
, pos
, this_local
, ret_local
= 0;
9411 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
9414 cache
= get_cache (&method
->klass
->image
->synchronized_cache
, mono_aligned_addr_hash
, NULL
);
9415 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9418 sig
= signature_dup (method
->klass
->image
, mono_method_signature (method
));
9421 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
9424 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9425 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
9427 if (method
->klass
->valuetype
&& !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
9428 mono_class_set_failure (method
->klass
, MONO_EXCEPTION_TYPE_LOAD
, NULL
);
9429 /* This will throw the type load exception when the wrapper is compiled */
9430 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9431 mono_mb_emit_op (mb
, CEE_ISINST
, method
->klass
);
9432 mono_mb_emit_byte (mb
, CEE_POP
);
9434 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9435 mono_mb_emit_ldloc (mb
, ret_local
);
9436 mono_mb_emit_byte (mb
, CEE_RET
);
9438 res
= mono_mb_create_and_cache (cache
, method
,
9439 mb
, sig
, sig
->param_count
+ 16);
9446 this_local
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
9448 clause
= mono_image_alloc0 (method
->klass
->image
, sizeof (MonoExceptionClause
));
9449 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
9451 mono_loader_lock ();
9453 if (!enter_method
) {
9454 MonoMethodDesc
*desc
;
9456 desc
= mono_method_desc_new ("Monitor:Enter", FALSE
);
9457 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9458 g_assert (enter_method
);
9459 mono_method_desc_free (desc
);
9461 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
9462 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9463 g_assert (exit_method
);
9464 mono_method_desc_free (desc
);
9466 desc
= mono_method_desc_new ("Type:GetTypeFromHandle", FALSE
);
9467 gettypefromhandle_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monotype_class
->parent
);
9468 g_assert (gettypefromhandle_method
);
9469 mono_method_desc_free (desc
);
9472 mono_loader_unlock ();
9474 /* Push this or the type object */
9475 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
9476 /* We have special handling for this in the JIT */
9477 int index
= mono_mb_add_data (mb
, method
->klass
);
9478 mono_mb_add_data (mb
, mono_defaults
.typehandle_class
);
9479 mono_mb_emit_byte (mb
, CEE_LDTOKEN
);
9480 mono_mb_emit_i4 (mb
, index
);
9482 mono_mb_emit_managed_call (mb
, gettypefromhandle_method
, NULL
);
9485 mono_mb_emit_ldarg (mb
, 0);
9486 mono_mb_emit_stloc (mb
, this_local
);
9488 /* Call Monitor::Enter() */
9489 mono_mb_emit_ldloc (mb
, this_local
);
9490 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
9492 clause
->try_offset
= mono_mb_get_label (mb
);
9494 /* Call the method */
9496 mono_mb_emit_ldarg (mb
, 0);
9497 for (i
= 0; i
< sig
->param_count
; i
++)
9498 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
9500 mono_mb_emit_managed_call (mb
, method
, NULL
);
9502 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9503 mono_mb_emit_stloc (mb
, ret_local
);
9505 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
9507 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
9508 clause
->handler_offset
= mono_mb_get_label (mb
);
9510 /* Call Monitor::Exit() */
9511 mono_mb_emit_ldloc (mb
, this_local
);
9512 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
9513 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
9515 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
9517 mono_mb_patch_branch (mb
, pos
);
9518 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9519 mono_mb_emit_ldloc (mb
, ret_local
);
9520 mono_mb_emit_byte (mb
, CEE_RET
);
9522 mono_mb_set_clauses (mb
, 1, clause
);
9524 res
= mono_mb_create_and_cache (cache
, method
,
9525 mb
, sig
, sig
->param_count
+ 16);
9533 * the returned method calls 'method' unboxing the this argument
9536 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
9538 MonoMethodSignature
*sig
= mono_method_signature (method
);
9540 MonoMethodBuilder
*mb
;
9544 cache
= get_cache (&method
->klass
->image
->unbox_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
9545 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9548 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
9550 g_assert (sig
->hasthis
);
9552 mono_mb_emit_ldarg (mb
, 0);
9553 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
9554 mono_mb_emit_byte (mb
, CEE_ADD
);
9555 for (i
= 0; i
< sig
->param_count
; ++i
)
9556 mono_mb_emit_ldarg (mb
, i
+ 1);
9557 mono_mb_emit_managed_call (mb
, method
, NULL
);
9558 mono_mb_emit_byte (mb
, CEE_RET
);
9560 res
= mono_mb_create_and_cache (cache
, method
,
9561 mb
, sig
, sig
->param_count
+ 16);
9564 /* code_for (res); */
9570 STELEMREF_OBJECT
, /*no check at all*/
9571 STELEMREF_SEALED_CLASS
, /*check vtable->klass->element_type */
9572 STELEMREF_CLASS
, /*only the klass->parents check*/
9573 STELEMREF_INTERFACE
, /*interfaces without variant generic arguments. */
9574 STELEMREF_COMPLEX
, /*arrays, MBR or types with variant generic args - go straight to icalls*/
9575 STELEMREF_KIND_COUNT
9578 static const char *strelemref_wrapper_name
[] = {
9579 "object", "sealed_class", "class", "interface", "complex"
9583 is_monomorphic_array (MonoClass
*klass
)
9585 MonoClass
*element_class
;
9586 if (klass
->rank
!= 1)
9589 element_class
= klass
->element_class
;
9590 return (element_class
->flags
& TYPE_ATTRIBUTE_SEALED
) || element_class
->valuetype
;
9594 get_virtual_stelemref_kind (MonoClass
*element_class
)
9596 if (element_class
== mono_defaults
.object_class
)
9597 return STELEMREF_OBJECT
;
9598 if (is_monomorphic_array (element_class
))
9599 return STELEMREF_SEALED_CLASS
;
9600 if (MONO_CLASS_IS_INTERFACE (element_class
) && !mono_class_has_variant_generic_params (element_class
))
9601 return STELEMREF_INTERFACE
;
9602 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
9603 if (element_class
->marshalbyref
|| element_class
->rank
|| mono_class_has_variant_generic_params (element_class
))
9604 return STELEMREF_COMPLEX
;
9605 if (element_class
->flags
& TYPE_ATTRIBUTE_SEALED
)
9606 return STELEMREF_SEALED_CLASS
;
9607 return STELEMREF_CLASS
;
9611 load_array_element_address (MonoMethodBuilder
*mb
)
9613 mono_mb_emit_ldarg (mb
, 0);
9614 mono_mb_emit_ldarg (mb
, 1);
9615 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
9619 load_array_class (MonoMethodBuilder
*mb
, int aklass
)
9621 mono_mb_emit_ldarg (mb
, 0);
9622 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
9623 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9624 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
9625 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9626 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, element_class
));
9627 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9628 mono_mb_emit_stloc (mb
, aklass
);
9632 load_value_class (MonoMethodBuilder
*mb
, int vklass
)
9634 mono_mb_emit_ldarg (mb
, 2);
9635 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
9636 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9637 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
9638 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9639 mono_mb_emit_stloc (mb
, vklass
);
9644 record_slot_vstore (MonoObject
*array
, size_t index
, MonoObject
*value
)
9646 char *name
= mono_type_get_full_name (array
->vtable
->klass
->element_class
);
9647 printf ("slow vstore of %s\n", name
);
9653 * The wrapper info for the wrapper contains the wrapper 'kind' + 1.
9656 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
9657 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
9658 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
9659 * - Add a case for arrays of arrays.
9662 mono_marshal_get_virtual_stelemref (MonoClass
*array_class
)
9664 static MonoMethod
*cached_methods
[STELEMREF_KIND_COUNT
] = { NULL
}; /*object iface sealed regular*/
9665 static MonoMethodSignature
*signature
;
9666 MonoMethodBuilder
*mb
;
9671 int aklass
, vklass
, vtable
, uiid
;
9672 int array_slot_addr
;
9674 g_assert (array_class
->rank
== 1);
9675 kind
= get_virtual_stelemref_kind (array_class
->element_class
);
9677 if (cached_methods
[kind
])
9678 return cached_methods
[kind
];
9680 mb
= mono_mb_new_no_dup_name (mono_defaults
.object_class
, g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name
[kind
]), MONO_WRAPPER_STELEMREF
);
9683 MonoMethodSignature
*sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
9685 /* void this::stelemref (size_t idx, void* value) */
9686 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9687 sig
->hasthis
= TRUE
;
9688 sig
->params
[0] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9689 sig
->params
[1] = &mono_defaults
.object_class
->byval_arg
;
9693 /*For now simply call plain old stelemref*/
9695 case STELEMREF_OBJECT
:
9696 /* ldelema (implicit bound check) */
9697 load_array_element_address (mb
);
9699 mono_mb_emit_ldarg (mb
, 2);
9700 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9701 mono_mb_emit_byte (mb
, CEE_RET
);
9704 case STELEMREF_COMPLEX
:
9706 <ldelema (bound check)>
9709 if (!mono_object_isinst (value, aklass))
9713 *array_slot_addr = value;
9716 throw new ArrayTypeMismatchException ();
9719 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9720 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9724 /*Use this to debug/record stores that are going thru the slow path*/
9725 MonoMethodSignature
*csig
;
9726 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
9727 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9728 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9729 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9730 csig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
9731 mono_mb_emit_ldarg (mb
, 0);
9732 mono_mb_emit_ldarg (mb
, 1);
9733 mono_mb_emit_ldarg (mb
, 2);
9734 mono_mb_emit_native_call (mb
, csig
, record_slot_vstore
);
9738 /* ldelema (implicit bound check) */
9739 load_array_element_address (mb
);
9740 mono_mb_emit_stloc (mb
, array_slot_addr
);
9742 /* if (!value) goto do_store */
9743 mono_mb_emit_ldarg (mb
, 2);
9744 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9746 /* aklass = array->vtable->klass->element_class */
9747 load_array_class (mb
, aklass
);
9749 /*if (mono_object_isinst (value, aklass)) */
9750 mono_mb_emit_ldarg (mb
, 2);
9751 mono_mb_emit_ldloc (mb
, aklass
);
9752 mono_mb_emit_icall (mb
, mono_object_isinst
);
9753 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9756 mono_mb_patch_branch (mb
, b1
);
9757 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9758 mono_mb_emit_ldarg (mb
, 2);
9759 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9760 mono_mb_emit_byte (mb
, CEE_RET
);
9763 mono_mb_patch_branch (mb
, b2
);
9765 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9768 case STELEMREF_SEALED_CLASS
:
9770 <ldelema (bound check)>
9774 aklass = array->vtable->klass->element_class;
9775 vklass = value->vtable->klass;
9777 if (vklass != aklass)
9781 *array_slot_addr = value;
9784 throw new ArrayTypeMismatchException ();
9786 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9787 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9788 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9791 /* ldelema (implicit bound check) */
9792 load_array_element_address (mb
);
9793 mono_mb_emit_stloc (mb
, array_slot_addr
);
9795 /* if (!value) goto do_store */
9796 mono_mb_emit_ldarg (mb
, 2);
9797 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9799 /* aklass = array->vtable->klass->element_class */
9800 load_array_class (mb
, aklass
);
9802 /* vklass = value->vtable->klass */
9803 load_value_class (mb
, vklass
);
9805 /*if (vklass != aklass) goto do_exception; */
9806 mono_mb_emit_ldloc (mb
, aklass
);
9807 mono_mb_emit_ldloc (mb
, vklass
);
9808 b2
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9811 mono_mb_patch_branch (mb
, b1
);
9812 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9813 mono_mb_emit_ldarg (mb
, 2);
9814 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9815 mono_mb_emit_byte (mb
, CEE_RET
);
9818 mono_mb_patch_branch (mb
, b2
);
9819 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9822 case STELEMREF_CLASS
:
9825 <ldelema (bound check)>
9829 aklass = array->vtable->klass->element_class;
9830 vklass = value->vtable->klass;
9832 if (vklass->idepth < aklass->idepth)
9835 if (vklass->supertypes [aklass->idepth - 1] != aklass)
9839 *array_slot_addr = value;
9843 throw new ArrayTypeMismatchException ();
9845 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9846 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9847 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9849 /* ldelema (implicit bound check) */
9850 load_array_element_address (mb
);
9851 mono_mb_emit_stloc (mb
, array_slot_addr
);
9853 /* if (!value) goto do_store */
9854 mono_mb_emit_ldarg (mb
, 2);
9855 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9857 /* aklass = array->vtable->klass->element_class */
9858 load_array_class (mb
, aklass
);
9860 /* vklass = value->vtable->klass */
9861 load_value_class (mb
, vklass
);
9863 /*if (mono_object_isinst (value, aklass)) */
9864 mono_mb_emit_ldarg (mb
, 2);
9865 mono_mb_emit_ldloc (mb
, aklass
);
9866 mono_mb_emit_icall (mb
, mono_object_isinst
);
9867 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9869 /* if (vklass->idepth < aklass->idepth) goto failue */
9870 mono_mb_emit_ldloc (mb
, vklass
);
9871 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
9872 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9874 mono_mb_emit_ldloc (mb
, aklass
);
9875 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
9876 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9878 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
9880 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
9881 mono_mb_emit_ldloc (mb
, vklass
);
9882 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, supertypes
));
9883 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9885 mono_mb_emit_ldloc (mb
, aklass
);
9886 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
9887 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9888 mono_mb_emit_icon (mb
, 1);
9889 mono_mb_emit_byte (mb
, CEE_SUB
);
9890 mono_mb_emit_icon (mb
, sizeof (void*));
9891 mono_mb_emit_byte (mb
, CEE_MUL
);
9892 mono_mb_emit_byte (mb
, CEE_ADD
);
9893 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9895 mono_mb_emit_ldloc (mb
, aklass
);
9896 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9899 mono_mb_patch_branch (mb
, b1
);
9900 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9901 mono_mb_emit_ldarg (mb
, 2);
9902 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9903 mono_mb_emit_byte (mb
, CEE_RET
);
9906 mono_mb_patch_branch (mb
, b2
);
9907 mono_mb_patch_branch (mb
, b3
);
9909 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9912 case STELEMREF_INTERFACE
:
9919 klass = array->obj.vtable->klass->element_class;
9921 uiid = klass->interface_id;
9922 if (uiid > vt->max_interface_id)
9924 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
9927 mono_array_setref (array, index, value);
9930 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
9932 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9933 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9934 vtable
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9935 uiid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
9937 /* ldelema (implicit bound check) */
9938 load_array_element_address (mb
);
9939 mono_mb_emit_stloc (mb
, array_slot_addr
);
9941 /* if (!value) goto do_store */
9942 mono_mb_emit_ldarg (mb
, 2);
9943 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9945 /* klass = array->vtable->klass->element_class */
9946 load_array_class (mb
, aklass
);
9948 /* vt = value->vtable */
9949 mono_mb_emit_ldarg (mb
, 2);
9950 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
9951 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9952 mono_mb_emit_stloc (mb
, vtable
);
9954 /* uiid = klass->interface_id; */
9955 mono_mb_emit_ldloc (mb
, aklass
);
9956 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, interface_id
));
9957 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9958 mono_mb_emit_stloc (mb
, uiid
);
9960 /*if (uiid > vt->max_interface_id)*/
9961 mono_mb_emit_ldloc (mb
, uiid
);
9962 mono_mb_emit_ldloc (mb
, vtable
);
9963 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
9964 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9965 b2
= mono_mb_emit_branch (mb
, CEE_BGT_UN
);
9967 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
9969 /*vt->interface_bitmap*/
9970 mono_mb_emit_ldloc (mb
, vtable
);
9971 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, interface_bitmap
));
9972 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9975 mono_mb_emit_ldloc (mb
, uiid
);
9976 mono_mb_emit_icon (mb
, 3);
9977 mono_mb_emit_byte (mb
, CEE_SHR_UN
);
9979 /*vt->interface_bitmap [(uiid) >> 3]*/
9980 mono_mb_emit_byte (mb
, CEE_ADD
); /*interface_bitmap is a guint8 array*/
9981 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
9983 /*(1 << ((uiid)&7)))*/
9984 mono_mb_emit_icon (mb
, 1);
9985 mono_mb_emit_ldloc (mb
, uiid
);
9986 mono_mb_emit_icon (mb
, 7);
9987 mono_mb_emit_byte (mb
, CEE_AND
);
9988 mono_mb_emit_byte (mb
, CEE_SHL
);
9990 /*bitwise and the whole thing*/
9991 mono_mb_emit_byte (mb
, CEE_AND
);
9992 b3
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9995 mono_mb_patch_branch (mb
, b1
);
9996 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9997 mono_mb_emit_ldarg (mb
, 2);
9998 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9999 mono_mb_emit_byte (mb
, CEE_RET
);
10001 /* do_exception: */
10002 mono_mb_patch_branch (mb
, b2
);
10003 mono_mb_patch_branch (mb
, b3
);
10004 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
10008 mono_mb_emit_ldarg (mb
, 0);
10009 mono_mb_emit_ldarg (mb
, 1);
10010 mono_mb_emit_ldarg (mb
, 2);
10011 mono_mb_emit_managed_call (mb
, mono_marshal_get_stelemref (), NULL
);
10012 mono_mb_emit_byte (mb
, CEE_RET
);
10016 res
= mono_mb_create_method (mb
, signature
, 4);
10017 res
->flags
|= METHOD_ATTRIBUTE_VIRTUAL
;
10018 mono_marshal_set_wrapper_info (res
, GUINT_TO_POINTER (kind
+ 1));
10019 cached_methods
[kind
] = res
;
10026 mono_marshal_get_stelemref ()
10028 static MonoMethod
* ret
= NULL
;
10029 MonoMethodSignature
*sig
;
10030 MonoMethodBuilder
*mb
;
10032 guint32 b1
, b2
, b3
, b4
;
10034 int aklass
, vklass
;
10035 int array_slot_addr
;
10040 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
10043 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
10045 /* void stelemref (void* array, int idx, void* value) */
10046 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
10047 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
10048 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
10049 sig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
10051 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10052 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10053 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
10057 <ldelema (bound check)>
10061 aklass = array->vtable->klass->element_class;
10062 vklass = value->vtable->klass;
10064 if (vklass->idepth < aklass->idepth)
10067 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10071 *array_slot_addr = value;
10075 if (mono_object_isinst (value, aklass))
10078 throw new ArrayTypeMismatchException ();
10081 /* ldelema (implicit bound check) */
10082 mono_mb_emit_ldarg (mb
, 0);
10083 mono_mb_emit_ldarg (mb
, 1);
10084 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
10085 mono_mb_emit_stloc (mb
, array_slot_addr
);
10087 /* if (!value) goto do_store */
10088 mono_mb_emit_ldarg (mb
, 2);
10089 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
10091 /* aklass = array->vtable->klass->element_class */
10092 mono_mb_emit_ldarg (mb
, 0);
10093 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
10094 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10095 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
10096 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10097 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, element_class
));
10098 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10099 mono_mb_emit_stloc (mb
, aklass
);
10101 /* vklass = value->vtable->klass */
10102 mono_mb_emit_ldarg (mb
, 2);
10103 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
10104 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10105 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
10106 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10107 mono_mb_emit_stloc (mb
, vklass
);
10109 /* if (vklass->idepth < aklass->idepth) goto failue */
10110 mono_mb_emit_ldloc (mb
, vklass
);
10111 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
10112 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10114 mono_mb_emit_ldloc (mb
, aklass
);
10115 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
10116 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10118 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
10120 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10121 mono_mb_emit_ldloc (mb
, vklass
);
10122 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, supertypes
));
10123 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10125 mono_mb_emit_ldloc (mb
, aklass
);
10126 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
10127 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
10128 mono_mb_emit_icon (mb
, 1);
10129 mono_mb_emit_byte (mb
, CEE_SUB
);
10130 mono_mb_emit_icon (mb
, sizeof (void*));
10131 mono_mb_emit_byte (mb
, CEE_MUL
);
10132 mono_mb_emit_byte (mb
, CEE_ADD
);
10133 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10135 mono_mb_emit_ldloc (mb
, aklass
);
10137 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
10139 copy_pos
= mono_mb_get_label (mb
);
10141 mono_mb_patch_branch (mb
, b1
);
10142 mono_mb_emit_ldloc (mb
, array_slot_addr
);
10143 mono_mb_emit_ldarg (mb
, 2);
10144 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
10146 mono_mb_emit_byte (mb
, CEE_RET
);
10149 mono_mb_patch_branch (mb
, b2
);
10150 mono_mb_patch_branch (mb
, b3
);
10152 mono_mb_emit_ldarg (mb
, 2);
10153 mono_mb_emit_ldloc (mb
, aklass
);
10154 mono_mb_emit_icall (mb
, mono_object_isinst
);
10156 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
10157 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
10158 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
10160 mono_mb_emit_byte (mb
, CEE_RET
);
10161 ret
= mono_mb_create_method (mb
, sig
, 4);
10169 MonoMethod
*method
;
10172 /* LOCKING: vars accessed under the marshal lock */
10173 static ArrayElemAddr
*elem_addr_cache
= NULL
;
10174 static int elem_addr_cache_size
= 0;
10175 static int elem_addr_cache_next
= 0;
10178 * mono_marshal_get_array_address:
10179 * @rank: rank of the array type
10180 * @elem_size: size in bytes of an element of an array.
10182 * Returns a MonoMethd that implements the code to get the address
10183 * of an element in a multi-dimenasional array of @rank dimensions.
10184 * The returned method takes an array as the first argument and then
10185 * @rank indexes for the @rank dimensions.
10188 mono_marshal_get_array_address (int rank
, int elem_size
)
10191 MonoMethodBuilder
*mb
;
10192 MonoMethodSignature
*sig
;
10193 int i
, bounds
, ind
, realidx
;
10194 int branch_pos
, *branch_positions
;
10198 mono_marshal_lock ();
10199 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
10200 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
10201 ret
= elem_addr_cache
[i
].method
;
10205 mono_marshal_unlock ();
10209 branch_positions
= g_new0 (int, rank
);
10211 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
10213 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
10214 sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
10215 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
10216 for (i
= 0; i
< rank
; ++i
) {
10217 sig
->params
[i
+ 1] = &mono_defaults
.int32_class
->byval_arg
;
10220 mb
= mono_mb_new (mono_defaults
.object_class
, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED
);
10222 bounds
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
10223 ind
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10224 realidx
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
10226 /* bounds = array->bounds; */
10227 mono_mb_emit_ldarg (mb
, 0);
10228 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoArray
, bounds
));
10229 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
10230 mono_mb_emit_stloc (mb
, bounds
);
10232 /* ind is the overall element index, realidx is the partial index in a single dimension */
10233 /* ind = idx0 - bounds [0].lower_bound */
10234 mono_mb_emit_ldarg (mb
, 1);
10235 mono_mb_emit_ldloc (mb
, bounds
);
10236 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
10237 mono_mb_emit_byte (mb
, CEE_ADD
);
10238 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10239 mono_mb_emit_byte (mb
, CEE_SUB
);
10240 mono_mb_emit_stloc (mb
, ind
);
10241 /* if (ind >= bounds [0].length) goto exeception; */
10242 mono_mb_emit_ldloc (mb
, ind
);
10243 mono_mb_emit_ldloc (mb
, bounds
);
10244 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArrayBounds
, length
));
10245 mono_mb_emit_byte (mb
, CEE_ADD
);
10246 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10247 /* note that we use unsigned comparison */
10248 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
10250 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
10251 * We could also decide to ignore the passed elem_size and get it
10252 * from the array object, to reduce the number of methods we generate:
10253 * the additional cost is 3 memory loads and a non-immediate mul.
10255 for (i
= 1; i
< rank
; ++i
) {
10256 /* realidx = idxi - bounds [i].lower_bound */
10257 mono_mb_emit_ldarg (mb
, 1 + i
);
10258 mono_mb_emit_ldloc (mb
, bounds
);
10259 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + G_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
10260 mono_mb_emit_byte (mb
, CEE_ADD
);
10261 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10262 mono_mb_emit_byte (mb
, CEE_SUB
);
10263 mono_mb_emit_stloc (mb
, realidx
);
10264 /* if (realidx >= bounds [i].length) goto exeception; */
10265 mono_mb_emit_ldloc (mb
, realidx
);
10266 mono_mb_emit_ldloc (mb
, bounds
);
10267 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + G_STRUCT_OFFSET (MonoArrayBounds
, length
));
10268 mono_mb_emit_byte (mb
, CEE_ADD
);
10269 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10270 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
10271 /* ind = ind * bounds [i].length + realidx */
10272 mono_mb_emit_ldloc (mb
, ind
);
10273 mono_mb_emit_ldloc (mb
, bounds
);
10274 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + G_STRUCT_OFFSET (MonoArrayBounds
, length
));
10275 mono_mb_emit_byte (mb
, CEE_ADD
);
10276 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
10277 mono_mb_emit_byte (mb
, CEE_MUL
);
10278 mono_mb_emit_ldloc (mb
, realidx
);
10279 mono_mb_emit_byte (mb
, CEE_ADD
);
10280 mono_mb_emit_stloc (mb
, ind
);
10283 /* return array->vector + ind * element_size */
10284 mono_mb_emit_ldarg (mb
, 0);
10285 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
10286 mono_mb_emit_ldloc (mb
, ind
);
10287 mono_mb_emit_icon (mb
, elem_size
);
10288 mono_mb_emit_byte (mb
, CEE_MUL
);
10289 mono_mb_emit_byte (mb
, CEE_ADD
);
10290 mono_mb_emit_byte (mb
, CEE_RET
);
10292 /* patch the branches to get here and throw */
10293 for (i
= 1; i
< rank
; ++i
) {
10294 mono_mb_patch_branch (mb
, branch_positions
[i
]);
10296 mono_mb_patch_branch (mb
, branch_pos
);
10297 /* throw exception */
10298 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
10300 g_free (branch_positions
);
10301 ret
= mono_mb_create_method (mb
, sig
, 4);
10304 /* cache the result */
10306 mono_marshal_lock ();
10307 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
10308 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
10309 /* FIXME: free ret */
10310 ret
= elem_addr_cache
[i
].method
;
10316 ElementAddrWrapperInfo
*info
;
10318 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
10319 int new_size
= elem_addr_cache_size
+ 4;
10320 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
10321 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
10322 g_free (elem_addr_cache
);
10323 elem_addr_cache
= new_array
;
10324 elem_addr_cache_size
= new_size
;
10326 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
10327 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
10328 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
10330 info
= mono_image_alloc0 (mono_defaults
.corlib
, sizeof (ElementAddrWrapperInfo
));
10332 info
->elem_size
= elem_size
;
10334 mono_marshal_set_wrapper_info (ret
, info
);
10336 mono_marshal_unlock ();
10341 mono_marshal_alloc (gulong size
)
10346 res
= CoTaskMemAlloc (size
);
10348 res
= g_try_malloc ((gulong
)size
);
10350 mono_gc_out_of_memory ((gulong
)size
);
10356 mono_marshal_free (gpointer ptr
)
10359 CoTaskMemFree (ptr
);
10366 mono_marshal_free_array (gpointer
*ptr
, int size
)
10373 for (i
= 0; i
< size
; i
++)
10379 mono_marshal_string_to_utf16 (MonoString
*s
)
10381 return s
? mono_string_chars (s
) : NULL
;
10385 mono_marshal_string_to_utf16_copy (MonoString
*s
)
10390 gunichar2
*res
= mono_marshal_alloc ((mono_string_length (s
) * 2) + 2);
10391 memcpy (res
, mono_string_chars (s
), mono_string_length (s
) * 2);
10392 res
[mono_string_length (s
)] = 0;
10398 * mono_marshal_set_last_error:
10400 * This function is invoked to set the last error value from a P/Invoke call
10401 * which has SetLastError set.
10404 mono_marshal_set_last_error (void)
10407 TlsSetValue (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
10409 TlsSetValue (last_error_tls_id
, GINT_TO_POINTER (errno
));
10414 mono_marshal_set_last_error_windows (int error
)
10417 TlsSetValue (last_error_tls_id
, GINT_TO_POINTER (error
));
10422 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray
*src
, gint32 start_index
,
10423 gpointer dest
, gint32 length
)
10428 MONO_ARCH_SAVE_REGS
;
10430 MONO_CHECK_ARG_NULL (src
);
10431 MONO_CHECK_ARG_NULL (dest
);
10433 if (src
->obj
.vtable
->klass
->rank
!= 1)
10434 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10435 if (start_index
< 0)
10436 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10438 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10439 if (start_index
+ length
> mono_array_length (src
))
10440 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10442 element_size
= mono_array_element_size (src
->obj
.vtable
->klass
);
10444 /* no references should be involved */
10445 source_addr
= mono_array_addr_with_size (src
, element_size
, start_index
);
10447 memcpy (dest
, source_addr
, length
* element_size
);
10451 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src
, gint32 start_index
,
10452 MonoArray
*dest
, gint32 length
)
10457 MONO_ARCH_SAVE_REGS
;
10459 MONO_CHECK_ARG_NULL (src
);
10460 MONO_CHECK_ARG_NULL (dest
);
10462 if (dest
->obj
.vtable
->klass
->rank
!= 1)
10463 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10464 if (start_index
< 0)
10465 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10467 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10468 if (start_index
+ length
> mono_array_length (dest
))
10469 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10471 element_size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
10473 /* no references should be involved */
10474 dest_addr
= mono_array_addr_with_size (dest
, element_size
, start_index
);
10476 memcpy (dest_addr
, src
, length
* element_size
);
10479 #if NO_UNALIGNED_ACCESS
10480 #define RETURN_UNALIGNED(type, addr) \
10483 memcpy(&val, p + offset, sizeof(val)); \
10486 #define WRITE_UNALIGNED(type, addr, val) \
10487 memcpy(addr, &val, sizeof(type))
10489 #define RETURN_UNALIGNED(type, addr) \
10490 return *(type*)(p + offset);
10491 #define WRITE_UNALIGNED(type, addr, val) \
10492 (*(type *)(addr) = (val))
10496 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr
, gint32 offset
)
10500 MONO_ARCH_SAVE_REGS
;
10502 RETURN_UNALIGNED(gpointer
, p
+ offset
);
10506 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr
, gint32 offset
)
10510 MONO_ARCH_SAVE_REGS
;
10512 return *(unsigned char*)(p
+ offset
);
10516 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr
, gint32 offset
)
10520 MONO_ARCH_SAVE_REGS
;
10522 RETURN_UNALIGNED(gint16
, p
+ offset
);
10526 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr
, gint32 offset
)
10530 MONO_ARCH_SAVE_REGS
;
10532 RETURN_UNALIGNED(gint32
, p
+ offset
);
10536 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr
, gint32 offset
)
10540 MONO_ARCH_SAVE_REGS
;
10542 RETURN_UNALIGNED(gint64
, p
+ offset
);
10546 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr
, gint32 offset
, unsigned char val
)
10550 MONO_ARCH_SAVE_REGS
;
10552 *(unsigned char*)(p
+ offset
) = val
;
10556 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr
, gint32 offset
, gpointer val
)
10560 MONO_ARCH_SAVE_REGS
;
10562 WRITE_UNALIGNED(gpointer
, p
+ offset
, val
);
10566 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr
, gint32 offset
, gint16 val
)
10570 MONO_ARCH_SAVE_REGS
;
10572 WRITE_UNALIGNED(gint16
, p
+ offset
, val
);
10576 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr
, gint32 offset
, gint32 val
)
10580 MONO_ARCH_SAVE_REGS
;
10582 WRITE_UNALIGNED(gint32
, p
+ offset
, val
);
10586 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr
, gint32 offset
, gint64 val
)
10590 MONO_ARCH_SAVE_REGS
;
10592 WRITE_UNALIGNED(gint64
, p
+ offset
, val
);
10596 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr
)
10598 MONO_ARCH_SAVE_REGS
;
10603 return mono_string_new (mono_domain_get (), ptr
);
10607 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr
, gint32 len
)
10609 MONO_ARCH_SAVE_REGS
;
10612 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10613 g_assert_not_reached ();
10616 return mono_string_new_len (mono_domain_get (), ptr
, len
);
10621 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16
*ptr
)
10623 MonoDomain
*domain
= mono_domain_get ();
10627 MONO_ARCH_SAVE_REGS
;
10635 return mono_string_new_utf16 (domain
, ptr
, len
);
10639 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16
*ptr
, gint32 len
)
10641 MonoDomain
*domain
= mono_domain_get ();
10643 MONO_ARCH_SAVE_REGS
;
10646 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10647 g_assert_not_reached ();
10650 return mono_string_new_utf16 (domain
, ptr
, len
);
10655 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10657 MONO_ARCH_SAVE_REGS
;
10659 return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id
)));
10663 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType
*rtype
)
10669 MONO_ARCH_SAVE_REGS
;
10671 MONO_CHECK_ARG_NULL (rtype
);
10673 type
= rtype
->type
;
10674 klass
= mono_class_from_mono_type (type
);
10675 if (!mono_class_init (klass
))
10676 mono_raise_exception (mono_class_get_exception_for_failure (klass
));
10678 layout
= (klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
);
10680 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
10682 MonoException
*exc
;
10684 msg
= g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass
->name
);
10685 exc
= mono_get_exception_argument ("t", msg
);
10687 mono_raise_exception (exc
);
10691 return mono_class_native_size (klass
, NULL
);
10695 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject
*obj
, gpointer dst
, MonoBoolean delete_old
)
10697 MonoMethod
*method
;
10700 MONO_ARCH_SAVE_REGS
;
10702 MONO_CHECK_ARG_NULL (obj
);
10703 MONO_CHECK_ARG_NULL (dst
);
10705 method
= mono_marshal_get_struct_to_ptr (obj
->vtable
->klass
);
10709 pa
[2] = &delete_old
;
10711 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
10715 ptr_to_structure (gpointer src
, MonoObject
*dst
)
10717 MonoMethod
*method
;
10720 method
= mono_marshal_get_ptr_to_struct (dst
->vtable
->klass
);
10725 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
10729 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src
, MonoObject
*dst
)
10733 MONO_ARCH_SAVE_REGS
;
10735 MONO_CHECK_ARG_NULL (src
);
10736 MONO_CHECK_ARG_NULL (dst
);
10738 t
= mono_type_get_underlying_type (mono_class_get_type (dst
->vtable
->klass
));
10740 if (t
->type
== MONO_TYPE_VALUETYPE
) {
10741 MonoException
*exc
;
10744 tmp
= g_strdup_printf ("Destination is a boxed value type.");
10745 exc
= mono_get_exception_argument ("dst", tmp
);
10748 mono_raise_exception (exc
);
10752 ptr_to_structure (src
, dst
);
10756 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src
, MonoReflectionType
*type
)
10759 MonoDomain
*domain
= mono_domain_get ();
10762 MONO_ARCH_SAVE_REGS
;
10764 MONO_CHECK_ARG_NULL (src
);
10765 MONO_CHECK_ARG_NULL (type
);
10767 klass
= mono_class_from_mono_type (type
->type
);
10768 if (!mono_class_init (klass
))
10769 mono_raise_exception (mono_class_get_exception_for_failure (klass
));
10771 res
= mono_object_new (domain
, klass
);
10773 ptr_to_structure (src
, res
);
10779 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType
*type
, MonoString
*field_name
)
10781 MonoMarshalType
*info
;
10784 int match_index
= -1;
10786 MONO_ARCH_SAVE_REGS
;
10788 MONO_CHECK_ARG_NULL (type
);
10789 MONO_CHECK_ARG_NULL (field_name
);
10791 fname
= mono_string_to_utf8 (field_name
);
10792 klass
= mono_class_from_mono_type (type
->type
);
10793 if (!mono_class_init (klass
))
10794 mono_raise_exception (mono_class_get_exception_for_failure (klass
));
10796 while (klass
&& match_index
== -1) {
10797 MonoClassField
* field
;
10799 gpointer iter
= NULL
;
10800 while ((field
= mono_class_get_fields (klass
, &iter
))) {
10801 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10803 if (!strcmp (fname
, mono_field_get_name (field
))) {
10810 if (match_index
== -1)
10811 klass
= klass
->parent
;
10816 if(match_index
== -1) {
10817 MonoException
* exc
;
10820 /* Get back original class instance */
10821 klass
= mono_class_from_mono_type (type
->type
);
10823 tmp
= g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass
->name
);
10824 exc
= mono_get_exception_argument ("fieldName", tmp
);
10827 mono_raise_exception ((MonoException
*)exc
);
10830 info
= mono_marshal_load_type_info (klass
);
10831 return info
->fields
[match_index
].offset
;
10835 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString
*string
)
10840 tres
= mono_string_to_utf8 (string
);
10844 len
= strlen (tres
) + 1;
10845 ret
= ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len
);
10846 memcpy (ret
, tres
, len
);
10851 return mono_string_to_utf8 (string
);
10856 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString
*string
)
10858 MONO_ARCH_SAVE_REGS
;
10860 if (string
== NULL
)
10863 #ifdef TARGET_WIN32
10864 gunichar2
*res
= ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal
10865 ((mono_string_length (string
) + 1) * 2);
10867 gunichar2
*res
= g_malloc ((mono_string_length (string
) + 1) * 2);
10869 memcpy (res
, mono_string_chars (string
), mono_string_length (string
) * 2);
10870 res
[mono_string_length (string
)] = 0;
10876 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
10878 MonoMarshalType
*info
;
10881 info
= mono_marshal_load_type_info (klass
);
10883 for (i
= 0; i
< info
->num_fields
; i
++) {
10884 MonoMarshalNative ntype
;
10885 MonoMarshalConv conv
;
10886 MonoType
*ftype
= info
->fields
[i
].field
->type
;
10889 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10892 ntype
= mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
10893 klass
->unicode
, &conv
);
10895 cpos
= ptr
+ info
->fields
[i
].offset
;
10898 case MONO_MARSHAL_CONV_NONE
:
10899 if (MONO_TYPE_ISSTRUCT (ftype
)) {
10900 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
10904 case MONO_MARSHAL_CONV_STR_LPWSTR
:
10905 /* We assume this field points inside a MonoString */
10907 case MONO_MARSHAL_CONV_STR_LPTSTR
:
10908 #ifdef TARGET_WIN32
10909 /* We assume this field points inside a MonoString
10913 case MONO_MARSHAL_CONV_STR_LPSTR
:
10914 case MONO_MARSHAL_CONV_STR_BSTR
:
10915 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
10916 case MONO_MARSHAL_CONV_STR_TBSTR
:
10917 mono_marshal_free (*(gpointer
*)cpos
);
10927 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionType
*type
)
10931 MONO_ARCH_SAVE_REGS
;
10933 MONO_CHECK_ARG_NULL (src
);
10934 MONO_CHECK_ARG_NULL (type
);
10936 klass
= mono_class_from_mono_type (type
->type
);
10937 if (!mono_class_init (klass
))
10938 mono_raise_exception (mono_class_get_exception_for_failure (klass
));
10940 mono_struct_delete_old (klass
, (char *)src
);
10944 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size
)
10948 MONO_ARCH_SAVE_REGS
;
10950 if ((gulong
)size
== 0)
10951 /* This returns a valid pointer for size 0 on MS.NET */
10955 res
= GlobalAlloc (GMEM_FIXED
, (gulong
)size
);
10957 res
= g_try_malloc ((gulong
)size
);
10960 mono_gc_out_of_memory ((gulong
)size
);
10966 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, int size
)
10971 mono_gc_out_of_memory ((gulong
)size
);
10976 res
= GlobalReAlloc (ptr
, (gulong
)size
, GMEM_MOVEABLE
);
10978 res
= g_try_realloc (ptr
, (gulong
)size
);
10981 mono_gc_out_of_memory ((gulong
)size
);
10987 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
10989 MONO_ARCH_SAVE_REGS
;
10999 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
)
11001 MONO_ARCH_SAVE_REGS
;
11004 return CoTaskMemAlloc (size
);
11006 return g_try_malloc ((gulong
)size
);
11011 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
11013 MONO_ARCH_SAVE_REGS
;
11016 CoTaskMemFree (ptr
);
11023 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
)
11025 MONO_ARCH_SAVE_REGS
;
11028 return CoTaskMemRealloc (ptr
, size
);
11030 return g_try_realloc (ptr
, (gulong
)size
);
11035 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray
*arrayobj
, int index
)
11037 return mono_array_addr_with_size (arrayobj
, mono_array_element_size (arrayobj
->obj
.vtable
->klass
), index
);
11041 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionType
*type
)
11043 MonoClass
*klass
= mono_type_get_class (type
->type
);
11044 if (!mono_class_init (klass
))
11045 mono_raise_exception (mono_class_get_exception_for_failure (klass
));
11047 return mono_ftnptr_to_delegate (klass
, ftn
);
11051 * mono_marshal_is_loading_type_info:
11053 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
11057 mono_marshal_is_loading_type_info (MonoClass
*klass
)
11059 GSList
*loads_list
= TlsGetValue (load_type_info_tls_id
);
11061 return g_slist_find (loads_list
, klass
) != NULL
;
11065 * mono_marshal_load_type_info:
11067 * Initialize klass->marshal_info using information from metadata. This function can
11068 * recursively call itself, and the caller is responsible to avoid that by calling
11069 * mono_marshal_is_loading_type_info () beforehand.
11071 * LOCKING: Acquires the loader lock.
11074 mono_marshal_load_type_info (MonoClass
* klass
)
11077 guint32 native_size
= 0, min_align
= 1, packing
;
11078 MonoMarshalType
*info
;
11079 MonoClassField
* field
;
11082 GSList
*loads_list
;
11084 g_assert (klass
!= NULL
);
11086 if (klass
->marshal_info
)
11087 return klass
->marshal_info
;
11089 if (!klass
->inited
)
11090 mono_class_init (klass
);
11092 mono_loader_lock ();
11094 if (klass
->marshal_info
) {
11095 mono_loader_unlock ();
11096 return klass
->marshal_info
;
11100 * This function can recursively call itself, so we keep the list of classes which are
11101 * under initialization in a TLS list.
11103 g_assert (!mono_marshal_is_loading_type_info (klass
));
11104 loads_list
= TlsGetValue (load_type_info_tls_id
);
11105 loads_list
= g_slist_prepend (loads_list
, klass
);
11106 TlsSetValue (load_type_info_tls_id
, loads_list
);
11109 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11110 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11112 if (mono_field_is_deleted (field
))
11117 layout
= klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
;
11119 /* The mempool is protected by the loader lock */
11120 info
= mono_image_alloc0 (klass
->image
, MONO_SIZEOF_MARSHAL_TYPE
+ sizeof (MonoMarshalField
) * count
);
11121 info
->num_fields
= count
;
11123 /* Try to find a size for this type in metadata */
11124 mono_metadata_packing_from_typedef (klass
->image
, klass
->type_token
, NULL
, &native_size
);
11126 if (klass
->parent
) {
11127 int parent_size
= mono_class_native_size (klass
->parent
, NULL
);
11129 /* Add parent size to real size */
11130 native_size
+= parent_size
;
11131 info
->native_size
= parent_size
;
11134 packing
= klass
->packing_size
? klass
->packing_size
: 8;
11137 while ((field
= mono_class_get_fields (klass
, &iter
))) {
11141 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
11144 if (mono_field_is_deleted (field
))
11146 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
11147 mono_metadata_field_info_with_mempool (klass
->image
, mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
11148 NULL
, NULL
, &info
->fields
[j
].mspec
);
11150 info
->fields
[j
].field
= field
;
11152 if ((mono_class_num_fields (klass
) == 1) && (klass
->instance_size
== sizeof (MonoObject
)) &&
11153 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
11154 /* This field is a hack inserted by MCS to empty structures */
11159 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
11160 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
11161 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
11162 &align
, TRUE
, klass
->unicode
);
11163 align
= klass
->packing_size
? MIN (klass
->packing_size
, align
): align
;
11164 min_align
= MAX (align
, min_align
);
11165 info
->fields
[j
].offset
= info
->native_size
;
11166 info
->fields
[j
].offset
+= align
- 1;
11167 info
->fields
[j
].offset
&= ~(align
- 1);
11168 info
->native_size
= info
->fields
[j
].offset
+ size
;
11170 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
11171 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
11172 &align
, TRUE
, klass
->unicode
);
11173 min_align
= packing
;
11174 info
->fields
[j
].offset
= field
->offset
- sizeof (MonoObject
);
11175 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
11181 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
11182 info
->native_size
= MAX (native_size
, info
->native_size
);
11184 * If the provided Size is equal or larger than the calculated size, and there
11185 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
11187 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
)
11188 if (native_size
&& native_size
== info
->native_size
&& klass
->packing_size
== 0)
11192 if (info
->native_size
& (min_align
- 1)) {
11193 info
->native_size
+= min_align
- 1;
11194 info
->native_size
&= ~(min_align
- 1);
11197 info
->min_align
= min_align
;
11199 /* Update the class's blittable info, if the layouts don't match */
11200 if (info
->native_size
!= mono_class_value_size (klass
, NULL
))
11201 klass
->blittable
= FALSE
;
11203 /* If this is an array type, ensure that we have element info */
11204 if (klass
->rank
&& !mono_marshal_is_loading_type_info (klass
->element_class
)) {
11205 mono_marshal_load_type_info (klass
->element_class
);
11208 loads_list
= TlsGetValue (load_type_info_tls_id
);
11209 loads_list
= g_slist_remove (loads_list
, klass
);
11210 TlsSetValue (load_type_info_tls_id
, loads_list
);
11212 /*We do double-checking locking on marshal_info */
11213 mono_memory_barrier ();
11215 klass
->marshal_info
= info
;
11217 mono_loader_unlock ();
11219 return klass
->marshal_info
;
11223 * mono_class_native_size:
11226 * Returns: the native size of an object instance (when marshaled
11227 * to unmanaged code)
11230 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
11232 if (!klass
->marshal_info
) {
11233 if (mono_marshal_is_loading_type_info (klass
)) {
11238 mono_marshal_load_type_info (klass
);
11243 *align
= klass
->marshal_info
->min_align
;
11245 return klass
->marshal_info
->native_size
;
11248 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
11249 the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
11250 but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
11251 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
11254 * mono_type_native_stack_size:
11255 * @t: the type to return the size it uses on the stack
11257 * Returns: the number of bytes required to hold an instance of this
11258 * type on the native stack
11261 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
11265 g_assert (t
!= NULL
);
11271 *align
= sizeof (gpointer
);
11272 return sizeof (gpointer
);
11276 case MONO_TYPE_BOOLEAN
:
11277 case MONO_TYPE_CHAR
:
11288 case MONO_TYPE_STRING
:
11289 case MONO_TYPE_OBJECT
:
11290 case MONO_TYPE_CLASS
:
11291 case MONO_TYPE_SZARRAY
:
11292 case MONO_TYPE_PTR
:
11293 case MONO_TYPE_FNPTR
:
11294 case MONO_TYPE_ARRAY
:
11295 *align
= sizeof (gpointer
);
11296 return sizeof (gpointer
);
11301 *align
= ALIGNMENT (gdouble
);
11305 *align
= ALIGNMENT (glong
);
11307 case MONO_TYPE_GENERICINST
:
11308 if (!mono_type_generic_inst_is_valuetype (t
)) {
11309 *align
= sizeof (gpointer
);
11310 return sizeof (gpointer
);
11313 case MONO_TYPE_TYPEDBYREF
:
11314 case MONO_TYPE_VALUETYPE
: {
11316 MonoClass
*klass
= mono_class_from_mono_type (t
);
11318 if (klass
->enumtype
)
11319 return mono_type_native_stack_size (mono_class_enum_basetype (klass
), align
);
11321 size
= mono_class_native_size (klass
, align
);
11322 *align
= *align
+ 3;
11332 g_error ("type 0x%02x unknown", t
->type
);
11338 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
11339 gboolean as_field
, gboolean unicode
)
11341 MonoMarshalNative native_type
= mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
11344 switch (native_type
) {
11345 case MONO_NATIVE_BOOLEAN
:
11348 case MONO_NATIVE_I1
:
11349 case MONO_NATIVE_U1
:
11352 case MONO_NATIVE_I2
:
11353 case MONO_NATIVE_U2
:
11354 case MONO_NATIVE_VARIANTBOOL
:
11357 case MONO_NATIVE_I4
:
11358 case MONO_NATIVE_U4
:
11359 case MONO_NATIVE_ERROR
:
11362 case MONO_NATIVE_I8
:
11363 case MONO_NATIVE_U8
:
11364 *align
= ALIGNMENT(guint64
);
11366 case MONO_NATIVE_R4
:
11369 case MONO_NATIVE_R8
:
11370 *align
= ALIGNMENT(double);
11372 case MONO_NATIVE_INT
:
11373 case MONO_NATIVE_UINT
:
11374 case MONO_NATIVE_LPSTR
:
11375 case MONO_NATIVE_LPWSTR
:
11376 case MONO_NATIVE_LPTSTR
:
11377 case MONO_NATIVE_BSTR
:
11378 case MONO_NATIVE_ANSIBSTR
:
11379 case MONO_NATIVE_TBSTR
:
11380 case MONO_NATIVE_LPARRAY
:
11381 case MONO_NATIVE_SAFEARRAY
:
11382 case MONO_NATIVE_IUNKNOWN
:
11383 case MONO_NATIVE_IDISPATCH
:
11384 case MONO_NATIVE_INTERFACE
:
11385 case MONO_NATIVE_ASANY
:
11386 case MONO_NATIVE_FUNC
:
11387 case MONO_NATIVE_LPSTRUCT
:
11388 *align
= ALIGNMENT(gpointer
);
11389 return sizeof (gpointer
);
11390 case MONO_NATIVE_STRUCT
:
11391 klass
= mono_class_from_mono_type (type
);
11392 if (klass
== mono_defaults
.object_class
&&
11393 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
11397 return mono_class_native_size (klass
, align
);
11398 case MONO_NATIVE_BYVALTSTR
: {
11399 int esize
= unicode
? 2: 1;
11402 return mspec
->data
.array_data
.num_elem
* esize
;
11404 case MONO_NATIVE_BYVALARRAY
: {
11405 // FIXME: Have to consider ArraySubType
11407 klass
= mono_class_from_mono_type (type
);
11408 if (klass
->element_class
== mono_defaults
.char_class
) {
11409 esize
= unicode
? 2 : 1;
11412 esize
= mono_class_native_size (klass
->element_class
, align
);
11415 return mspec
->data
.array_data
.num_elem
* esize
;
11417 case MONO_NATIVE_CUSTOM
:
11418 *align
= sizeof (gpointer
);
11419 return sizeof (gpointer
);
11421 case MONO_NATIVE_CURRENCY
:
11422 case MONO_NATIVE_VBBYREFSTR
:
11424 g_error ("native type %02x not implemented", native_type
);
11427 g_assert_not_reached ();
11432 mono_marshal_asany (MonoObject
*o
, MonoMarshalNative string_encoding
, int param_attrs
)
11440 t
= &o
->vtable
->klass
->byval_arg
;
11444 case MONO_TYPE_PTR
:
11447 case MONO_TYPE_BOOLEAN
:
11450 case MONO_TYPE_CHAR
:
11455 return mono_object_unbox (o
);
11457 case MONO_TYPE_STRING
:
11458 switch (string_encoding
) {
11459 case MONO_NATIVE_LPWSTR
:
11460 return mono_marshal_string_to_utf16_copy ((MonoString
*)o
);
11462 case MONO_NATIVE_LPSTR
:
11463 return mono_string_to_lpstr ((MonoString
*)o
);
11466 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11467 g_assert_not_reached ();
11470 case MONO_TYPE_CLASS
:
11471 case MONO_TYPE_VALUETYPE
: {
11472 MonoMethod
*method
;
11475 MonoBoolean delete_old
= FALSE
;
11477 klass
= t
->data
.klass
;
11479 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
)
11482 if (klass
->valuetype
&& (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
11483 klass
->blittable
|| klass
->enumtype
))
11484 return mono_object_unbox (o
);
11486 res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
));
11488 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11489 method
= mono_marshal_get_struct_to_ptr (o
->vtable
->klass
);
11493 pa
[2] = &delete_old
;
11495 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
11502 mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
11508 mono_marshal_free_asany (MonoObject
*o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
)
11516 t
= &o
->vtable
->klass
->byval_arg
;
11518 case MONO_TYPE_STRING
:
11519 switch (string_encoding
) {
11520 case MONO_NATIVE_LPWSTR
:
11521 case MONO_NATIVE_LPSTR
:
11522 mono_marshal_free (ptr
);
11525 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11526 g_assert_not_reached ();
11529 case MONO_TYPE_CLASS
:
11530 case MONO_TYPE_VALUETYPE
: {
11531 klass
= t
->data
.klass
;
11533 if (klass
->valuetype
&& (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
11534 klass
->blittable
|| klass
->enumtype
))
11537 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
11538 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (o
->vtable
->klass
);
11544 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
11547 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11548 mono_struct_delete_old (klass
, ptr
);
11551 mono_marshal_free (ptr
);
11560 mono_marshal_get_generic_array_helper (MonoClass
*class, MonoClass
*iface
, gchar
*name
, MonoMethod
*method
)
11562 MonoMethodSignature
*sig
, *csig
;
11563 MonoMethodBuilder
*mb
;
11567 mb
= mono_mb_new_no_dup_name (class, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
11568 mb
->method
->slot
= -1;
11570 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
11571 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
11573 sig
= mono_method_signature (method
);
11574 csig
= signature_dup (method
->klass
->image
, sig
);
11575 csig
->generic_param_count
= 0;
11577 mono_mb_emit_ldarg (mb
, 0);
11578 for (i
= 0; i
< csig
->param_count
; i
++)
11579 mono_mb_emit_ldarg (mb
, i
+ 1);
11580 mono_mb_emit_managed_call (mb
, method
, NULL
);
11581 mono_mb_emit_byte (mb
, CEE_RET
);
11583 /* We can corlib internal methods */
11584 mb
->skip_visibility
= TRUE
;
11586 res
= mono_mb_create_method (mb
, csig
, csig
->param_count
+ 16);
11594 * The mono_win32_compat_* functions are implementations of inline
11595 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11596 * although not exported by kernel32.
11598 * We map the appropiate kernel32 entries to these functions using
11599 * dllmaps declared in the global etc/mono/config.
11603 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
11605 if (!dest
|| !source
)
11608 memcpy (dest
, source
, length
);
11612 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
11614 memset (dest
, fill
, length
);
11618 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
11620 if (!dest
|| !source
)
11623 memmove (dest
, source
, length
);
11627 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
11629 memset (dest
, 0, length
);
11633 mono_marshal_find_nonzero_bit_offset (guint8
*buf
, int len
, int *byte_offset
, guint8
*bitmask
)
11638 for (i
= 0; i
< len
; ++i
)
11642 g_assert (i
< len
);
11645 while (byte
&& !(byte
& 1))
11647 g_assert (byte
== 1);
11650 *bitmask
= buf
[i
];
11654 mono_marshal_get_thunk_invoke_wrapper (MonoMethod
*method
)
11656 MonoMethodBuilder
*mb
;
11657 MonoMethodSignature
*sig
, *csig
;
11658 MonoExceptionClause
*clause
;
11663 int i
, param_count
, sig_size
, pos_leave
;
11667 klass
= method
->klass
;
11668 image
= method
->klass
->image
;
11669 cache
= get_cache (&image
->thunk_invoke_cache
, mono_aligned_addr_hash
, NULL
);
11671 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
11674 sig
= mono_method_signature (method
);
11675 mb
= mono_mb_new (klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
11677 /* add "this" and exception param */
11678 param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
11680 /* dup & extend signature */
11681 csig
= mono_metadata_signature_alloc (image
, param_count
);
11682 sig_size
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
11683 memcpy (csig
, sig
, sig_size
);
11684 csig
->param_count
= param_count
;
11687 csig
->call_convention
= MONO_CALL_DEFAULT
;
11689 if (sig
->hasthis
) {
11691 csig
->params
[0] = &klass
->byval_arg
;
11692 /* move params up by one */
11693 for (i
= 0; i
< sig
->param_count
; i
++)
11694 csig
->params
[i
+ 1] = sig
->params
[i
];
11697 /* setup exception param as byref+[out] */
11698 csig
->params
[param_count
- 1] = mono_metadata_type_dup (image
,
11699 &mono_defaults
.exception_class
->byval_arg
);
11700 csig
->params
[param_count
- 1]->byref
= 1;
11701 csig
->params
[param_count
- 1]->attrs
= PARAM_ATTRIBUTE_OUT
;
11703 /* convert struct return to object */
11704 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
11705 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
11707 /* local 0 (temp for exception object) */
11708 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
11710 /* local 1 (temp for result) */
11711 if (!MONO_TYPE_IS_VOID (sig
->ret
))
11712 mono_mb_add_local (mb
, sig
->ret
);
11714 /* clear exception arg */
11715 mono_mb_emit_ldarg (mb
, param_count
- 1);
11716 mono_mb_emit_byte (mb
, CEE_LDNULL
);
11717 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
11720 clause
= mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
11721 clause
->try_offset
= mono_mb_get_label (mb
);
11723 /* push method's args */
11724 for (i
= 0; i
< param_count
- 1; i
++) {
11728 mono_mb_emit_ldarg (mb
, i
);
11730 /* get the byval type of the param */
11731 klass
= mono_class_from_mono_type (csig
->params
[i
]);
11732 type
= &klass
->byval_arg
;
11734 /* unbox struct args */
11735 if (MONO_TYPE_ISSTRUCT (type
)) {
11736 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
11738 /* byref args & and the "this" arg must remain a ptr.
11739 Otherwise make a copy of the value type */
11740 if (!(csig
->params
[i
]->byref
|| (i
== 0 && sig
->hasthis
)))
11741 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
11743 csig
->params
[i
] = &mono_defaults
.object_class
->byval_arg
;
11748 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
11749 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
11751 mono_mb_emit_op (mb
, CEE_CALL
, method
);
11753 /* save result at local 1 */
11754 if (!MONO_TYPE_IS_VOID (sig
->ret
))
11755 mono_mb_emit_stloc (mb
, 1);
11757 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
11760 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
11761 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
11762 clause
->data
.catch_class
= mono_defaults
.object_class
;
11764 clause
->handler_offset
= mono_mb_get_label (mb
);
11766 /* store exception at local 0 */
11767 mono_mb_emit_stloc (mb
, 0);
11768 mono_mb_emit_ldarg (mb
, param_count
- 1);
11769 mono_mb_emit_ldloc (mb
, 0);
11770 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
11771 mono_mb_emit_branch (mb
, CEE_LEAVE
);
11773 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
11775 mono_mb_set_clauses (mb
, 1, clause
);
11777 mono_mb_patch_branch (mb
, pos_leave
);
11780 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
11781 mono_mb_emit_ldloc (mb
, 1);
11783 /* box the return value */
11784 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
11785 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
11788 mono_mb_emit_byte (mb
, CEE_RET
);
11790 res
= mono_mb_create_and_cache (cache
, method
, mb
, csig
, param_count
+ 16);
11797 * mono_marshal_free_dynamic_wrappers:
11799 * Free wrappers of the dynamic method METHOD.
11802 mono_marshal_free_dynamic_wrappers (MonoMethod
*method
)
11804 MonoImage
*image
= method
->klass
->image
;
11806 g_assert (method
->dynamic
);
11808 /* This could be called during shutdown */
11809 if (marshal_mutex_initialized
)
11810 mono_marshal_lock ();
11812 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
11813 * they could be shared with other methods ?
11815 if (image
->runtime_invoke_direct_cache
)
11816 g_hash_table_remove (image
->runtime_invoke_direct_cache
, method
);
11817 if (image
->delegate_bound_static_invoke_cache
)
11818 g_hash_table_foreach_remove (image
->delegate_bound_static_invoke_cache
, signature_method_pair_matches_method
, method
);
11819 if (image
->delegate_abstract_invoke_cache
)
11820 g_hash_table_foreach_remove (image
->delegate_abstract_invoke_cache
, signature_method_pair_matches_method
, method
);
11822 if (marshal_mutex_initialized
)
11823 mono_marshal_unlock ();
11827 * mono_marshal_free_inflated_wrappers:
11829 * Free wrappers of the inflated method METHOD.
11833 signature_method_pair_matches_signature (gpointer key
, gpointer value
, gpointer user_data
)
11835 SignatureMethodPair
*pair
= (SignatureMethodPair
*)key
;
11836 MonoMethodSignature
*sig
= (MonoMethodSignature
*)user_data
;
11838 return mono_metadata_signature_equal (pair
->sig
, sig
);
11842 mono_marshal_free_inflated_wrappers (MonoMethod
*method
)
11844 MonoMethodSignature
*sig
= method
->signature
;
11846 g_assert (method
->is_inflated
);
11848 /* Ignore calls occuring late during cleanup. */
11849 if (!marshal_mutex_initialized
)
11852 mono_marshal_lock ();
11854 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
11855 * they could be shared with other methods ?
11859 * indexed by MonoMethodSignature
11861 /* FIXME: This could remove unrelated wrappers as well */
11862 if (sig
&& method
->klass
->image
->delegate_begin_invoke_cache
)
11863 g_hash_table_remove (method
->klass
->image
->delegate_begin_invoke_cache
, sig
);
11864 if (sig
&& method
->klass
->image
->delegate_end_invoke_cache
)
11865 g_hash_table_remove (method
->klass
->image
->delegate_end_invoke_cache
, sig
);
11866 if (sig
&& method
->klass
->image
->delegate_invoke_cache
)
11867 g_hash_table_remove (method
->klass
->image
->delegate_invoke_cache
, sig
);
11868 if (sig
&& method
->klass
->image
->runtime_invoke_cache
)
11869 g_hash_table_remove (method
->klass
->image
->runtime_invoke_cache
, sig
);
11872 * indexed by SignatureMethodPair
11874 if (sig
&& method
->klass
->image
->delegate_abstract_invoke_cache
)
11875 g_hash_table_foreach_remove (method
->klass
->image
->delegate_abstract_invoke_cache
,
11876 signature_method_pair_matches_signature
, (gpointer
)sig
);
11878 if (sig
&& method
->klass
->image
->delegate_bound_static_invoke_cache
)
11879 g_hash_table_foreach_remove (method
->klass
->image
->delegate_bound_static_invoke_cache
,
11880 signature_method_pair_matches_signature
, (gpointer
)sig
);
11883 * indexed by MonoMethod pointers
11885 if (method
->klass
->image
->runtime_invoke_direct_cache
)
11886 g_hash_table_remove (method
->klass
->image
->runtime_invoke_direct_cache
, method
);
11887 if (method
->klass
->image
->managed_wrapper_cache
)
11888 g_hash_table_remove (method
->klass
->image
->managed_wrapper_cache
, method
);
11889 if (method
->klass
->image
->native_wrapper_cache
)
11890 g_hash_table_remove (method
->klass
->image
->native_wrapper_cache
, method
);
11891 if (method
->klass
->image
->remoting_invoke_cache
)
11892 g_hash_table_remove (method
->klass
->image
->remoting_invoke_cache
, method
);
11893 if (method
->klass
->image
->synchronized_cache
)
11894 g_hash_table_remove (method
->klass
->image
->synchronized_cache
, method
);
11895 if (method
->klass
->image
->unbox_wrapper_cache
)
11896 g_hash_table_remove (method
->klass
->image
->unbox_wrapper_cache
, method
);
11897 if (method
->klass
->image
->cominterop_invoke_cache
)
11898 g_hash_table_remove (method
->klass
->image
->cominterop_invoke_cache
, method
);
11899 if (method
->klass
->image
->cominterop_wrapper_cache
)
11900 g_hash_table_remove (method
->klass
->image
->cominterop_wrapper_cache
, method
);
11901 if (method
->klass
->image
->thunk_invoke_cache
)
11902 g_hash_table_remove (method
->klass
->image
->thunk_invoke_cache
, method
);
11904 mono_marshal_unlock ();