2 * marshal.c: Routines for marshaling complex types in P/Invoke methods.
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2002 Ximian, Inc. http://www.ximian.com
14 #include "metadata/marshal.h"
15 #include "metadata/tabledefs.h"
16 #include "metadata/exception.h"
17 #include "metadata/appdomain.h"
18 #include "mono/metadata/debug-helpers.h"
19 #include "mono/metadata/threadpool.h"
20 #include "mono/metadata/threads.h"
21 #include "mono/metadata/monitor.h"
22 #include "mono/metadata/metadata-internals.h"
23 #include "mono/metadata/domain-internals.h"
24 #include "mono/metadata/gc-internal.h"
25 #include "mono/metadata/threads-types.h"
26 #include "mono/metadata/string-icalls.h"
27 #include <mono/os/gc_wrapper.h>
31 /* #define DEBUG_RUNTIME_CODE */
33 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
37 MONO_MARSHAL_NONE
, /* No marshalling needed */
38 MONO_MARSHAL_COPY
, /* Can be copied by value to the new domain */
39 MONO_MARSHAL_COPY_OUT
, /* out parameter that needs to be copied back to the original instance */
40 MONO_MARSHAL_SERIALIZE
/* Value needs to be serialized into the new domain */
41 } MonoXDomainMarshalType
;
44 #include "mono/cil/opcode.def"
49 struct _MonoMethodBuilder
{
55 guint32 code_size
, pos
;
59 struct _MonoRemotingMethods
{
61 MonoMethod
*invoke_with_check
;
62 MonoMethod
*xdomain_invoke
;
63 MonoMethod
*xdomain_dispatch
;
66 typedef struct _MonoRemotingMethods MonoRemotingMethods
;
68 #ifdef DEBUG_RUNTIME_CODE
70 indenter (MonoDisHelper
*dh
, MonoMethod
*method
, guint32 ip_offset
)
72 return g_strdup (" ");
75 static MonoDisHelper marshal_dh
= {
86 * This mutex protects the various marshalling related caches in MonoImage
87 * and a few other data structures static to this file.
88 * Note that when this lock is held it is not possible to take other runtime
89 * locks like the loader lock.
91 #define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
92 #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
93 static CRITICAL_SECTION marshal_mutex
;
95 /* This mutex protects the various cominterop related caches in MonoImage */
96 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
97 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
98 static CRITICAL_SECTION cominterop_mutex
;
100 /* Maps wrapper methods to the methods they wrap */
101 static GHashTable
*wrapper_hash
;
103 static guint32 last_error_tls_id
;
105 static guint32 load_type_info_tls_id
;
108 delegate_hash_table_add (MonoDelegate
*d
);
111 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
114 mono_struct_delete_old (MonoClass
*klass
, char *ptr
);
117 mono_marshal_string_to_utf16 (MonoString
*s
);
120 mono_marshal_string_to_utf16_copy (MonoString
*s
);
123 mono_string_to_lpstr (MonoString
*string_obj
);
126 mono_string_from_bstr (gpointer bstr
);
129 mono_free_bstr (gpointer bstr
);
132 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*eltype
, guint32 elnum
);
135 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*eltype
, guint32 elnum
);
138 mono_remoting_wrapper (MonoMethod
*method
, gpointer
*params
);
140 static MonoAsyncResult
*
141 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
);
144 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
);
147 mono_marshal_xdomain_copy_value (MonoObject
*val
);
150 mono_marshal_xdomain_copy_out_value (MonoObject
*src
, MonoObject
*dst
);
153 mono_marshal_set_domain_by_id (gint32 id
, MonoBoolean push
);
156 mono_marshal_check_domain_image (gint32 domain_id
, MonoImage
*image
);
159 mono_upgrade_remote_class_wrapper (MonoReflectionType
*rtype
, MonoTransparentProxy
*tproxy
);
161 static MonoReflectionType
*
162 type_from_handle (MonoType
*handle
);
165 mono_marshal_set_last_error_windows (int error
);
168 mono_marshal_emit_native_wrapper (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
);
170 static void init_safe_handle (void);
172 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
173 static MonoMethod
*sh_dangerous_add_ref
;
174 static MonoMethod
*sh_dangerous_release
;
180 sh_dangerous_add_ref
= mono_class_get_method_from_name (
181 mono_defaults
.safehandle_class
, "DangerousAddRef", 1);
182 sh_dangerous_release
= mono_class_get_method_from_name (
183 mono_defaults
.safehandle_class
, "DangerousRelease", 0);
187 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
189 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
191 mono_register_jit_icall (func
, name
, sig
, save
);
194 static MonoMethodSignature
*
195 signature_dup (MonoImage
*image
, MonoMethodSignature
*sig
)
197 MonoMethodSignature
*res
;
200 sigsize
= sizeof (MonoMethodSignature
) + ((sig
->param_count
- MONO_ZERO_LEN_ARRAY
) * sizeof (MonoType
*));
202 res
= mono_mempool_alloc (image
->mempool
, sigsize
);
203 mono_loader_unlock ();
204 memcpy (res
, sig
, sigsize
);
209 static MonoMethodSignature
*
210 signature_no_pinvoke (MonoMethod
*method
)
212 MonoMethodSignature
*sig
= mono_method_signature (method
);
214 sig
= signature_dup (method
->klass
->image
, sig
);
215 sig
->pinvoke
= FALSE
;
221 /* Begin COM Interop related stuff until seperate file */
224 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
225 #ifdef PLATFORM_WIN32
226 #define STDCALL __stdcall
231 /* Upon creation of a CCW, only allocate a weak handle and set the
232 * reference count to 0. If the unmanaged client code decides to addref and
233 * hold onto the CCW, I then allocate a strong handle. Once the reference count
234 * goes back to 0, convert back to a weak handle.
239 GHashTable
* vtable_hash
;
242 /* This type is the actual pointer passed to unmanaged code
243 * to represent a COM interface.
251 static int STDCALL
cominterop_ccw_addref (MonoCCWInterface
* ccwe
);
253 static int STDCALL
cominterop_ccw_release (MonoCCWInterface
* ccwe
);
255 static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, guint8
* riid
, gpointer
* ppv
);
258 static int STDCALL
cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
);
260 static int STDCALL
cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
);
262 static int STDCALL
cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
263 gunichar2
** rgszNames
, guint32 cNames
,
264 guint32 lcid
, gint32
*rgDispId
);
266 static int STDCALL
cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
267 gpointer riid
, guint32 lcid
,
268 guint16 wFlags
, gpointer pDispParams
,
269 gpointer pVarResult
, gpointer pExcepInfo
,
273 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
);
276 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
);
279 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
);
282 * cominterop_method_signature:
285 * Returns: the corresponding unmanaged method signature for a managed COM
288 static MonoMethodSignature
*
289 cominterop_method_signature (MonoMethod
* method
)
291 MonoMethodSignature
*res
;
292 MonoImage
*image
= method
->klass
->image
;
293 MonoMethodSignature
*sig
= mono_method_signature (method
);
294 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
297 int param_count
= sig
->param_count
+ 1; // convert this arg into IntPtr arg
299 if (!preserve_sig
&&!MONO_TYPE_IS_VOID (sig
->ret
))
302 sigsize
= sizeof (MonoMethodSignature
) + ((param_count
- MONO_ZERO_LEN_ARRAY
) * sizeof (MonoType
*));
304 res
= mono_mempool_alloc (image
->mempool
, sigsize
);
305 mono_loader_unlock ();
306 memcpy (res
, sig
, sigsize
);
308 // now move args forward one
309 for (i
= sig
->param_count
-1; i
>= 0; i
--)
310 res
->params
[i
+1] = sig
->params
[i
];
312 // first arg is interface pointer
313 res
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
319 // last arg is return type
320 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
321 res
->params
[param_count
-1] = mono_metadata_type_dup (image
->mempool
, sig
->ret
);
322 res
->params
[param_count
-1]->byref
= 1;
323 res
->params
[param_count
-1]->attrs
= PARAM_ATTRIBUTE_OUT
;
326 // return type is always int32 (HRESULT)
327 res
->ret
= &mono_defaults
.int32_class
->byval_arg
;
331 res
->pinvoke
= FALSE
;
337 res
->param_count
= param_count
;
339 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
340 #ifdef PLATFORM_WIN32
341 res
->call_convention
= MONO_CALL_STDCALL
;
343 res
->call_convention
= MONO_CALL_C
;
350 * cominterop_get_function_pointer:
351 * @itf: a pointer to the COM interface
352 * @slot: the vtable slot of the method pointer to return
354 * Returns: the unmanaged vtable function pointer from the interface
357 cominterop_get_function_pointer (gpointer itf
, int slot
)
360 func
= *((*(gpointer
**)itf
)+slot
);
365 * cominterop_object_is_com_object:
366 * @obj: a pointer to the object
368 * Returns: a value indicating if the object is a
369 * Runtime Callable Wrapper (RCW) for a COM object
372 cominterop_object_is_rcw (MonoObject
*obj
)
374 MonoClass
*klass
= NULL
;
375 MonoRealProxy
* real_proxy
= NULL
;
378 klass
= mono_object_class (obj
);
379 if (klass
!= mono_defaults
.transparent_proxy_class
)
382 real_proxy
= ((MonoTransparentProxy
*)obj
)->rp
;
386 klass
= mono_object_class (real_proxy
);
387 return (klass
&& klass
== mono_defaults
.com_interop_proxy_class
);
391 cominterop_get_com_slot_begin (MonoClass
* klass
)
393 static MonoClass
*interface_type_attribute
= NULL
;
394 MonoCustomAttrInfo
*cinfo
= NULL
;
395 MonoInterfaceTypeAttribute
* itf_attr
= NULL
;
397 if (!interface_type_attribute
)
398 interface_type_attribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
399 cinfo
= mono_custom_attrs_from_class (klass
);
401 itf_attr
= (MonoInterfaceTypeAttribute
*)mono_custom_attrs_get_attr (cinfo
, interface_type_attribute
);
403 mono_custom_attrs_free (cinfo
);
406 if (itf_attr
&& itf_attr
->intType
== 1)
407 return 3; /* 3 methods in IUnknown*/
409 return 7; /* 7 methods in IDispatch*/
413 * cominterop_get_method_interface:
414 * @method: method being called
416 * Returns: the MonoClass* representing the interface on which
417 * the method is defined.
420 cominterop_get_method_interface (MonoMethod
* method
)
422 MonoClass
*ic
= method
->klass
;
424 /* if method is on a class, we need to look up interface method exists on */
425 if (!MONO_CLASS_IS_INTERFACE(method
->klass
)) {
426 GPtrArray
*ifaces
= mono_class_get_implemented_interfaces (method
->klass
);
429 for (i
= 0; i
< ifaces
->len
; ++i
) {
431 ic
= g_ptr_array_index (ifaces
, i
);
432 offset
= mono_class_interface_offset (method
->klass
, ic
);
433 if (method
->slot
>= offset
&& method
->slot
< offset
+ ic
->method
.count
)
437 g_ptr_array_free (ifaces
, TRUE
);
442 g_assert (MONO_CLASS_IS_INTERFACE (ic
));
448 * cominterop_get_com_slot_for_method:
451 * Returns: the method's slot in the COM interface vtable
454 cominterop_get_com_slot_for_method (MonoMethod
* method
)
456 guint32 slot
= method
->slot
;
457 MonoClass
*ic
= method
->klass
;
459 /* if method is on a class, we need to look up interface method exists on */
460 if (!MONO_CLASS_IS_INTERFACE(ic
)) {
462 ic
= cominterop_get_method_interface (method
);
463 offset
= mono_class_interface_offset (method
->klass
, ic
);
464 g_assert(offset
>= 0);
469 g_assert (MONO_CLASS_IS_INTERFACE (ic
));
471 return slot
+ cominterop_get_com_slot_begin (ic
);
476 cominterop_mono_string_to_guid (const MonoString
* string
, guint8
*guid
);
479 cominterop_class_guid (MonoClass
* klass
, guint8
* guid
)
481 static MonoClass
*GuidAttribute
= NULL
;
482 MonoCustomAttrInfo
*cinfo
;
484 /* Handle the GuidAttribute */
486 GuidAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "GuidAttribute");
488 cinfo
= mono_custom_attrs_from_class (klass
);
490 MonoReflectionGuidAttribute
*attr
= (MonoReflectionGuidAttribute
*)mono_custom_attrs_get_attr (cinfo
, GuidAttribute
);
495 mono_custom_attrs_free (cinfo
);
497 cominterop_mono_string_to_guid (attr
->guid
, guid
);
504 * cominterop_get_interface:
505 * @obj: managed wrapper object containing COM object
506 * @ic: interface type to retrieve for COM object
508 * Returns: the COM interface requested
511 cominterop_get_interface (MonoComObject
* obj
, MonoClass
* ic
, gboolean throw_exception
)
516 g_assert (MONO_CLASS_IS_INTERFACE (ic
));
518 mono_cominterop_lock ();
520 itf
= g_hash_table_lookup (obj
->itf_hash
, GUINT_TO_POINTER ((guint
)ic
->interface_id
));
521 mono_cominterop_unlock ();
525 int found
= cominterop_class_guid (ic
, iid
);
528 hr
= ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj
->iunknown
, iid
, &itf
);
529 if (hr
< 0 && throw_exception
) {
530 static MonoMethod
* throw_exception_for_hr
= NULL
;
532 void* params
[1] = {&hr
};
533 if (!throw_exception_for_hr
)
534 throw_exception_for_hr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetExceptionForHR", 1);
535 ex
= (MonoException
*)mono_runtime_invoke (throw_exception_for_hr
, NULL
, params
, NULL
);
536 mono_raise_exception (ex
);
539 if (hr
>= 0 && itf
) {
540 mono_cominterop_lock ();
542 obj
->itf_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
543 g_hash_table_insert (obj
->itf_hash
, GUINT_TO_POINTER ((guint
)ic
->interface_id
), itf
);
544 mono_cominterop_unlock ();
555 cominterop_get_hresult_for_exception (MonoException
* exc
)
562 mono_marshal_init (void)
564 static gboolean module_initialized
= FALSE
;
566 if (!module_initialized
) {
567 module_initialized
= TRUE
;
568 InitializeCriticalSection (&marshal_mutex
);
569 InitializeCriticalSection (&cominterop_mutex
);
570 wrapper_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
571 last_error_tls_id
= TlsAlloc ();
572 load_type_info_tls_id
= TlsAlloc ();
574 register_icall (mono_marshal_string_to_utf16
, "mono_marshal_string_to_utf16", "ptr obj", FALSE
);
575 register_icall (mono_marshal_string_to_utf16_copy
, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE
);
576 register_icall (mono_string_to_utf16
, "mono_string_to_utf16", "ptr obj", FALSE
);
577 register_icall (mono_string_from_utf16
, "mono_string_from_utf16", "obj ptr", FALSE
);
578 register_icall (mono_string_new_wrapper
, "mono_string_new_wrapper", "obj ptr", FALSE
);
579 register_icall (mono_string_to_utf8
, "mono_string_to_utf8", "ptr obj", FALSE
);
580 register_icall (mono_string_to_lpstr
, "mono_string_to_lpstr", "ptr obj", FALSE
);
581 register_icall (mono_string_to_bstr
, "mono_string_to_bstr", "ptr obj", FALSE
);
582 register_icall (mono_string_from_bstr
, "mono_string_from_bstr", "obj ptr", FALSE
);
583 register_icall (mono_free_bstr
, "mono_free_bstr", "void ptr", FALSE
);
584 register_icall (mono_string_to_ansibstr
, "mono_string_to_ansibstr", "ptr object", FALSE
);
585 register_icall (mono_string_builder_to_utf8
, "mono_string_builder_to_utf8", "ptr object", FALSE
);
586 register_icall (mono_string_builder_to_utf16
, "mono_string_builder_to_utf16", "ptr object", FALSE
);
587 register_icall (mono_array_to_savearray
, "mono_array_to_savearray", "ptr object", FALSE
);
588 register_icall (mono_array_to_lparray
, "mono_array_to_lparray", "ptr object", FALSE
);
589 register_icall (mono_byvalarray_to_array
, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE
);
590 register_icall (mono_array_to_byvalarray
, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE
);
591 register_icall (mono_delegate_to_ftnptr
, "mono_delegate_to_ftnptr", "ptr object", FALSE
);
592 register_icall (mono_ftnptr_to_delegate
, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE
);
593 register_icall (mono_marshal_asany
, "mono_marshal_asany", "ptr object int32 int32", FALSE
);
594 register_icall (mono_marshal_free_asany
, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE
);
595 register_icall (mono_marshal_alloc
, "mono_marshal_alloc", "ptr int32", FALSE
);
596 register_icall (mono_marshal_free
, "mono_marshal_free", "void ptr", FALSE
);
597 register_icall (mono_marshal_set_last_error
, "mono_marshal_set_last_error", "void", FALSE
);
598 register_icall (mono_marshal_set_last_error_windows
, "mono_marshal_set_last_error_windows", "void int32", FALSE
);
599 register_icall (mono_string_utf8_to_builder
, "mono_string_utf8_to_builder", "void ptr ptr", FALSE
);
600 register_icall (mono_string_utf16_to_builder
, "mono_string_utf16_to_builder", "void ptr ptr", FALSE
);
601 register_icall (mono_marshal_free_array
, "mono_marshal_free_array", "void ptr int32", FALSE
);
602 register_icall (mono_string_to_byvalstr
, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE
);
603 register_icall (mono_string_to_byvalwstr
, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE
);
604 register_icall (g_free
, "g_free", "void ptr", FALSE
);
605 register_icall (mono_object_isinst
, "mono_object_isinst", "object object ptr", FALSE
);
606 register_icall (mono_struct_delete_old
, "mono_struct_delete_old", "void ptr ptr", FALSE
);
607 register_icall (mono_remoting_wrapper
, "mono_remoting_wrapper", "object ptr ptr", FALSE
);
608 register_icall (mono_delegate_begin_invoke
, "mono_delegate_begin_invoke", "object object ptr", FALSE
);
609 register_icall (mono_delegate_end_invoke
, "mono_delegate_end_invoke", "object object ptr", FALSE
);
610 register_icall (mono_marshal_xdomain_copy_value
, "mono_marshal_xdomain_copy_value", "object object", FALSE
);
611 register_icall (mono_marshal_xdomain_copy_out_value
, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE
);
612 register_icall (mono_marshal_set_domain_by_id
, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE
);
613 register_icall (mono_marshal_check_domain_image
, "mono_marshal_check_domain_image", "int32 int32 ptr", FALSE
);
614 register_icall (mono_compile_method
, "mono_compile_method", "ptr ptr", FALSE
);
615 register_icall (mono_context_get
, "mono_context_get", "object", FALSE
);
616 register_icall (mono_context_set
, "mono_context_set", "void object", FALSE
);
617 register_icall (mono_upgrade_remote_class_wrapper
, "mono_upgrade_remote_class_wrapper", "void object object", FALSE
);
618 register_icall (type_from_handle
, "type_from_handle", "object ptr", FALSE
);
619 register_icall (mono_gc_wbarrier_generic_store
, "wb_generic", "void ptr object", FALSE
);
620 register_icall (cominterop_get_method_interface
, "cominterop_get_method_interface", "ptr ptr", FALSE
);
621 register_icall (cominterop_get_function_pointer
, "cominterop_get_function_pointer", "ptr ptr int32", FALSE
);
622 register_icall (cominterop_object_is_rcw
, "cominterop_object_is_rcw", "int32 object", FALSE
);
623 register_icall (cominterop_get_ccw
, "cominterop_get_ccw", "ptr object ptr", FALSE
);
624 register_icall (cominterop_get_ccw_object
, "cominterop_get_ccw_object", "object ptr int32", FALSE
);
625 register_icall (cominterop_get_hresult_for_exception
, "cominterop_get_hresult_for_exception", "int32 object", FALSE
);
626 register_icall (cominterop_get_interface
, "cominterop_get_interface", "ptr object ptr int32", FALSE
);
631 mono_marshal_cleanup (void)
633 g_hash_table_destroy (wrapper_hash
);
634 TlsFree (load_type_info_tls_id
);
635 TlsFree (last_error_tls_id
);
636 DeleteCriticalSection (&marshal_mutex
);
637 DeleteCriticalSection (&cominterop_mutex
);
640 MonoClass
*byte_array_class
;
641 static MonoMethod
*method_rs_serialize
, *method_rs_deserialize
, *method_exc_fixexc
, *method_rs_appdomain_target
;
642 static MonoMethod
*method_set_context
, *method_get_context
;
643 static MonoMethod
*method_set_call_context
, *method_needs_context_sink
, *method_rs_serialize_exc
;
646 mono_remoting_marshal_init (void)
650 static gboolean module_initialized
= FALSE
;
652 if (!module_initialized
) {
653 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting", "RemotingServices");
654 method_rs_serialize
= mono_class_get_method_from_name (klass
, "SerializeCallData", -1);
655 method_rs_deserialize
= mono_class_get_method_from_name (klass
, "DeserializeCallData", -1);
656 method_rs_serialize_exc
= mono_class_get_method_from_name (klass
, "SerializeExceptionData", -1);
658 klass
= mono_defaults
.real_proxy_class
;
659 method_rs_appdomain_target
= mono_class_get_method_from_name (klass
, "GetAppDomainTarget", -1);
661 klass
= mono_defaults
.exception_class
;
662 method_exc_fixexc
= mono_class_get_method_from_name (klass
, "FixRemotingException", -1);
664 klass
= mono_defaults
.thread_class
;
665 method_get_context
= mono_class_get_method_from_name (klass
, "get_CurrentContext", -1);
667 klass
= mono_defaults
.appdomain_class
;
668 method_set_context
= mono_class_get_method_from_name (klass
, "InternalSetContext", -1);
669 byte_array_class
= mono_array_class_get (mono_defaults
.byte_class
, 1);
671 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Messaging", "CallContext");
672 method_set_call_context
= mono_class_get_method_from_name (klass
, "SetCurrentCallContext", -1);
674 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Contexts", "Context");
675 method_needs_context_sink
= mono_class_get_method_from_name (klass
, "get_NeedsContextSink", -1);
677 module_initialized
= TRUE
;
682 mono_delegate_to_ftnptr (MonoDelegate
*delegate
)
684 MonoMethod
*method
, *wrapper
;
690 if (delegate
->delegate_trampoline
)
691 return delegate
->delegate_trampoline
;
693 klass
= ((MonoObject
*)delegate
)->vtable
->klass
;
694 g_assert (klass
->delegate
);
696 method
= delegate
->method_info
->method
;
698 wrapper
= mono_marshal_get_managed_wrapper (method
, klass
, delegate
->target
);
700 delegate
->delegate_trampoline
= mono_compile_method (wrapper
);
702 // Add the delegate to the delegate hash table
703 delegate_hash_table_add (delegate
);
705 /* when the object is collected, collect the dynamic method, too */
706 mono_object_register_finalizer ((MonoObject
*)delegate
);
708 return delegate
->delegate_trampoline
;
712 * this hash table maps from a delegate trampoline object to a weak reference
713 * of the delegate. As an optimizations with a non-moving GC we store the
714 * object pointer itself, otherwise we use a GC handle.
716 static GHashTable
*delegate_hash_table
;
719 delegate_hash_table_new (void) {
720 return g_hash_table_new (NULL
, NULL
);
724 delegate_hash_table_remove (MonoDelegate
*d
)
726 #ifdef HAVE_MOVING_COLLECTOR
729 mono_marshal_lock ();
730 if (delegate_hash_table
== NULL
)
731 delegate_hash_table
= delegate_hash_table_new ();
732 #ifdef HAVE_MOVING_COLLECTOR
733 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, d
->delegate_trampoline
));
735 g_hash_table_remove (delegate_hash_table
, d
->delegate_trampoline
);
736 mono_marshal_unlock ();
737 #ifdef HAVE_MOVING_COLLECTOR
738 mono_gchandle_free (gchandle
);
743 delegate_hash_table_add (MonoDelegate
*d
)
745 #ifdef HAVE_MOVING_COLLECTOR
746 guint32 gchandle
= mono_gchandle_new_weakref ((MonoObject
*)d
, FALSE
);
748 mono_marshal_lock ();
749 if (delegate_hash_table
== NULL
)
750 delegate_hash_table
= delegate_hash_table_new ();
751 #ifdef HAVE_MOVING_COLLECTOR
752 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, GUINT_TO_POINTER (gchandle
));
754 g_hash_table_insert (delegate_hash_table
, d
->delegate_trampoline
, d
);
756 mono_marshal_unlock ();
760 mono_ftnptr_to_delegate (MonoClass
*klass
, gpointer ftn
)
762 #ifdef HAVE_MOVING_COLLECTOR
767 mono_marshal_lock ();
768 if (delegate_hash_table
== NULL
)
769 delegate_hash_table
= delegate_hash_table_new ();
771 #ifdef HAVE_MOVING_COLLECTOR
772 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table
, ftn
));
773 mono_marshal_unlock ();
775 d
= (MonoDelegate
*)mono_gchandle_get_target (gchandle
);
779 d
= g_hash_table_lookup (delegate_hash_table
, ftn
);
780 mono_marshal_unlock ();
783 /* This is a native function, so construct a delegate for it */
784 static MonoClass
*UnmanagedFunctionPointerAttribute
;
785 MonoMethodSignature
*sig
;
787 MonoMarshalSpec
**mspecs
;
788 MonoCustomAttrInfo
*cinfo
;
789 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
790 MonoMethod
*invoke
= mono_get_delegate_invoke (klass
);
791 MonoMethodPInvoke piinfo
;
794 memset (&piinfo
, 0, sizeof (piinfo
));
795 if (!UnmanagedFunctionPointerAttribute
)
796 UnmanagedFunctionPointerAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
798 /* The attribute is only available in Net 2.0 */
799 if (UnmanagedFunctionPointerAttribute
) {
801 * The pinvoke attributes are stored in a real custom attribute so we have to
804 cinfo
= mono_custom_attrs_from_class (klass
);
806 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr (cinfo
, UnmanagedFunctionPointerAttribute
);
808 piinfo
.piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
811 mono_custom_attrs_free (cinfo
);
815 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
816 mono_method_get_marshal_info (invoke
, mspecs
);
817 /* Freed below so don't alloc from mempool */
818 sig
= mono_metadata_signature_dup (mono_method_signature (invoke
));
821 wrapper
= mono_marshal_get_native_func_wrapper (klass
->image
, sig
, &piinfo
, mspecs
, ftn
);
823 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
825 mono_metadata_free_marshal_spec (mspecs
[i
]);
829 d
= (MonoDelegate
*)mono_object_new (mono_domain_get (), klass
);
830 mono_delegate_ctor ((MonoObject
*)d
, NULL
, mono_compile_method (wrapper
));
833 if (d
->object
.vtable
->domain
!= mono_domain_get ())
834 mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
840 mono_delegate_free_ftnptr (MonoDelegate
*delegate
)
845 delegate_hash_table_remove (delegate
);
847 ptr
= (gpointer
)InterlockedExchangePointer (&delegate
->delegate_trampoline
, NULL
);
849 if (!delegate
->target
) {
850 /* The wrapper method is shared between delegates -> no need to free it */
855 ji
= mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr
));
858 mono_runtime_free_method (mono_object_domain (delegate
), ji
->method
);
863 mono_array_to_savearray (MonoArray
*array
)
868 g_assert_not_reached ();
873 mono_array_to_lparray (MonoArray
*array
)
878 /* fixme: maybe we need to make a copy */
879 return array
->vector
;
883 mono_byvalarray_to_array (MonoArray
*arr
, gpointer native_arr
, MonoClass
*elclass
, guint32 elnum
)
885 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
887 if (elclass
== mono_defaults
.byte_class
) {
888 GError
*error
= NULL
;
892 ut
= g_utf8_to_utf16 (native_arr
, elnum
, NULL
, &items_written
, &error
);
895 memcpy (mono_array_addr (arr
, guint16
, 0), ut
, items_written
* sizeof (guint16
));
899 g_error_free (error
);
902 g_assert_not_reached ();
906 mono_array_to_byvalarray (gpointer native_arr
, MonoArray
*arr
, MonoClass
*elclass
, guint32 elnum
)
908 g_assert (arr
->obj
.vtable
->klass
->element_class
== mono_defaults
.char_class
);
910 if (elclass
== mono_defaults
.byte_class
) {
912 GError
*error
= NULL
;
914 as
= g_utf16_to_utf8 (mono_array_addr (arr
, gunichar2
, 0), mono_array_length (arr
), NULL
, NULL
, &error
);
916 MonoException
*exc
= mono_get_exception_argument ("string", error
->message
);
917 g_error_free (error
);
918 mono_raise_exception (exc
);
921 memcpy (native_arr
, as
, MIN (strlen (as
), elnum
));
924 g_assert_not_reached ();
929 mono_string_utf8_to_builder (MonoStringBuilder
*sb
, char *text
)
931 GError
*error
= NULL
;
941 ut
= g_utf8_to_utf16 (text
, l
, NULL
, &items_written
, &error
);
943 if (items_written
> mono_stringbuilder_capacity (sb
))
944 items_written
= mono_stringbuilder_capacity (sb
);
947 if (! sb
->str
|| sb
->str
== sb
->cached_str
) {
948 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_size (mono_domain_get (), items_written
));
949 sb
->cached_str
= NULL
;
952 memcpy (mono_string_chars (sb
->str
), ut
, items_written
* 2);
953 sb
->length
= items_written
;
955 g_error_free (error
);
961 * FIXME: This routine does not seem to do what it seems to do
962 * the @text is never copied into the string builder
965 mono_string_utf16_to_builder (MonoStringBuilder
*sb
, gunichar2
*text
)
972 g_assert (mono_string_chars (sb
->str
) == text
);
974 for (len
= 0; text
[len
] != 0; ++len
)
981 * mono_string_builder_to_utf8:
982 * @sb: the string builder
984 * Converts to utf8 the contents of the MonoStringBuilder.
986 * Returns: a utf8 string with the contents of the StringBuilder.
988 * The return value must be released with g_free.
991 mono_string_builder_to_utf8 (MonoStringBuilder
*sb
)
993 GError
*error
= NULL
;
1000 if ((sb
->str
== sb
->cached_str
) && (sb
->str
->length
== 0)) {
1002 * The sb could have been allocated with the default capacity and be empty.
1003 * we need to alloc a buffer of the default capacity in this case.
1005 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_size (mono_domain_get (), 16));
1006 sb
->cached_str
= NULL
;
1009 res
= mono_marshal_alloc (mono_stringbuilder_capacity (sb
) + 1);
1011 tmp
= g_utf16_to_utf8 (mono_string_chars (sb
->str
), sb
->length
, NULL
, res
, &error
);
1013 g_error_free (error
);
1014 mono_marshal_free (res
);
1015 mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
1017 memcpy (res
, tmp
, sb
->length
+ 1);
1025 * mono_string_builder_to_utf16:
1026 * @sb: the string builder
1028 * Converts to utf16 the contents of the MonoStringBuilder.
1030 * Returns: a utf16 string with the contents of the StringBuilder.
1032 * The return value must not be freed.
1035 mono_string_builder_to_utf16 (MonoStringBuilder
*sb
)
1043 * The stringbuilder might not have ownership of this string. If this is
1044 * the case, we must duplicate the string, so that we don't munge immutable
1047 if (sb
->str
== sb
->cached_str
) {
1049 * The sb could have been allocated with the default capacity and be empty.
1050 * we need to alloc a buffer of the default capacity in this case.
1052 if (sb
->str
->length
== 0)
1053 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_size (mono_domain_get (), 16));
1055 MONO_OBJECT_SETREF (sb
, str
, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb
->str
), mono_stringbuilder_capacity (sb
)));
1056 sb
->cached_str
= NULL
;
1059 return mono_string_chars (sb
->str
);
1063 mono_string_to_lpstr (MonoString
*s
)
1065 #ifdef PLATFORM_WIN32
1068 GError
*error
= NULL
;
1074 as
= CoTaskMemAlloc (1);
1079 tmp
= g_utf16_to_utf8 (mono_string_chars (s
), s
->length
, NULL
, &len
, &error
);
1081 MonoException
*exc
= mono_get_exception_argument ("string", error
->message
);
1082 g_error_free (error
);
1083 mono_raise_exception(exc
);
1086 as
= CoTaskMemAlloc (len
+ 1);
1087 memcpy (as
, tmp
, len
+ 1);
1092 return mono_string_to_utf8 (s
);
1097 mono_string_to_ansibstr (MonoString
*string_obj
)
1099 g_error ("UnmanagedMarshal.BStr is not implemented.");
1104 mono_string_to_bstr (MonoString
*string_obj
)
1106 #ifdef PLATFORM_WIN32
1109 return SysAllocStringLen (mono_string_chars (string_obj
), mono_string_length (string_obj
));
1111 int slen
= mono_string_length (string_obj
);
1112 char *ret
= g_malloc (slen
* 2 + 4 + 2);
1115 memcpy (ret
+ 4, mono_string_chars (string_obj
), slen
* 2);
1116 * ((guint32
*) ret
) = slen
* 2;
1117 ret
[4 + slen
* 2] = 0;
1118 ret
[5 + slen
* 2] = 0;
1125 mono_string_from_bstr (gpointer bstr
)
1127 #ifdef PLATFORM_WIN32
1130 return mono_string_new_utf16 (mono_domain_get (), bstr
, SysStringLen (bstr
));
1132 return mono_string_new_utf16 (mono_domain_get (), bstr
, *(guint32
*)((char *)bstr
- 4));
1137 mono_free_bstr (gpointer bstr
)
1139 #ifdef PLATFORM_WIN32
1140 SysFreeString ((BSTR
)bstr
);
1142 g_free (((char *)bstr
) - 4);
1147 * mono_string_to_byvalstr:
1148 * @dst: Where to store the null-terminated utf8 decoded string.
1149 * @src: the MonoString to copy.
1150 * @size: the maximum number of bytes to copy.
1152 * Copies the MonoString pointed to by @src as a utf8 string
1153 * into @dst, it copies at most @size bytes into the destination.
1156 mono_string_to_byvalstr (gpointer dst
, MonoString
*src
, int size
)
1161 g_assert (dst
!= NULL
);
1162 g_assert (size
> 0);
1164 memset (dst
, 0, size
);
1168 s
= mono_string_to_utf8 (src
);
1169 len
= MIN (size
, strlen (s
));
1172 memcpy (dst
, s
, len
);
1177 * mono_string_to_byvalwstr:
1178 * @dst: Where to store the null-terminated utf16 decoded string.
1179 * @src: the MonoString to copy.
1180 * @size: the maximum number of bytes to copy.
1182 * Copies the MonoString pointed to by @src as a utf16 string into
1183 * @dst, it copies at most @size bytes into the destination (including
1184 * a terminating 16-bit zero terminator).
1187 mono_string_to_byvalwstr (gpointer dst
, MonoString
*src
, int size
)
1191 g_assert (dst
!= NULL
);
1192 g_assert (size
> 1);
1195 memset (dst
, 0, size
* 2);
1199 len
= MIN (size
, (mono_string_length (src
)));
1200 memcpy (dst
, mono_string_chars (src
), size
* 2);
1201 if (size
<= mono_string_length (src
))
1203 *((gunichar2
*) dst
+ len
) = 0;
1207 mono_mb_free (MonoMethodBuilder
*mb
)
1209 g_list_free (mb
->locals_list
);
1211 g_free (mb
->method
);
1219 mono_mb_new (MonoClass
*klass
, const char *name
, MonoWrapperType type
)
1221 MonoMethodBuilder
*mb
;
1224 g_assert (klass
!= NULL
);
1225 g_assert (name
!= NULL
);
1227 mb
= g_new0 (MonoMethodBuilder
, 1);
1229 mb
->method
= m
= (MonoMethod
*)g_new0 (MonoMethodWrapper
, 1);
1233 m
->wrapper_type
= type
;
1235 mb
->name
= g_strdup (name
);
1237 mb
->code
= g_malloc (mb
->code_size
);
1243 mono_mb_add_local (MonoMethodBuilder
*mb
, MonoType
*type
)
1247 g_assert (mb
!= NULL
);
1248 g_assert (type
!= NULL
);
1251 mb
->locals_list
= g_list_append (mb
->locals_list
, type
);
1258 * mono_mb_create_method:
1260 * Create a MonoMethod from this method builder.
1261 * Returns: the newly created method.
1263 * LOCKING: Takes the loader lock.
1266 mono_mb_create_method (MonoMethodBuilder
*mb
, MonoMethodSignature
*signature
, int max_stack
)
1268 MonoMethodHeader
*header
;
1269 MonoMethodWrapper
*mw
;
1275 g_assert (mb
!= NULL
);
1277 mp
= mb
->method
->klass
->image
->mempool
;
1279 mono_loader_lock ();
1281 method
= mb
->method
;
1283 method
->name
= mb
->name
;
1284 method
->dynamic
= TRUE
;
1286 ((MonoMethodNormal
*)method
)->header
= header
= (MonoMethodHeader
*)
1287 g_malloc0 (sizeof (MonoMethodHeader
) + mb
->locals
* sizeof (MonoType
*));
1289 header
->code
= mb
->code
;
1291 for (i
= 0, l
= mb
->locals_list
; l
; l
= l
->next
, i
++) {
1292 header
->locals
[i
] = mono_metadata_type_dup (NULL
, (MonoType
*)l
->data
);
1295 /* Realloc the method info into a mempool */
1297 method
= mono_mempool_alloc (mp
, sizeof (MonoMethodWrapper
));
1298 memcpy (method
, mb
->method
, sizeof (MonoMethodWrapper
));
1300 method
->name
= mono_mempool_strdup (mp
, mb
->name
);
1302 ((MonoMethodNormal
*)method
)->header
= header
= (MonoMethodHeader
*)
1303 mono_mempool_alloc0 (mp
, sizeof (MonoMethodHeader
) + mb
->locals
* sizeof (MonoType
*));
1305 header
->code
= mono_mempool_alloc (mp
, mb
->pos
);
1306 memcpy ((char*)header
->code
, mb
->code
, mb
->pos
);
1308 for (i
= 0, l
= mb
->locals_list
; l
; l
= l
->next
, i
++) {
1309 header
->locals
[i
] = (MonoType
*)l
->data
;
1316 header
->max_stack
= max_stack
;
1318 method
->signature
= signature
;
1320 header
->code_size
= mb
->pos
;
1321 header
->num_locals
= mb
->locals
;
1322 header
->init_locals
= TRUE
;
1324 mw
= (MonoMethodWrapper
*) mb
->method
;
1325 i
= g_list_length (mw
->method_data
);
1329 l
= g_list_reverse (mw
->method_data
);
1330 if (method
->dynamic
)
1331 data
= g_malloc (sizeof (gpointer
) * (i
+ 1));
1333 data
= mono_mempool_alloc (mp
, sizeof (gpointer
) * (i
+ 1));
1334 /* store the size in the first element */
1335 data
[0] = GUINT_TO_POINTER (i
);
1337 for (tmp
= l
; tmp
; tmp
= tmp
->next
) {
1338 data
[i
++] = tmp
->data
;
1342 ((MonoMethodWrapper
*)method
)->method_data
= data
;
1345 static int total_code = 0;
1346 static int total_alloc = 0;
1347 total_code += mb->pos;
1348 total_alloc += mb->code_size;
1349 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
1352 #ifdef DEBUG_RUNTIME_CODE
1353 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method
, TRUE
));
1354 printf ("%s\n", mono_disasm_code (&marshal_dh
, method
, mb
->code
, mb
->code
+ mb
->pos
));
1357 mono_loader_unlock ();
1362 mono_mb_add_data (MonoMethodBuilder
*mb
, gpointer data
)
1364 MonoMethodWrapper
*mw
;
1366 g_assert (mb
!= NULL
);
1368 mw
= (MonoMethodWrapper
*)mb
->method
;
1370 /* one O(n) is enough */
1371 mw
->method_data
= g_list_prepend (mw
->method_data
, data
);
1373 return g_list_length (mw
->method_data
);
1377 mono_mb_patch_addr (MonoMethodBuilder
*mb
, int pos
, int value
)
1379 mb
->code
[pos
] = value
& 0xff;
1380 mb
->code
[pos
+ 1] = (value
>> 8) & 0xff;
1381 mb
->code
[pos
+ 2] = (value
>> 16) & 0xff;
1382 mb
->code
[pos
+ 3] = (value
>> 24) & 0xff;
1386 mono_mb_patch_addr_s (MonoMethodBuilder
*mb
, int pos
, gint8 value
)
1388 *((gint8
*)(&mb
->code
[pos
])) = value
;
1392 mono_mb_emit_byte (MonoMethodBuilder
*mb
, guint8 op
)
1394 if (mb
->pos
>= mb
->code_size
) {
1395 mb
->code_size
+= mb
->code_size
>> 1;
1396 mb
->code
= g_realloc (mb
->code
, mb
->code_size
);
1399 mb
->code
[mb
->pos
++] = op
;
1403 mono_mb_emit_ldflda (MonoMethodBuilder
*mb
, gint32 offset
)
1405 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1406 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
1409 mono_mb_emit_icon (mb
, offset
);
1410 mono_mb_emit_byte (mb
, CEE_ADD
);
1415 mono_mb_emit_proxy_check (MonoMethodBuilder
*mb
, int branch_code
)
1418 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
1419 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1420 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
1421 mono_mb_emit_byte (mb
, CEE_ADD
);
1422 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1423 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1424 mono_mb_emit_byte (mb
, CEE_MONO_CLASSCONST
);
1425 mono_mb_emit_i4 (mb
, mono_mb_add_data (mb
, mono_defaults
.transparent_proxy_class
));
1426 mono_mb_emit_byte (mb
, branch_code
);
1428 mono_mb_emit_i4 (mb
, 0);
1433 mono_mb_emit_xdomain_check (MonoMethodBuilder
*mb
, int branch_code
)
1436 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1437 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1438 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRealProxy
, target_domain_id
));
1439 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
1440 mono_mb_emit_icon (mb
, -1);
1441 mono_mb_emit_byte (mb
, branch_code
);
1443 mono_mb_emit_i4 (mb
, 0);
1448 mono_mb_emit_i4 (MonoMethodBuilder
*mb
, gint32 data
)
1450 if ((mb
->pos
+ 4) >= mb
->code_size
) {
1451 mb
->code_size
+= mb
->code_size
>> 1;
1452 mb
->code
= g_realloc (mb
->code
, mb
->code_size
);
1455 mono_mb_patch_addr (mb
, mb
->pos
, data
);
1460 mono_mb_emit_i2 (MonoMethodBuilder
*mb
, gint16 data
)
1462 if ((mb
->pos
+ 2) >= mb
->code_size
) {
1463 mb
->code_size
+= mb
->code_size
>> 1;
1464 mb
->code
= g_realloc (mb
->code
, mb
->code_size
);
1467 mb
->code
[mb
->pos
] = data
& 0xff;
1468 mb
->code
[mb
->pos
+ 1] = (data
>> 8) & 0xff;
1473 mono_mb_emit_op (MonoMethodBuilder
*mb
, guint8 op
, gpointer data
)
1475 mono_mb_emit_byte (mb
, op
);
1476 mono_mb_emit_i4 (mb
, mono_mb_add_data (mb
, data
));
1480 mono_mb_emit_ldstr (MonoMethodBuilder
*mb
, char *str
)
1482 mono_mb_emit_op (mb
, CEE_LDSTR
, str
);
1486 mono_mb_emit_ldarg (MonoMethodBuilder
*mb
, guint argnum
)
1489 mono_mb_emit_byte (mb
, CEE_LDARG_0
+ argnum
);
1490 } else if (argnum
< 256) {
1491 mono_mb_emit_byte (mb
, CEE_LDARG_S
);
1492 mono_mb_emit_byte (mb
, argnum
);
1494 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1495 mono_mb_emit_byte (mb
, CEE_LDARG
);
1496 mono_mb_emit_i2 (mb
, argnum
);
1501 mono_mb_emit_ldarg_addr (MonoMethodBuilder
*mb
, guint argnum
)
1504 mono_mb_emit_byte (mb
, CEE_LDARGA_S
);
1505 mono_mb_emit_byte (mb
, argnum
);
1507 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1508 mono_mb_emit_byte (mb
, CEE_LDARGA
);
1509 mono_mb_emit_i2 (mb
, argnum
);
1514 mono_mb_emit_ldloc_addr (MonoMethodBuilder
*mb
, guint locnum
)
1517 mono_mb_emit_byte (mb
, CEE_LDLOCA_S
);
1518 mono_mb_emit_byte (mb
, locnum
);
1520 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1521 mono_mb_emit_byte (mb
, CEE_LDLOCA
);
1522 mono_mb_emit_i2 (mb
, locnum
);
1527 mono_mb_emit_ldloc (MonoMethodBuilder
*mb
, guint num
)
1530 mono_mb_emit_byte (mb
, CEE_LDLOC_0
+ num
);
1531 } else if (num
< 256) {
1532 mono_mb_emit_byte (mb
, CEE_LDLOC_S
);
1533 mono_mb_emit_byte (mb
, num
);
1535 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1536 mono_mb_emit_byte (mb
, CEE_LDLOC
);
1537 mono_mb_emit_i2 (mb
, num
);
1542 mono_mb_emit_stloc (MonoMethodBuilder
*mb
, guint num
)
1545 mono_mb_emit_byte (mb
, CEE_STLOC_0
+ num
);
1546 } else if (num
< 256) {
1547 mono_mb_emit_byte (mb
, CEE_STLOC_S
);
1548 mono_mb_emit_byte (mb
, num
);
1550 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1551 mono_mb_emit_byte (mb
, CEE_STLOC
);
1552 mono_mb_emit_i2 (mb
, num
);
1557 mono_mb_emit_icon (MonoMethodBuilder
*mb
, gint32 value
)
1559 if (value
>= -1 && value
< 8) {
1560 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
+ value
);
1561 } else if (value
>= -128 && value
<= 127) {
1562 mono_mb_emit_byte (mb
, CEE_LDC_I4_S
);
1563 mono_mb_emit_byte (mb
, value
);
1565 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
1566 mono_mb_emit_i4 (mb
, value
);
1571 mono_mb_emit_branch (MonoMethodBuilder
*mb
, guint8 op
)
1574 mono_mb_emit_byte (mb
, op
);
1576 mono_mb_emit_i4 (mb
, 0);
1581 mono_mb_emit_short_branch (MonoMethodBuilder
*mb
, guint8 op
)
1584 mono_mb_emit_byte (mb
, op
);
1586 mono_mb_emit_byte (mb
, 0);
1592 mono_mb_patch_branch (MonoMethodBuilder
*mb
, guint32 pos
)
1594 mono_mb_patch_addr (mb
, pos
, mb
->pos
- (pos
+ 4));
1598 mono_mb_patch_short_branch (MonoMethodBuilder
*mb
, guint32 pos
)
1600 mono_mb_patch_addr_s (mb
, pos
, mb
->pos
- (pos
+ 1));
1604 mono_mb_emit_ptr (MonoMethodBuilder
*mb
, gpointer ptr
)
1606 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1607 mono_mb_emit_op (mb
, CEE_MONO_LDPTR
, ptr
);
1611 mono_mb_emit_calli (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
1613 mono_mb_emit_op (mb
, CEE_CALLI
, sig
);
1617 mono_mb_emit_managed_call (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*opt_sig
)
1619 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1623 mono_mb_emit_native_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gpointer func
)
1625 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1626 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LMF
);
1627 mono_mb_emit_ptr (mb
, func
);
1628 mono_mb_emit_calli (mb
, sig
);
1629 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1630 mono_mb_emit_byte (mb
, CEE_MONO_RESTORE_LMF
);
1634 mono_mb_emit_icall (MonoMethodBuilder
*mb
, gpointer func
)
1636 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1637 mono_mb_emit_op (mb
, CEE_MONO_ICALL
, func
);
1641 mono_mb_emit_cominterop_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethod
* method
)
1643 // get function pointer from 1st arg, the COM interface pointer
1644 mono_mb_emit_ldarg (mb
, 0);
1645 mono_mb_emit_icon (mb
, cominterop_get_com_slot_for_method (method
));
1646 mono_mb_emit_icall (mb
, cominterop_get_function_pointer
);
1648 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1649 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LMF
);
1650 mono_mb_emit_calli (mb
, sig
);
1651 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1652 mono_mb_emit_byte (mb
, CEE_MONO_RESTORE_LMF
);
1656 mono_mb_emit_exception_full (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
1658 MonoMethod
*ctor
= NULL
;
1660 MonoClass
*mme
= mono_class_from_name (mono_defaults
.corlib
, exc_nspace
, exc_name
);
1661 mono_class_init (mme
);
1662 ctor
= mono_class_get_method_from_name (mme
, ".ctor", 0);
1664 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
1666 mono_mb_emit_byte (mb
, CEE_DUP
);
1667 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoException
, message
));
1668 mono_mb_emit_ldstr (mb
, (char*)msg
);
1669 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1671 mono_mb_emit_byte (mb
, CEE_THROW
);
1675 mono_mb_emit_exception (MonoMethodBuilder
*mb
, const char *exc_name
, const char *msg
)
1677 mono_mb_emit_exception_full (mb
, "System", exc_name
, msg
);
1681 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, const char *msg
)
1683 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", msg
);
1687 mono_mb_emit_add_to_local (MonoMethodBuilder
*mb
, guint16 local
, gint32 incr
)
1689 mono_mb_emit_ldloc (mb
, local
);
1690 mono_mb_emit_icon (mb
, incr
);
1691 mono_mb_emit_byte (mb
, CEE_ADD
);
1692 mono_mb_emit_stloc (mb
, local
);
1696 mono_type_to_ldind (MonoType
*type
)
1702 switch (type
->type
) {
1704 return CEE_LDIND_I1
;
1706 case MONO_TYPE_BOOLEAN
:
1707 return CEE_LDIND_U1
;
1709 return CEE_LDIND_I2
;
1711 case MONO_TYPE_CHAR
:
1712 return CEE_LDIND_U2
;
1714 return CEE_LDIND_I4
;
1716 return CEE_LDIND_U4
;
1720 case MONO_TYPE_FNPTR
:
1722 case MONO_TYPE_CLASS
:
1723 case MONO_TYPE_STRING
:
1724 case MONO_TYPE_OBJECT
:
1725 case MONO_TYPE_SZARRAY
:
1726 case MONO_TYPE_ARRAY
:
1727 return CEE_LDIND_REF
;
1730 return CEE_LDIND_I8
;
1732 return CEE_LDIND_R4
;
1734 return CEE_LDIND_R8
;
1735 case MONO_TYPE_VALUETYPE
:
1736 if (type
->data
.klass
->enumtype
) {
1737 type
= type
->data
.klass
->enum_basetype
;
1741 case MONO_TYPE_TYPEDBYREF
:
1743 case MONO_TYPE_GENERICINST
:
1744 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1747 g_error ("unknown type 0x%02x in type_to_ldind", type
->type
);
1753 mono_type_to_stind (MonoType
*type
)
1759 switch (type
->type
) {
1762 case MONO_TYPE_BOOLEAN
:
1763 return CEE_STIND_I1
;
1766 case MONO_TYPE_CHAR
:
1767 return CEE_STIND_I2
;
1770 return CEE_STIND_I4
;
1774 case MONO_TYPE_FNPTR
:
1776 case MONO_TYPE_CLASS
:
1777 case MONO_TYPE_STRING
:
1778 case MONO_TYPE_OBJECT
:
1779 case MONO_TYPE_SZARRAY
:
1780 case MONO_TYPE_ARRAY
:
1781 return CEE_STIND_REF
;
1784 return CEE_STIND_I8
;
1786 return CEE_STIND_R4
;
1788 return CEE_STIND_R8
;
1789 case MONO_TYPE_VALUETYPE
:
1790 if (type
->data
.klass
->enumtype
) {
1791 type
= type
->data
.klass
->enum_basetype
;
1795 case MONO_TYPE_TYPEDBYREF
:
1797 case MONO_TYPE_GENERICINST
:
1798 type
= &type
->data
.generic_class
->container_class
->byval_arg
;
1801 g_error ("unknown type 0x%02x in type_to_stind", type
->type
);
1807 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
1810 case MONO_MARSHAL_CONV_BOOL_I4
:
1811 mono_mb_emit_ldloc (mb
, 1);
1812 mono_mb_emit_ldloc (mb
, 0);
1813 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
1814 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1815 mono_mb_emit_byte (mb
, 3);
1816 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1817 mono_mb_emit_byte (mb
, CEE_BR_S
);
1818 mono_mb_emit_byte (mb
, 1);
1819 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1820 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1822 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
1823 mono_mb_emit_ldloc (mb
, 1);
1824 mono_mb_emit_ldloc (mb
, 0);
1825 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
1826 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1827 mono_mb_emit_byte (mb
, 3);
1828 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1829 mono_mb_emit_byte (mb
, CEE_BR_S
);
1830 mono_mb_emit_byte (mb
, 1);
1831 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1832 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1834 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
1835 MonoClass
*eklass
= NULL
;
1838 if (type
->type
== MONO_TYPE_SZARRAY
) {
1839 eklass
= type
->data
.klass
;
1841 g_assert_not_reached ();
1844 esize
= mono_class_native_size (eklass
, NULL
);
1846 /* create a new array */
1847 mono_mb_emit_ldloc (mb
, 1);
1848 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1849 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
1850 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1852 if (eklass
->blittable
) {
1853 /* copy the elements */
1854 mono_mb_emit_ldloc (mb
, 1);
1855 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1856 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
1857 mono_mb_emit_byte (mb
, CEE_ADD
);
1858 mono_mb_emit_ldloc (mb
, 0);
1859 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
1860 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1861 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1864 int array_var
, src_var
, dst_var
, index_var
;
1865 guint32 label2
, label3
;
1867 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1868 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1869 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1872 mono_mb_emit_ldloc (mb
, 1);
1873 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1874 mono_mb_emit_stloc (mb
, array_var
);
1876 /* save the old src pointer */
1877 mono_mb_emit_ldloc (mb
, 0);
1878 mono_mb_emit_stloc (mb
, src_var
);
1879 /* save the old dst pointer */
1880 mono_mb_emit_ldloc (mb
, 1);
1881 mono_mb_emit_stloc (mb
, dst_var
);
1883 /* Emit marshalling loop */
1884 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1885 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1886 mono_mb_emit_stloc (mb
, index_var
);
1890 mono_mb_emit_ldloc (mb
, index_var
);
1891 mono_mb_emit_ldloc (mb
, array_var
);
1892 mono_mb_emit_byte (mb
, CEE_LDLEN
);
1893 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
1895 /* src is already set */
1898 mono_mb_emit_ldloc (mb
, array_var
);
1899 mono_mb_emit_ldloc (mb
, index_var
);
1900 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
1901 mono_mb_emit_stloc (mb
, 1);
1903 /* Do the conversion */
1904 emit_struct_conv (mb
, eklass
, TRUE
);
1907 mono_mb_emit_add_to_local (mb
, index_var
, 1);
1909 mono_mb_emit_byte (mb
, CEE_BR
);
1910 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
1912 mono_mb_patch_branch (mb
, label3
);
1914 /* restore the old src pointer */
1915 mono_mb_emit_ldloc (mb
, src_var
);
1916 mono_mb_emit_stloc (mb
, 0);
1917 /* restore the old dst pointer */
1918 mono_mb_emit_ldloc (mb
, dst_var
);
1919 mono_mb_emit_stloc (mb
, 1);
1923 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
1924 MonoClass
*eclass
= mono_defaults
.char_class
;
1926 /* create a new array */
1927 mono_mb_emit_ldloc (mb
, 1);
1928 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1929 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
1930 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1932 mono_mb_emit_ldloc (mb
, 1);
1933 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1934 mono_mb_emit_ldloc (mb
, 0);
1935 mono_mb_emit_ptr (mb
, mono_defaults
.byte_class
);
1936 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
1937 mono_mb_emit_icall (mb
, mono_byvalarray_to_array
);
1940 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
1941 mono_mb_emit_ldloc (mb
, 1);
1942 mono_mb_emit_ldloc (mb
, 0);
1943 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1944 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1946 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
1947 mono_mb_emit_ldloc (mb
, 1);
1948 mono_mb_emit_ldloc (mb
, 0);
1949 mono_mb_emit_icall (mb
, mono_string_from_utf16
);
1950 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1952 case MONO_MARSHAL_CONV_STR_LPTSTR
:
1953 mono_mb_emit_ldloc (mb
, 1);
1954 mono_mb_emit_ldloc (mb
, 0);
1955 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1956 #ifdef PLATFORM_WIN32
1957 mono_mb_emit_icall (mb
, mono_string_from_utf16
);
1959 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1961 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1963 case MONO_MARSHAL_CONV_STR_LPSTR
:
1964 mono_mb_emit_ldloc (mb
, 1);
1965 mono_mb_emit_ldloc (mb
, 0);
1966 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1967 mono_mb_emit_icall (mb
, mono_string_new_wrapper
);
1968 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1970 case MONO_MARSHAL_CONV_STR_LPWSTR
:
1971 mono_mb_emit_ldloc (mb
, 1);
1972 mono_mb_emit_ldloc (mb
, 0);
1973 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1974 mono_mb_emit_icall (mb
, mono_string_from_utf16
);
1975 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1977 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
1978 MonoClass
*klass
= mono_class_from_mono_type (type
);
1979 int src_var
, dst_var
;
1981 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1982 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1984 /* *dst = new object */
1985 mono_mb_emit_ldloc (mb
, 1);
1986 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1987 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
1988 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1990 /* save the old src pointer */
1991 mono_mb_emit_ldloc (mb
, 0);
1992 mono_mb_emit_stloc (mb
, src_var
);
1993 /* save the old dst pointer */
1994 mono_mb_emit_ldloc (mb
, 1);
1995 mono_mb_emit_stloc (mb
, dst_var
);
1997 /* dst = pointer to newly created object data */
1998 mono_mb_emit_ldloc (mb
, 1);
1999 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2000 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
2001 mono_mb_emit_byte (mb
, CEE_ADD
);
2002 mono_mb_emit_stloc (mb
, 1);
2004 emit_struct_conv (mb
, klass
, TRUE
);
2006 /* restore the old src pointer */
2007 mono_mb_emit_ldloc (mb
, src_var
);
2008 mono_mb_emit_stloc (mb
, 0);
2009 /* restore the old dst pointer */
2010 mono_mb_emit_ldloc (mb
, dst_var
);
2011 mono_mb_emit_stloc (mb
, 1);
2014 case MONO_MARSHAL_CONV_DEL_FTN
: {
2015 MonoClass
*klass
= mono_class_from_mono_type (type
);
2017 mono_mb_emit_ldloc (mb
, 1);
2018 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2019 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
2020 mono_mb_emit_ldloc (mb
, 0);
2021 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2022 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
2023 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2026 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
2027 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type
)->name
);
2029 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
2030 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
2031 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
: {
2032 static MonoClass
* com_interop_proxy_class
= NULL
;
2033 static MonoMethod
* com_interop_proxy_get_proxy
= NULL
;
2034 static MonoMethod
* get_transparent_proxy
= NULL
;
2036 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
2037 MonoClass
*klass
= NULL
;
2039 /* COM types are initialized lazily */
2040 mono_init_com_types ();
2042 klass
= mono_class_from_mono_type (type
);
2044 mono_mb_emit_ldloc (mb
, 1);
2045 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2046 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2048 mono_mb_emit_ldloc (mb
, 0);
2049 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2050 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
2052 /* load dst to store later */
2053 mono_mb_emit_ldloc (mb
, 1);
2055 mono_mb_emit_ldloc (mb
, 0);
2056 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2057 mono_mb_emit_icon (mb
, TRUE
);
2058 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
2059 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
2061 if (!com_interop_proxy_class
)
2062 com_interop_proxy_class
= mono_class_from_name (mono_defaults
.corlib
, "Mono.Interop", "ComInteropProxy");
2063 if (!com_interop_proxy_get_proxy
)
2064 com_interop_proxy_get_proxy
= mono_class_get_method_from_name_flags (com_interop_proxy_class
, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE
);
2065 if (!get_transparent_proxy
)
2066 get_transparent_proxy
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0);
2068 real_proxy
= mono_mb_add_local (mb
, &com_interop_proxy_class
->byval_arg
);
2070 mono_mb_emit_ldloc (mb
, 0);
2071 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2072 mono_mb_emit_ptr (mb
, &mono_defaults
.com_object_class
->byval_arg
);
2073 mono_mb_emit_icall (mb
, type_from_handle
);
2074 mono_mb_emit_managed_call (mb
, com_interop_proxy_get_proxy
, NULL
);
2075 mono_mb_emit_managed_call (mb
, get_transparent_proxy
, NULL
);
2076 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
2078 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
2080 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2081 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
2083 /* is already managed object */
2084 mono_mb_patch_short_branch (mb
, pos_ccw
);
2085 mono_mb_emit_ldloc (mb
, 0);
2086 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2087 mono_mb_emit_icon (mb
, TRUE
);
2088 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
2090 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
2092 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
2094 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2096 mono_mb_patch_short_branch (mb
, pos_end
);
2098 mono_mb_patch_short_branch (mb
, pos_null
);
2102 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
2104 * Passing SafeHandles as ref does not allow the unmanaged code
2105 * to change the SafeHandle value. If the value is changed,
2106 * we should issue a diagnostic exception (NotSupportedException)
2107 * that informs the user that changes to handles in unmanaged code
2110 * Since we currently have no access to the original
2111 * SafeHandle that was used during the marshalling,
2112 * for now we just ignore this, and ignore/discard any
2113 * changes that might have happened to the handle.
2118 case MONO_MARSHAL_CONV_HANDLEREF
: {
2120 * Passing HandleRefs in a struct that is ref()ed does not
2121 * copy the values back to the HandleRef
2126 case MONO_MARSHAL_CONV_STR_BSTR
:
2127 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
2128 case MONO_MARSHAL_CONV_STR_TBSTR
:
2129 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
2131 g_warning ("marshaling conversion %d not implemented", conv
);
2132 g_assert_not_reached ();
2137 conv_to_icall (MonoMarshalConv conv
)
2140 case MONO_MARSHAL_CONV_STR_LPWSTR
:
2141 return mono_marshal_string_to_utf16
;
2142 case MONO_MARSHAL_CONV_LPWSTR_STR
:
2143 return mono_string_from_utf16
;
2144 case MONO_MARSHAL_CONV_LPSTR_STR
:
2145 return mono_string_new_wrapper
;
2146 case MONO_MARSHAL_CONV_STR_LPTSTR
:
2147 #ifdef PLATFORM_WIN32
2148 return mono_marshal_string_to_utf16
;
2150 return mono_string_to_lpstr
;
2152 case MONO_MARSHAL_CONV_STR_LPSTR
:
2153 return mono_string_to_lpstr
;
2154 case MONO_MARSHAL_CONV_STR_BSTR
:
2155 return mono_string_to_bstr
;
2156 case MONO_MARSHAL_CONV_BSTR_STR
:
2157 return mono_string_from_bstr
;
2158 case MONO_MARSHAL_CONV_STR_TBSTR
:
2159 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
2160 return mono_string_to_ansibstr
;
2161 case MONO_MARSHAL_CONV_SB_LPSTR
:
2162 return mono_string_builder_to_utf8
;
2163 case MONO_MARSHAL_CONV_SB_LPTSTR
:
2164 #ifdef PLATFORM_WIN32
2165 return mono_string_builder_to_utf16
;
2167 return mono_string_builder_to_utf8
;
2169 case MONO_MARSHAL_CONV_SB_LPWSTR
:
2170 return mono_string_builder_to_utf16
;
2171 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
2172 return mono_array_to_savearray
;
2173 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
2174 return mono_array_to_lparray
;
2175 case MONO_MARSHAL_CONV_DEL_FTN
:
2176 return mono_delegate_to_ftnptr
;
2177 case MONO_MARSHAL_CONV_FTN_DEL
:
2178 return mono_ftnptr_to_delegate
;
2179 case MONO_MARSHAL_CONV_LPSTR_SB
:
2180 return mono_string_utf8_to_builder
;
2181 case MONO_MARSHAL_CONV_LPTSTR_SB
:
2182 #ifdef PLATFORM_WIN32
2183 return mono_string_utf16_to_builder
;
2185 return mono_string_utf8_to_builder
;
2187 case MONO_MARSHAL_CONV_LPWSTR_SB
:
2188 return mono_string_utf16_to_builder
;
2189 case MONO_MARSHAL_FREE_ARRAY
:
2190 return mono_marshal_free_array
;
2191 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
2192 return mono_string_to_byvalstr
;
2193 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
2194 return mono_string_to_byvalwstr
;
2196 g_assert_not_reached ();
2203 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
2208 case MONO_MARSHAL_CONV_BOOL_I4
:
2209 mono_mb_emit_ldloc (mb
, 1);
2210 mono_mb_emit_ldloc (mb
, 0);
2211 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
2212 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
2214 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
2215 mono_mb_emit_ldloc (mb
, 1);
2216 mono_mb_emit_ldloc (mb
, 0);
2217 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
2218 mono_mb_emit_byte (mb
, CEE_NEG
);
2219 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
2221 case MONO_MARSHAL_CONV_STR_LPWSTR
:
2222 case MONO_MARSHAL_CONV_STR_LPSTR
:
2223 case MONO_MARSHAL_CONV_STR_LPTSTR
:
2224 case MONO_MARSHAL_CONV_STR_BSTR
:
2225 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
2226 case MONO_MARSHAL_CONV_STR_TBSTR
: {
2229 /* free space if free == true */
2230 mono_mb_emit_ldloc (mb
, 2);
2231 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
2232 mono_mb_emit_ldloc (mb
, 1);
2233 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2234 mono_mb_emit_icall (mb
, g_free
);
2235 mono_mb_patch_short_branch (mb
, pos
);
2237 mono_mb_emit_ldloc (mb
, 1);
2238 mono_mb_emit_ldloc (mb
, 0);
2239 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2240 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
2241 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2244 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
2245 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
2246 case MONO_MARSHAL_CONV_DEL_FTN
:
2247 mono_mb_emit_ldloc (mb
, 1);
2248 mono_mb_emit_ldloc (mb
, 0);
2249 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2250 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
2251 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2253 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
2254 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
2257 mono_mb_emit_ldloc (mb
, 1); /* dst */
2258 mono_mb_emit_ldloc (mb
, 0);
2259 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
2260 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
2261 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
2264 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
2265 MonoClass
*eklass
= NULL
;
2268 if (type
->type
== MONO_TYPE_SZARRAY
) {
2269 eklass
= type
->data
.klass
;
2271 g_assert_not_reached ();
2274 if (eklass
->valuetype
)
2275 esize
= mono_class_native_size (eklass
, NULL
);
2277 esize
= sizeof (gpointer
);
2279 mono_mb_emit_ldloc (mb
, 0);
2280 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2281 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2283 if (eklass
->blittable
) {
2284 mono_mb_emit_ldloc (mb
, 1);
2285 mono_mb_emit_ldloc (mb
, 0);
2286 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2287 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
2288 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
2289 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2290 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2292 int array_var
, src_var
, dst_var
, index_var
;
2293 guint32 label2
, label3
;
2295 array_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
2296 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2297 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2300 mono_mb_emit_ldloc (mb
, 0);
2301 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2302 mono_mb_emit_stloc (mb
, array_var
);
2304 /* save the old src pointer */
2305 mono_mb_emit_ldloc (mb
, 0);
2306 mono_mb_emit_stloc (mb
, src_var
);
2307 /* save the old dst pointer */
2308 mono_mb_emit_ldloc (mb
, 1);
2309 mono_mb_emit_stloc (mb
, dst_var
);
2311 /* Emit marshalling loop */
2312 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2313 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2314 mono_mb_emit_stloc (mb
, index_var
);
2318 mono_mb_emit_ldloc (mb
, index_var
);
2319 mono_mb_emit_ldloc (mb
, array_var
);
2320 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2321 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2324 mono_mb_emit_ldloc (mb
, array_var
);
2325 mono_mb_emit_ldloc (mb
, index_var
);
2326 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2327 mono_mb_emit_stloc (mb
, 0);
2329 /* dst is already set */
2331 /* Do the conversion */
2332 emit_struct_conv (mb
, eklass
, FALSE
);
2335 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2337 mono_mb_emit_byte (mb
, CEE_BR
);
2338 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
2340 mono_mb_patch_branch (mb
, label3
);
2342 /* restore the old src pointer */
2343 mono_mb_emit_ldloc (mb
, src_var
);
2344 mono_mb_emit_stloc (mb
, 0);
2345 /* restore the old dst pointer */
2346 mono_mb_emit_ldloc (mb
, dst_var
);
2347 mono_mb_emit_stloc (mb
, 1);
2350 mono_mb_patch_branch (mb
, pos
);
2353 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
2354 mono_mb_emit_ldloc (mb
, 0);
2355 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2356 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
2358 mono_mb_emit_ldloc (mb
, 1);
2359 mono_mb_emit_ldloc (mb
, 0);
2360 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2361 mono_mb_emit_ptr (mb
, mono_defaults
.byte_class
);
2362 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
2363 mono_mb_emit_icall (mb
, mono_array_to_byvalarray
);
2364 mono_mb_patch_short_branch (mb
, pos
);
2367 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
2368 int src_var
, dst_var
;
2370 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2371 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2373 mono_mb_emit_ldloc (mb
, 0);
2374 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2375 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2377 /* save the old src pointer */
2378 mono_mb_emit_ldloc (mb
, 0);
2379 mono_mb_emit_stloc (mb
, src_var
);
2380 /* save the old dst pointer */
2381 mono_mb_emit_ldloc (mb
, 1);
2382 mono_mb_emit_stloc (mb
, dst_var
);
2384 /* src = pointer to object data */
2385 mono_mb_emit_ldloc (mb
, 0);
2386 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2387 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
2388 mono_mb_emit_byte (mb
, CEE_ADD
);
2389 mono_mb_emit_stloc (mb
, 0);
2391 emit_struct_conv (mb
, mono_class_from_mono_type (type
), FALSE
);
2393 /* restore the old src pointer */
2394 mono_mb_emit_ldloc (mb
, src_var
);
2395 mono_mb_emit_stloc (mb
, 0);
2396 /* restore the old dst pointer */
2397 mono_mb_emit_ldloc (mb
, dst_var
);
2398 mono_mb_emit_stloc (mb
, 1);
2400 mono_mb_patch_branch (mb
, pos
);
2403 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
2404 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
2405 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
: {
2406 guint32 pos_null
= 0, pos_rcw
= 0, pos_end
= 0;
2408 /* COM types are initialized lazily */
2409 mono_init_com_types ();
2412 mono_mb_emit_ldloc (mb
, 1);
2413 mono_mb_emit_icon (mb
, 0);
2414 mono_mb_emit_byte (mb
, CEE_CONV_U
);
2415 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2417 mono_mb_emit_ldloc (mb
, 0);
2418 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2420 // if null just break, dst was already inited to 0
2421 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
2423 mono_mb_emit_ldloc (mb
, 0);
2424 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2425 mono_mb_emit_icall (mb
, cominterop_object_is_rcw
);
2426 pos_rcw
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
2428 // load dst to store later
2429 mono_mb_emit_ldloc (mb
, 1);
2432 mono_mb_emit_ldloc (mb
, 0);
2433 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2434 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
2435 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2437 /* load the RCW from the ComInteropProxy*/
2438 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
2439 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2441 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
2442 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
2443 mono_mb_emit_icon (mb
, TRUE
);
2444 mono_mb_emit_icall (mb
, cominterop_get_interface
);
2447 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
) {
2448 static MonoProperty
* iunknown
= NULL
;
2451 iunknown
= mono_class_get_property_from_name (mono_defaults
.com_object_class
, "IUnknown");
2452 mono_mb_emit_managed_call (mb
, iunknown
->get
, NULL
);
2454 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
) {
2455 static MonoProperty
* idispatch
= NULL
;
2458 idispatch
= mono_class_get_property_from_name (mono_defaults
.com_object_class
, "IDispatch");
2459 mono_mb_emit_managed_call (mb
, idispatch
->get
, NULL
);
2462 g_assert_not_reached ();
2464 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2465 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
2468 mono_mb_patch_short_branch (mb
, pos_rcw
);
2469 /* load dst to store later */
2470 mono_mb_emit_ldloc (mb
, 1);
2472 mono_mb_emit_ldloc (mb
, 0);
2473 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2475 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
)
2476 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
2477 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
)
2478 mono_mb_emit_ptr (mb
, mono_defaults
.iunknown_class
);
2479 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
)
2480 mono_mb_emit_ptr (mb
, mono_defaults
.idispatch_class
);
2482 g_assert_not_reached ();
2483 mono_mb_emit_icall (mb
, cominterop_get_ccw
);
2484 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2486 mono_mb_patch_short_branch (mb
, pos_end
);
2487 mono_mb_patch_short_branch (mb
, pos_null
);
2491 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
2492 int dar_release_slot
, pos
;
2494 dar_release_slot
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
2497 * The following is ifdefed-out, because I have no way of doing the
2498 * DangerousRelease when destroying the structure
2501 /* set release = false */
2502 mono_mb_emit_icon (mb
, 0);
2503 mono_mb_emit_stloc (mb
, dar_release_slot
);
2504 if (!sh_dangerous_add_ref
)
2505 init_safe_handle ();
2507 /* safehandle.DangerousAddRef (ref release) */
2508 mono_mb_emit_ldloc (mb
, 0); /* the source */
2509 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2510 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
2511 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
2513 mono_mb_emit_ldloc (mb
, 0);
2514 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2515 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
2516 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
2517 mono_mb_patch_branch (mb
, pos
);
2519 /* Pull the handle field from SafeHandle */
2520 mono_mb_emit_ldloc (mb
, 1);
2521 mono_mb_emit_ldloc (mb
, 0);
2522 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2523 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
2524 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2525 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2529 case MONO_MARSHAL_CONV_HANDLEREF
: {
2530 mono_mb_emit_ldloc (mb
, 1);
2531 mono_mb_emit_ldloc (mb
, 0);
2532 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoHandleRef
, handle
));
2533 mono_mb_emit_byte (mb
, CEE_ADD
);
2534 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2535 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2540 char *msg
= g_strdup_printf ("marshalling conversion %d not implemented", conv
);
2541 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
2544 mono_raise_exception (exc
);
2550 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
2552 MonoMarshalType
*info
;
2556 emit_struct_conv(mb
, klass
->parent
, to_object
);
2558 info
= mono_marshal_load_type_info (klass
);
2560 if (info
->native_size
== 0)
2563 if (klass
->blittable
) {
2564 int msize
= mono_class_value_size (klass
, NULL
);
2565 g_assert (msize
== info
->native_size
);
2566 mono_mb_emit_ldloc (mb
, 1);
2567 mono_mb_emit_ldloc (mb
, 0);
2568 mono_mb_emit_icon (mb
, msize
);
2569 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2570 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2572 mono_mb_emit_add_to_local (mb
, 0, msize
);
2573 mono_mb_emit_add_to_local (mb
, 1, msize
);
2577 for (i
= 0; i
< info
->num_fields
; i
++) {
2578 MonoMarshalNative ntype
;
2579 MonoMarshalConv conv
;
2580 MonoType
*ftype
= info
->fields
[i
].field
->type
;
2583 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
2585 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
2588 ntype
= mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, klass
->unicode
, &conv
);
2591 msize
= klass
->instance_size
- info
->fields
[i
].field
->offset
;
2592 usize
= info
->native_size
- info
->fields
[i
].offset
;
2594 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
2595 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
2598 if (klass
!= mono_defaults
.safehandle_class
){
2600 * FIXME: Should really check for usize==0 and msize>0, but we apply
2601 * the layout to the managed structure as well.
2604 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) && (usize
== 0)) {
2605 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
2606 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
2607 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
2608 "reference field at the same offset as another field.",
2609 mono_type_full_name (&klass
->byval_arg
));
2612 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
)
2613 g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute",
2614 mono_type_full_name (&klass
->byval_arg
));
2619 case MONO_MARSHAL_CONV_NONE
: {
2622 if (ftype
->byref
|| ftype
->type
== MONO_TYPE_I
||
2623 ftype
->type
== MONO_TYPE_U
) {
2624 mono_mb_emit_ldloc (mb
, 1);
2625 mono_mb_emit_ldloc (mb
, 0);
2626 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2627 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2638 case MONO_TYPE_BOOLEAN
:
2641 case MONO_TYPE_CHAR
:
2647 mono_mb_emit_ldloc (mb
, 1);
2648 mono_mb_emit_ldloc (mb
, 0);
2649 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
2650 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
2652 case MONO_TYPE_VALUETYPE
: {
2653 int src_var
, dst_var
;
2655 if (ftype
->data
.klass
->enumtype
) {
2656 ftype
= ftype
->data
.klass
->enum_basetype
;
2660 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2661 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2663 /* save the old src pointer */
2664 mono_mb_emit_ldloc (mb
, 0);
2665 mono_mb_emit_stloc (mb
, src_var
);
2666 /* save the old dst pointer */
2667 mono_mb_emit_ldloc (mb
, 1);
2668 mono_mb_emit_stloc (mb
, dst_var
);
2670 emit_struct_conv (mb
, ftype
->data
.klass
, to_object
);
2672 /* restore the old src pointer */
2673 mono_mb_emit_ldloc (mb
, src_var
);
2674 mono_mb_emit_stloc (mb
, 0);
2675 /* restore the old dst pointer */
2676 mono_mb_emit_ldloc (mb
, dst_var
);
2677 mono_mb_emit_stloc (mb
, 1);
2680 case MONO_TYPE_OBJECT
: {
2681 mono_init_com_types ();
2683 static MonoMethod
*variant_clear
= NULL
;
2684 static MonoMethod
*get_object_for_native_variant
= NULL
;
2687 variant_clear
= mono_class_get_method_from_name (mono_defaults
.variant_class
, "Clear", 0);
2688 if (!get_object_for_native_variant
)
2689 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
2690 mono_mb_emit_ldloc (mb
, 1);
2691 mono_mb_emit_ldloc (mb
, 0);
2692 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
2693 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2695 mono_mb_emit_ldloc (mb
, 0);
2696 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
2699 static MonoMethod
*get_native_variant_for_object
= NULL
;
2701 if (!get_native_variant_for_object
)
2702 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
2704 mono_mb_emit_ldloc (mb
, 0);
2705 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
2706 mono_mb_emit_ldloc (mb
, 1);
2707 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
2713 g_warning ("marshaling type %02x not implemented", ftype
->type
);
2714 g_assert_not_reached ();
2719 int src_var
, dst_var
;
2721 src_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2722 dst_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2724 /* save the old src pointer */
2725 mono_mb_emit_ldloc (mb
, 0);
2726 mono_mb_emit_stloc (mb
, src_var
);
2727 /* save the old dst pointer */
2728 mono_mb_emit_ldloc (mb
, 1);
2729 mono_mb_emit_stloc (mb
, dst_var
);
2732 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
2734 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
2736 /* restore the old src pointer */
2737 mono_mb_emit_ldloc (mb
, src_var
);
2738 mono_mb_emit_stloc (mb
, 0);
2739 /* restore the old dst pointer */
2740 mono_mb_emit_ldloc (mb
, dst_var
);
2741 mono_mb_emit_stloc (mb
, 1);
2746 mono_mb_emit_add_to_local (mb
, 0, usize
);
2747 mono_mb_emit_add_to_local (mb
, 1, msize
);
2749 mono_mb_emit_add_to_local (mb
, 0, msize
);
2750 mono_mb_emit_add_to_local (mb
, 1, usize
);
2756 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
2758 /* Call DestroyStructure */
2759 /* FIXME: Only do this if needed */
2760 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2761 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
2762 mono_mb_emit_ldloc (mb
, struct_var
);
2763 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
2767 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, gpointer checkpoint_func
)
2771 mono_mb_emit_ptr (mb
, (gpointer
) mono_thread_interruption_request_flag ());
2772 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
2773 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2775 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2776 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
2778 mono_mb_emit_icall (mb
, checkpoint_func
);
2780 mono_mb_patch_addr (mb
, pos_noabort
, mb
->pos
- (pos_noabort
+ 4));
2784 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2786 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
2789 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_interruption_checkpoint
);
2793 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
2795 emit_thread_interrupt_checkpoint_call (mb
, mono_thread_force_interruption_checkpoint
);
2798 static MonoAsyncResult
*
2799 mono_delegate_begin_invoke (MonoDelegate
*delegate
, gpointer
*params
)
2801 MonoMethodMessage
*msg
;
2802 MonoDelegate
*async_callback
;
2806 MonoMethod
*method
= NULL
, *method2
= NULL
;
2808 g_assert (delegate
);
2810 if (delegate
->target
&& mono_object_class (delegate
->target
) == mono_defaults
.transparent_proxy_class
) {
2812 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
2813 if (!tp
->remote_class
->proxy_class
->contextbound
|| tp
->rp
->context
!= (MonoObject
*) mono_context_get ()) {
2815 /* If the target is a proxy, make a direct call. Is proxy's work
2816 // to make the call asynchronous.
2818 MonoAsyncResult
*ares
;
2820 MonoArray
*out_args
;
2822 method
= delegate
->method_info
->method
;
2824 msg
= mono_method_call_message_new (mono_marshal_method_from_wrapper (method
), params
, NULL
, &async_callback
, &state
);
2825 handle
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
2826 g_assert(handle
!= NULL
);
2827 ares
= mono_async_result_new (mono_domain_get (), handle
, state
, handle
, NULL
);
2828 MONO_OBJECT_SETREF (ares
, async_delegate
, (MonoObject
*)delegate
);
2829 MONO_OBJECT_SETREF (ares
, async_callback
, (MonoObject
*)async_callback
);
2830 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
2831 msg
->call_type
= CallType_BeginInvoke
;
2833 mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
);
2838 klass
= delegate
->object
.vtable
->klass
;
2840 method
= mono_get_delegate_invoke (klass
);
2841 method2
= mono_class_get_method_from_name (klass
, "BeginInvoke", -1);
2844 g_assert (method
!= NULL
);
2846 im
= mono_get_delegate_invoke (method
->klass
);
2847 msg
= mono_method_call_message_new (method
, params
, im
, &async_callback
, &state
);
2849 return mono_thread_pool_add ((MonoObject
*)delegate
, msg
, async_callback
, state
);
2853 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
2855 int i
, params_var
, tmp_var
;
2857 /* allocate local (pointer) *params[] */
2858 params_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2859 /* allocate local (pointer) tmp */
2860 tmp_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
2862 /* alloate space on stack to store an array of pointers to the arguments */
2863 mono_mb_emit_icon (mb
, sizeof (gpointer
) * (sig
->param_count
+ 1));
2864 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2865 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2866 mono_mb_emit_stloc (mb
, params_var
);
2869 mono_mb_emit_ldloc (mb
, params_var
);
2870 mono_mb_emit_stloc (mb
, tmp_var
);
2872 if (save_this
&& sig
->hasthis
) {
2873 mono_mb_emit_ldloc (mb
, tmp_var
);
2874 mono_mb_emit_ldarg_addr (mb
, 0);
2875 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2876 /* tmp = tmp + sizeof (gpointer) */
2877 if (sig
->param_count
)
2878 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2882 for (i
= 0; i
< sig
->param_count
; i
++) {
2883 mono_mb_emit_ldloc (mb
, tmp_var
);
2884 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
2885 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2886 /* tmp = tmp + sizeof (gpointer) */
2887 if (i
< (sig
->param_count
- 1))
2888 mono_mb_emit_add_to_local (mb
, tmp_var
, sizeof (gpointer
));
2895 mono_signature_to_name (MonoMethodSignature
*sig
, const char *prefix
)
2899 GString
*res
= g_string_new ("");
2902 g_string_append (res
, prefix
);
2903 g_string_append_c (res
, '_');
2906 mono_type_get_desc (res
, sig
->ret
, FALSE
);
2908 for (i
= 0; i
< sig
->param_count
; ++i
) {
2909 g_string_append_c (res
, '_');
2910 mono_type_get_desc (res
, sig
->params
[i
], FALSE
);
2913 g_string_free (res
, FALSE
);
2918 * mono_marshal_get_string_encoding:
2920 * Return the string encoding which should be used for a given parameter.
2922 static MonoMarshalNative
2923 mono_marshal_get_string_encoding (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2925 /* First try the parameter marshal info */
2927 if (spec
->native
== MONO_NATIVE_LPARRAY
) {
2928 if ((spec
->data
.array_data
.elem_type
!= 0) && (spec
->data
.array_data
.elem_type
!= MONO_NATIVE_MAX
))
2929 return spec
->data
.array_data
.elem_type
;
2932 return spec
->native
;
2936 return MONO_NATIVE_LPSTR
;
2938 /* Then try the method level marshal info */
2939 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
2940 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
2941 return MONO_NATIVE_LPSTR
;
2942 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
2943 return MONO_NATIVE_LPWSTR
;
2944 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
2945 #ifdef PLATFORM_WIN32
2946 return MONO_NATIVE_LPWSTR
;
2948 return MONO_NATIVE_LPSTR
;
2951 return MONO_NATIVE_LPSTR
;
2955 static MonoMarshalConv
2956 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2958 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2961 case MONO_NATIVE_LPWSTR
:
2962 return MONO_MARSHAL_CONV_STR_LPWSTR
;
2963 case MONO_NATIVE_LPSTR
:
2964 return MONO_MARSHAL_CONV_STR_LPSTR
;
2965 case MONO_NATIVE_LPTSTR
:
2966 return MONO_MARSHAL_CONV_STR_LPTSTR
;
2967 case MONO_NATIVE_BSTR
:
2968 return MONO_MARSHAL_CONV_STR_BSTR
;
2974 static MonoMarshalConv
2975 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
2977 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
2980 case MONO_NATIVE_LPWSTR
:
2981 return MONO_MARSHAL_CONV_SB_LPWSTR
;
2983 case MONO_NATIVE_LPSTR
:
2984 return MONO_MARSHAL_CONV_SB_LPSTR
;
2986 case MONO_NATIVE_LPTSTR
:
2987 return MONO_MARSHAL_CONV_SB_LPTSTR
;
2994 static MonoMarshalConv
2995 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
2997 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
3002 case MONO_NATIVE_LPWSTR
:
3003 return MONO_MARSHAL_CONV_LPWSTR_STR
;
3004 case MONO_NATIVE_LPSTR
:
3005 return MONO_MARSHAL_CONV_LPSTR_STR
;
3006 case MONO_NATIVE_LPTSTR
:
3007 return MONO_MARSHAL_CONV_LPTSTR_STR
;
3008 case MONO_NATIVE_BSTR
:
3009 return MONO_MARSHAL_CONV_BSTR_STR
;
3015 static MonoMarshalConv
3016 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
, gboolean
*need_free
)
3018 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
3023 case MONO_NATIVE_LPWSTR
:
3025 * mono_string_builder_to_utf16 does not allocate a
3026 * new buffer, so no need to free it.
3029 return MONO_MARSHAL_CONV_LPWSTR_SB
;
3030 case MONO_NATIVE_LPSTR
:
3031 return MONO_MARSHAL_CONV_LPSTR_SB
;
3033 case MONO_NATIVE_LPTSTR
:
3034 return MONO_MARSHAL_CONV_LPTSTR_SB
;
3042 * Return whenever a field of a native structure or an array member needs to
3046 mono_marshal_need_free (MonoType
*t
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
*spec
)
3048 MonoMarshalNative encoding
;
3049 MonoMarshalConv conv
;
3052 case MONO_TYPE_VALUETYPE
:
3053 /* FIXME: Optimize this */
3055 case MONO_TYPE_OBJECT
:
3056 case MONO_TYPE_CLASS
:
3057 if (t
->data
.klass
== mono_defaults
.stringbuilder_class
) {
3059 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (piinfo
, spec
, &need_free
);
3063 case MONO_TYPE_STRING
:
3064 encoding
= mono_marshal_get_string_encoding (piinfo
, spec
);
3065 return (encoding
== MONO_NATIVE_LPWSTR
) ? FALSE
: TRUE
;
3071 static inline MonoMethod
*
3072 mono_marshal_find_in_cache (GHashTable
*cache
, gpointer key
)
3076 mono_marshal_lock ();
3077 res
= g_hash_table_lookup (cache
, key
);
3078 mono_marshal_unlock ();
3082 /* Create the method from the builder and place it in the cache */
3083 static inline MonoMethod
*
3084 mono_mb_create_and_cache (GHashTable
*cache
, gpointer key
,
3085 MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
,
3090 mono_marshal_lock ();
3091 res
= g_hash_table_lookup (cache
, key
);
3092 mono_marshal_unlock ();
3095 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
3096 mono_marshal_lock ();
3097 res
= g_hash_table_lookup (cache
, key
);
3100 g_hash_table_insert (cache
, key
, res
);
3101 g_hash_table_insert (wrapper_hash
, res
, key
);
3102 mono_marshal_unlock ();
3104 mono_marshal_unlock ();
3105 mono_free_method (newm
);
3113 static inline MonoMethod
*
3114 mono_marshal_remoting_find_in_cache (MonoMethod
*method
, int wrapper_type
)
3116 MonoMethod
*res
= NULL
;
3117 MonoRemotingMethods
*wrps
;
3119 mono_marshal_lock ();
3120 wrps
= g_hash_table_lookup (method
->klass
->image
->remoting_invoke_cache
, method
);
3123 switch (wrapper_type
) {
3124 case MONO_WRAPPER_REMOTING_INVOKE
: res
= wrps
->invoke
; break;
3125 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
: res
= wrps
->invoke_with_check
; break;
3126 case MONO_WRAPPER_XDOMAIN_INVOKE
: res
= wrps
->xdomain_invoke
; break;
3127 case MONO_WRAPPER_XDOMAIN_DISPATCH
: res
= wrps
->xdomain_dispatch
; break;
3131 /* it is important to do the unlock after the load from wrps, since in
3132 * mono_remoting_mb_create_and_cache () we drop the marshal lock to be able
3133 * to take the loader lock and some other thread may set the fields.
3135 mono_marshal_unlock ();
3139 /* Create the method from the builder and place it in the cache */
3140 static inline MonoMethod
*
3141 mono_remoting_mb_create_and_cache (MonoMethod
*key
, MonoMethodBuilder
*mb
,
3142 MonoMethodSignature
*sig
, int max_stack
)
3144 MonoMethod
**res
= NULL
;
3145 MonoRemotingMethods
*wrps
;
3146 GHashTable
*cache
= key
->klass
->image
->remoting_invoke_cache
;
3148 mono_marshal_lock ();
3149 wrps
= g_hash_table_lookup (cache
, key
);
3151 wrps
= g_new0 (MonoRemotingMethods
, 1);
3152 g_hash_table_insert (cache
, key
, wrps
);
3155 switch (mb
->method
->wrapper_type
) {
3156 case MONO_WRAPPER_REMOTING_INVOKE
: res
= &wrps
->invoke
; break;
3157 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
: res
= &wrps
->invoke_with_check
; break;
3158 case MONO_WRAPPER_XDOMAIN_INVOKE
: res
= &wrps
->xdomain_invoke
; break;
3159 case MONO_WRAPPER_XDOMAIN_DISPATCH
: res
= &wrps
->xdomain_dispatch
; break;
3160 default: g_assert_not_reached (); break;
3162 mono_marshal_unlock ();
3166 newm
= mono_mb_create_method (mb
, sig
, max_stack
);
3168 mono_marshal_lock ();
3171 g_hash_table_insert (wrapper_hash
, *res
, key
);
3172 mono_marshal_unlock ();
3174 mono_marshal_unlock ();
3175 mono_free_method (newm
);
3183 mono_marshal_method_from_wrapper (MonoMethod
*wrapper
)
3187 if (wrapper
->wrapper_type
== MONO_WRAPPER_NONE
)
3190 mono_marshal_lock ();
3191 res
= g_hash_table_lookup (wrapper_hash
, wrapper
);
3192 mono_marshal_unlock ();
3197 mono_marshal_get_delegate_begin_invoke (MonoMethod
*method
)
3199 MonoMethodSignature
*sig
;
3200 MonoMethodBuilder
*mb
;
3206 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3207 !strcmp (method
->name
, "BeginInvoke"));
3209 sig
= signature_no_pinvoke (method
);
3211 cache
= method
->klass
->image
->delegate_begin_invoke_cache
;
3212 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
3215 g_assert (sig
->hasthis
);
3217 name
= mono_signature_to_name (sig
, "begin_invoke");
3218 mb
= mono_mb_new (mono_defaults
.multicastdelegate_class
, name
, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE
);
3221 mb
->method
->save_lmf
= 1;
3223 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3225 mono_mb_emit_ldarg (mb
, 0);
3226 mono_mb_emit_ldloc (mb
, params_var
);
3227 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
3228 emit_thread_interrupt_checkpoint (mb
);
3229 mono_mb_emit_byte (mb
, CEE_RET
);
3231 res
= mono_mb_create_and_cache (cache
, sig
, mb
, sig
, sig
->param_count
+ 16);
3237 mono_delegate_end_invoke (MonoDelegate
*delegate
, gpointer
*params
)
3239 MonoDomain
*domain
= mono_domain_get ();
3240 MonoAsyncResult
*ares
;
3241 MonoMethod
*method
= NULL
;
3242 MonoMethodSignature
*sig
;
3243 MonoMethodMessage
*msg
;
3244 MonoObject
*res
, *exc
;
3245 MonoArray
*out_args
;
3248 g_assert (delegate
);
3250 if (!delegate
->method_info
|| !delegate
->method_info
->method
)
3251 g_assert_not_reached ();
3253 klass
= delegate
->object
.vtable
->klass
;
3255 method
= mono_class_get_method_from_name (klass
, "EndInvoke", -1);
3256 g_assert (method
!= NULL
);
3258 sig
= signature_no_pinvoke (method
);
3260 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
);
3262 ares
= mono_array_get (msg
->args
, gpointer
, sig
->param_count
- 1);
3265 if (ares
->async_delegate
!= (MonoObject
*)delegate
&& mono_get_runtime_info ()->framework_version
[0] >= '2') {
3266 mono_raise_exception (mono_get_exception_invalid_operation (
3267 "The IAsyncResult object provided does not match this delegate."));
3271 if (delegate
->target
&& mono_object_class (delegate
->target
) == mono_defaults
.transparent_proxy_class
) {
3272 MonoTransparentProxy
* tp
= (MonoTransparentProxy
*)delegate
->target
;
3273 msg
= (MonoMethodMessage
*)mono_object_new (domain
, mono_defaults
.mono_method_message_class
);
3274 mono_message_init (domain
, msg
, delegate
->method_info
, NULL
);
3275 msg
->call_type
= CallType_EndInvoke
;
3276 MONO_OBJECT_SETREF (msg
, async_result
, ares
);
3277 res
= mono_remoting_invoke ((MonoObject
*)tp
->rp
, msg
, &exc
, &out_args
);
3279 res
= mono_thread_pool_finish (ares
, &out_args
, &exc
);
3283 if (((MonoException
*)exc
)->stack_trace
) {
3284 char *strace
= mono_string_to_utf8 (((MonoException
*)exc
)->stack_trace
);
3286 tmp
= g_strdup_printf ("%s\nException Rethrown at:\n", strace
);
3288 MONO_OBJECT_SETREF (((MonoException
*)exc
), stack_trace
, mono_string_new (domain
, tmp
));
3291 mono_raise_exception ((MonoException
*)exc
);
3294 mono_method_return_message_restore (method
, params
, out_args
);
3299 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
3301 MonoType
*t
= mono_type_get_underlying_type (return_type
);
3303 if (return_type
->byref
)
3304 return_type
= &mono_defaults
.int_class
->byval_arg
;
3307 case MONO_TYPE_VOID
:
3308 g_assert_not_reached ();
3311 case MONO_TYPE_STRING
:
3312 case MONO_TYPE_CLASS
:
3313 case MONO_TYPE_OBJECT
:
3314 case MONO_TYPE_ARRAY
:
3315 case MONO_TYPE_SZARRAY
:
3319 case MONO_TYPE_BOOLEAN
:
3322 case MONO_TYPE_CHAR
:
3332 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (return_type
));
3333 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
3335 case MONO_TYPE_GENERICINST
:
3336 if (!mono_type_generic_inst_is_valuetype (return_type
))
3339 case MONO_TYPE_VALUETYPE
: {
3340 MonoClass
*klass
= mono_class_from_mono_type (return_type
);
3341 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
3342 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
3346 g_warning ("type 0x%x not handled", return_type
->type
);
3347 g_assert_not_reached ();
3350 mono_mb_emit_byte (mb
, CEE_RET
);
3354 mono_marshal_get_delegate_end_invoke (MonoMethod
*method
)
3356 MonoMethodSignature
*sig
;
3357 MonoMethodBuilder
*mb
;
3363 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
3364 !strcmp (method
->name
, "EndInvoke"));
3366 sig
= signature_no_pinvoke (method
);
3368 cache
= method
->klass
->image
->delegate_end_invoke_cache
;
3369 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
3372 g_assert (sig
->hasthis
);
3374 name
= mono_signature_to_name (sig
, "end_invoke");
3375 mb
= mono_mb_new (mono_defaults
.multicastdelegate_class
, name
, MONO_WRAPPER_DELEGATE_END_INVOKE
);
3378 mb
->method
->save_lmf
= 1;
3380 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3382 mono_mb_emit_ldarg (mb
, 0);
3383 mono_mb_emit_ldloc (mb
, params_var
);
3384 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
3385 emit_thread_interrupt_checkpoint (mb
);
3387 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
3388 mono_mb_emit_byte (mb
, CEE_POP
);
3389 mono_mb_emit_byte (mb
, CEE_RET
);
3391 mono_mb_emit_restore_result (mb
, sig
->ret
);
3393 res
= mono_mb_create_and_cache (cache
, sig
,
3394 mb
, sig
, sig
->param_count
+ 16);
3401 mono_remoting_wrapper (MonoMethod
*method
, gpointer
*params
)
3403 MonoMethodMessage
*msg
;
3404 MonoTransparentProxy
*this;
3405 MonoObject
*res
, *exc
;
3406 MonoArray
*out_args
;
3408 this = *((MonoTransparentProxy
**)params
[0]);
3411 g_assert (((MonoObject
*)this)->vtable
->klass
== mono_defaults
.transparent_proxy_class
);
3413 /* skip the this pointer */
3416 if (this->remote_class
->proxy_class
->contextbound
&& this->rp
->context
== (MonoObject
*) mono_context_get ())
3419 MonoMethodSignature
*sig
= mono_method_signature (method
);
3420 int count
= sig
->param_count
;
3421 gpointer
* mparams
= (gpointer
*) alloca(count
*sizeof(gpointer
));
3423 for (i
=0; i
<count
; i
++) {
3424 MonoClass
*class = mono_class_from_mono_type (sig
->params
[i
]);
3425 if (class->valuetype
) {
3426 if (sig
->params
[i
]->byref
)
3427 mparams
[i
] = *((gpointer
*)params
[i
]);
3429 mparams
[i
] = params
[i
];
3431 mparams
[i
] = *((gpointer
**)params
[i
]);
3435 return mono_runtime_invoke (method
, method
->klass
->valuetype
? mono_object_unbox ((MonoObject
*)this): this, mparams
, NULL
);
3438 msg
= mono_method_call_message_new (method
, params
, NULL
, NULL
, NULL
);
3440 res
= mono_remoting_invoke ((MonoObject
*)this->rp
, msg
, &exc
, &out_args
);
3443 mono_raise_exception ((MonoException
*)exc
);
3445 mono_method_return_message_restore (method
, params
, out_args
);
3451 * cominterop_get_native_wrapper_adjusted:
3452 * @method: managed COM Interop method
3454 * Returns: the generated method to call with signature matching
3455 * the unmanaged COM Method signature
3458 cominterop_get_native_wrapper_adjusted (MonoMethod
*method
)
3461 MonoMethodBuilder
*mb_native
;
3462 MonoMarshalSpec
**mspecs
;
3463 MonoMethodSignature
*sig
, *sig_native
;
3464 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
3467 sig
= mono_method_signature (method
);
3469 // create unmanaged wrapper
3470 mb_native
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
3471 sig_native
= cominterop_method_signature (method
);
3473 mspecs
= g_new (MonoMarshalSpec
*, sig_native
->param_count
+1);
3474 memset (mspecs
, 0, sizeof(MonoMarshalSpec
*)*(sig_native
->param_count
+1));
3476 mono_method_get_marshal_info (method
, mspecs
);
3478 // move managed args up one
3479 for (i
= sig
->param_count
; i
>= 1; i
--)
3480 mspecs
[i
+1] = mspecs
[i
];
3482 // first arg is IntPtr for interface
3485 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
)) {
3486 // move return spec to last param
3487 if (!MONO_TYPE_IS_VOID (sig
->ret
))
3488 mspecs
[sig_native
->param_count
] = mspecs
[0];
3493 mono_marshal_emit_native_wrapper(method
->klass
->image
, mb_native
, sig_native
, piinfo
, mspecs
, piinfo
->addr
);
3495 res
= mono_mb_create_method (mb_native
, sig_native
, sig_native
->param_count
+ 16);
3497 mono_mb_free (mb_native
);
3499 for (i
= sig_native
->param_count
; i
>= 0; i
--)
3501 mono_metadata_free_marshal_spec (mspecs
[i
]);
3508 * cominterop_get_native_wrapper:
3509 * @method: managed method
3511 * Returns: the generated method to call
3514 cominterop_get_native_wrapper (MonoMethod
*method
)
3518 MonoMethodBuilder
*mb
;
3519 MonoMethodSignature
*sig
, *csig
;
3523 cache
= method
->klass
->image
->cominterop_wrapper_cache
;
3524 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3527 mono_init_com_types ();
3529 sig
= mono_method_signature (method
);
3530 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
3532 /* if method klass is import, that means method
3533 * is really a com call. let interop system emit it.
3535 if (MONO_CLASS_IS_IMPORT(method
->klass
)) {
3536 /* FIXME: we have to call actual class .ctor
3537 * instead of just __ComObject .ctor.
3539 if (!strcmp(method
->name
, ".ctor")) {
3540 static MonoMethod
*ctor
= NULL
;
3543 ctor
= mono_class_get_method_from_name (mono_defaults
.com_object_class
, ".ctor", 0);
3544 mono_mb_emit_ldarg (mb
, 0);
3545 mono_mb_emit_managed_call (mb
, ctor
, NULL
);
3546 mono_mb_emit_byte (mb
, CEE_RET
);
3549 static MonoMethod
* ThrowExceptionForHR
= NULL
;
3550 MonoMethod
*adjusted_method
;
3554 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
3556 // add local variables
3557 ptr_this
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
3558 if (!MONO_TYPE_IS_VOID (sig
->ret
))
3559 retval
= mono_mb_add_local (mb
, sig
->ret
);
3561 // get the type for the interface the method is defined on
3562 // and then get the underlying COM interface for that type
3563 mono_mb_emit_ldarg (mb
, 0);
3564 mono_mb_emit_ptr (mb
, method
);
3565 mono_mb_emit_icall (mb
, cominterop_get_method_interface
);
3566 mono_mb_emit_icon (mb
, TRUE
);
3567 mono_mb_emit_icall (mb
, cominterop_get_interface
);
3568 mono_mb_emit_stloc (mb
, ptr_this
);
3570 // arg 1 is unmanaged this pointer
3571 mono_mb_emit_ldloc (mb
, ptr_this
);
3574 for (i
= 1; i
<= sig
->param_count
; i
++)
3575 mono_mb_emit_ldarg (mb
, i
);
3577 // push managed return value as byref last argument
3578 if (!MONO_TYPE_IS_VOID (sig
->ret
) && !preserve_sig
)
3579 mono_mb_emit_ldloc_addr (mb
, retval
);
3581 adjusted_method
= cominterop_get_native_wrapper_adjusted (method
);
3582 mono_mb_emit_managed_call (mb
, adjusted_method
, NULL
);
3584 if (!preserve_sig
) {
3585 if (!ThrowExceptionForHR
)
3586 ThrowExceptionForHR
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "ThrowExceptionForHR", 1);
3587 mono_mb_emit_managed_call (mb
, ThrowExceptionForHR
, NULL
);
3589 // load return value managed is expecting
3590 if (!MONO_TYPE_IS_VOID (sig
->ret
))
3591 mono_mb_emit_ldloc (mb
, retval
);
3594 mono_mb_emit_byte (mb
, CEE_RET
);
3599 /* Does this case ever get hit? */
3601 char *msg
= g_strdup ("non imported interfaces on \
3602 imported classes is not yet implemented.");
3603 mono_mb_emit_exception (mb
, "NotSupportedException", msg
);
3605 csig
= signature_dup (method
->klass
->image
, sig
);
3607 res
= mono_mb_create_and_cache (cache
, method
,
3608 mb
, csig
, csig
->param_count
+ 16);
3614 * cominterop_get_invoke:
3615 * @method: managed method
3617 * Returns: the generated method that calls the underlying __ComObject
3618 * rather than the proxy object.
3621 cominterop_get_invoke (MonoMethod
*method
)
3623 MonoMethodSignature
*sig
;
3624 MonoMethodBuilder
*mb
;
3627 GHashTable
* cache
= method
->klass
->image
->cominterop_invoke_cache
;
3631 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
3634 sig
= signature_no_pinvoke (method
);
3636 /* we cant remote methods without this pointer */
3640 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP_INVOKE
);
3642 /* get real proxy object, which is a ComInteropProxy in this case*/
3643 temp_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
3644 mono_mb_emit_ldarg (mb
, 0);
3645 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
3646 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3648 /* load the RCW from the ComInteropProxy*/
3649 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
3650 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3652 /* load args and make the call on the RCW */
3653 for (i
= 1; i
<= sig
->param_count
; i
++)
3654 mono_mb_emit_ldarg (mb
, i
);
3656 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
3657 MonoMethod
* native_wrapper
= cominterop_get_native_wrapper(method
);
3658 mono_mb_emit_managed_call (mb
, native_wrapper
, NULL
);
3661 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
3662 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
3664 mono_mb_emit_op (mb
, CEE_CALL
, method
);
3667 if (!strcmp(method
->name
, ".ctor")) {
3668 static MonoClass
*com_interop_proxy_class
= NULL
;
3669 static MonoMethod
*cache_proxy
= NULL
;
3671 if (!com_interop_proxy_class
)
3672 com_interop_proxy_class
= mono_class_from_name (mono_defaults
.corlib
, "Mono.Interop", "ComInteropProxy");
3674 cache_proxy
= mono_class_get_method_from_name (com_interop_proxy_class
, "CacheProxy", 0);
3676 mono_mb_emit_ldarg (mb
, 0);
3677 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
3678 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3679 mono_mb_emit_managed_call (mb
, cache_proxy
, NULL
);
3682 emit_thread_interrupt_checkpoint (mb
);
3684 mono_mb_emit_byte (mb
, CEE_RET
);
3686 res
= mono_mb_create_and_cache (cache
, method
, mb
, sig
, sig
->param_count
+ 16);
3691 /* Maps a managed object to its unmanaged representation
3692 * i.e. it's COM Callable Wrapper (CCW).
3696 static GHashTable
* ccw_hash
= NULL
;
3698 /* Maps a CCW interface to it's containing CCW.
3699 * Note that a CCW support many interfaces.
3701 * Value: MonoCCWInterface*
3703 static GHashTable
* ccw_interface_hash
= NULL
;
3705 /* Maps the IUnknown value of a RCW to
3706 * it's MonoComInteropProxy*.
3710 static GHashTable
* rcw_hash
= NULL
;
3713 mono_marshal_get_remoting_invoke (MonoMethod
*method
)
3715 MonoMethodSignature
*sig
;
3716 MonoMethodBuilder
*mb
;
3722 if (method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
|| method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
)
3725 /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
3726 if ((method
->klass
->is_com_object
|| method
->klass
== mono_defaults
.com_object_class
) && !mono_class_vtable (mono_domain_get (), method
->klass
)->remote
)
3727 return cominterop_get_invoke(method
);
3729 sig
= signature_no_pinvoke (method
);
3731 /* we cant remote methods without this pointer */
3735 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_REMOTING_INVOKE
)))
3738 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_REMOTING_INVOKE
);
3739 mb
->method
->save_lmf
= 1;
3741 params_var
= mono_mb_emit_save_args (mb
, sig
, TRUE
);
3743 mono_mb_emit_ptr (mb
, method
);
3744 mono_mb_emit_ldloc (mb
, params_var
);
3745 mono_mb_emit_icall (mb
, mono_remoting_wrapper
);
3746 emit_thread_interrupt_checkpoint (mb
);
3748 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
3749 mono_mb_emit_byte (mb
, CEE_POP
);
3750 mono_mb_emit_byte (mb
, CEE_RET
);
3752 mono_mb_emit_restore_result (mb
, sig
->ret
);
3755 res
= mono_remoting_mb_create_and_cache (method
, mb
, sig
, sig
->param_count
+ 16);
3761 /* mono_get_xdomain_marshal_type()
3762 * Returns the kind of marshalling that a type needs for cross domain calls.
3764 static MonoXDomainMarshalType
3765 mono_get_xdomain_marshal_type (MonoType
*t
)
3768 case MONO_TYPE_VOID
:
3769 g_assert_not_reached ();
3773 case MONO_TYPE_BOOLEAN
:
3776 case MONO_TYPE_CHAR
:
3783 return MONO_MARSHAL_NONE
;
3784 case MONO_TYPE_STRING
:
3785 return MONO_MARSHAL_COPY
;
3786 case MONO_TYPE_ARRAY
:
3787 case MONO_TYPE_SZARRAY
: {
3788 MonoClass
*elem_class
= mono_class_from_mono_type (t
)->element_class
;
3789 if (mono_get_xdomain_marshal_type (&(elem_class
->byval_arg
)) != MONO_MARSHAL_SERIALIZE
)
3790 return MONO_MARSHAL_COPY
;
3795 return MONO_MARSHAL_SERIALIZE
;
3799 /* mono_marshal_xdomain_copy_value
3800 * Makes a copy of "val" suitable for the current domain.
3803 mono_marshal_xdomain_copy_value (MonoObject
*val
)
3806 if (val
== NULL
) return NULL
;
3808 domain
= mono_domain_get ();
3810 switch (mono_object_class (val
)->byval_arg
.type
) {
3811 case MONO_TYPE_VOID
:
3812 g_assert_not_reached ();
3816 case MONO_TYPE_BOOLEAN
:
3819 case MONO_TYPE_CHAR
:
3825 case MONO_TYPE_R8
: {
3826 return mono_value_box (domain
, mono_object_class (val
), ((char*)val
) + sizeof(MonoObject
));
3828 case MONO_TYPE_STRING
: {
3829 MonoString
*str
= (MonoString
*) val
;
3830 return (MonoObject
*) mono_string_new_utf16 (domain
, mono_string_chars (str
), mono_string_length (str
));
3832 case MONO_TYPE_ARRAY
:
3833 case MONO_TYPE_SZARRAY
: {
3835 MonoXDomainMarshalType mt
= mono_get_xdomain_marshal_type (&(mono_object_class (val
)->element_class
->byval_arg
));
3836 if (mt
== MONO_MARSHAL_SERIALIZE
) return NULL
;
3837 acopy
= mono_array_clone_in_domain (domain
, (MonoArray
*) val
);
3838 if (mt
== MONO_MARSHAL_COPY
) {
3839 int i
, len
= mono_array_length (acopy
);
3840 for (i
= 0; i
< len
; i
++) {
3841 MonoObject
*item
= mono_array_get (acopy
, gpointer
, i
);
3842 mono_array_setref (acopy
, i
, mono_marshal_xdomain_copy_value (item
));
3845 return (MonoObject
*) acopy
;
3849 if (mono_object_class (val
) == mono_defaults
.stringbuilder_class
) {
3850 MonoStringBuilder
*oldsb
= (MonoStringBuilder
*) val
;
3851 MonoStringBuilder
*newsb
= (MonoStringBuilder
*) mono_object_new (domain
, mono_defaults
.stringbuilder_class
);
3852 MONO_OBJECT_SETREF (newsb
, str
, mono_string_new_utf16 (domain
, mono_string_chars (oldsb
->str
), mono_string_length (oldsb
->str
)));
3853 newsb
->length
= oldsb
->length
;
3854 newsb
->max_capacity
= (gint32
)0x7fffffff;
3855 return (MonoObject
*) newsb
;
3860 /* mono_marshal_xdomain_copy_out_value()
3861 * Copies the contents of the src instance into the dst instance. src and dst
3862 * must have the same type, and if they are arrays, the same size.
3865 mono_marshal_xdomain_copy_out_value (MonoObject
*src
, MonoObject
*dst
)
3867 if (src
== NULL
|| dst
== NULL
) return;
3869 g_assert (mono_object_class (src
) == mono_object_class (dst
));
3871 switch (mono_object_class (src
)->byval_arg
.type
) {
3872 case MONO_TYPE_ARRAY
:
3873 case MONO_TYPE_SZARRAY
: {
3874 int mt
= mono_get_xdomain_marshal_type (&(mono_object_class (src
)->element_class
->byval_arg
));
3875 if (mt
== MONO_MARSHAL_SERIALIZE
) return;
3876 if (mt
== MONO_MARSHAL_COPY
) {
3877 int i
, len
= mono_array_length ((MonoArray
*)dst
);
3878 for (i
= 0; i
< len
; i
++) {
3879 MonoObject
*item
= mono_array_get ((MonoArray
*)src
, gpointer
, i
);
3880 mono_array_setref ((MonoArray
*)dst
, i
, mono_marshal_xdomain_copy_value (item
));
3883 mono_array_full_copy ((MonoArray
*)src
, (MonoArray
*)dst
);
3889 if (mono_object_class (src
) == mono_defaults
.stringbuilder_class
) {
3890 MonoStringBuilder
*src_sb
= (MonoStringBuilder
*) src
;
3891 MonoStringBuilder
*dst_sb
= (MonoStringBuilder
*) dst
;
3893 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
)));
3894 dst_sb
->cached_str
= NULL
;
3895 dst_sb
->length
= src_sb
->length
;
3900 mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder
*mb
, MonoClass
*pclass
)
3902 mono_mb_emit_icall (mb
, mono_marshal_xdomain_copy_value
);
3903 mono_mb_emit_op (mb
, CEE_CASTCLASS
, pclass
);
3907 mono_marshal_emit_xdomain_copy_out_value (MonoMethodBuilder
*mb
, MonoClass
*pclass
)
3909 mono_mb_emit_icall (mb
, mono_marshal_xdomain_copy_out_value
);
3912 /* mono_marshal_supports_fast_xdomain()
3913 * Returns TRUE if the method can use the fast xdomain wrapper.
3916 mono_marshal_supports_fast_xdomain (MonoMethod
*method
)
3918 return !method
->klass
->contextbound
&&
3919 !((method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) && (strcmp (".ctor", method
->name
) == 0));
3923 mono_marshal_set_domain_by_id (gint32 id
, MonoBoolean push
)
3925 MonoDomain
*current_domain
= mono_domain_get ();
3926 MonoDomain
*domain
= mono_domain_get_by_id (id
);
3928 if (!domain
|| !mono_domain_set (domain
, FALSE
))
3929 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
3932 mono_thread_push_appdomain_ref (domain
);
3934 mono_thread_pop_appdomain_ref ();
3936 return current_domain
->domain_id
;
3940 mono_marshal_emit_switch_domain (MonoMethodBuilder
*mb
)
3942 mono_mb_emit_icall (mb
, mono_marshal_set_domain_by_id
);
3945 /* mono_marshal_emit_load_domain_method ()
3946 * Loads into the stack a pointer to the code of the provided method for
3947 * the current domain.
3950 mono_marshal_emit_load_domain_method (MonoMethodBuilder
*mb
, MonoMethod
*method
)
3952 /* We need a pointer to the method for the running domain (not the domain
3953 * that compiles the method).
3955 mono_mb_emit_ptr (mb
, method
);
3956 mono_mb_emit_icall (mb
, mono_compile_method
);
3959 /* mono_marshal_check_domain_image ()
3960 * Returns TRUE if the image is loaded in the specified
3961 * application domain.
3964 mono_marshal_check_domain_image (gint32 domain_id
, MonoImage
*image
)
3969 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
3973 mono_domain_assemblies_lock (domain
);
3974 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
3976 if (ass
->image
== image
)
3979 mono_domain_assemblies_unlock (domain
);
3984 /* mono_marshal_get_xappdomain_dispatch ()
3985 * Generates a method that dispatches a method call from another domain into
3986 * the current domain.
3989 mono_marshal_get_xappdomain_dispatch (MonoMethod
*method
, int *marshal_types
, int complex_count
, int complex_out_count
, int ret_marshal_type
)
3991 MonoMethodSignature
*sig
, *csig
;
3992 MonoMethodBuilder
*mb
;
3994 int i
, j
, param_index
, copy_locals_base
;
3995 MonoClass
*ret_class
= NULL
;
3996 int loc_array
=0, loc_return
=0, loc_serialized_exc
=0;
3997 MonoExceptionClause
*main_clause
;
3998 MonoMethodHeader
*header
;
4000 gboolean copy_return
;
4002 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_XDOMAIN_DISPATCH
)))
4005 sig
= mono_method_signature (method
);
4006 copy_return
= (sig
->ret
->type
!= MONO_TYPE_VOID
&& ret_marshal_type
!= MONO_MARSHAL_SERIALIZE
);
4009 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3 + sig
->param_count
- complex_count
);
4010 csig
->params
[j
++] = &mono_defaults
.object_class
->byval_arg
;
4011 csig
->params
[j
++] = &byte_array_class
->this_arg
;
4012 csig
->params
[j
++] = &byte_array_class
->this_arg
;
4013 for (i
= 0; i
< sig
->param_count
; i
++) {
4014 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
)
4015 csig
->params
[j
++] = sig
->params
[i
];
4018 csig
->ret
= sig
->ret
;
4020 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
4022 csig
->hasthis
= FALSE
;
4024 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_XDOMAIN_DISPATCH
);
4025 mb
->method
->save_lmf
= 1;
4029 loc_serialized_exc
= mono_mb_add_local (mb
, &byte_array_class
->byval_arg
);
4030 if (complex_count
> 0)
4031 loc_array
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4032 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
4033 loc_return
= mono_mb_add_local (mb
, sig
->ret
);
4034 ret_class
= mono_class_from_mono_type (sig
->ret
);
4039 main_clause
= g_new0 (MonoExceptionClause
, 1);
4040 main_clause
->try_offset
= mb
->pos
;
4042 /* Clean the call context */
4044 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4045 mono_mb_emit_managed_call (mb
, method_set_call_context
, NULL
);
4046 mono_mb_emit_byte (mb
, CEE_POP
);
4048 /* Deserialize call data */
4050 mono_mb_emit_ldarg (mb
, 1);
4051 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4052 mono_mb_emit_byte (mb
, CEE_DUP
);
4053 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
4055 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
4056 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
4058 if (complex_count
> 0)
4059 mono_mb_emit_stloc (mb
, loc_array
);
4061 mono_mb_emit_byte (mb
, CEE_POP
);
4063 mono_mb_patch_addr_s (mb
, pos
, mb
->pos
- (pos
+ 1));
4065 /* Get the target object */
4067 mono_mb_emit_ldarg (mb
, 0);
4068 mono_mb_emit_managed_call (mb
, method_rs_appdomain_target
, NULL
);
4070 /* Load the arguments */
4072 copy_locals_base
= mb
->locals
;
4073 param_index
= 3; // Index of the first non-serialized parameter of this wrapper
4075 for (i
= 0; i
< sig
->param_count
; i
++) {
4076 MonoType
*pt
= sig
->params
[i
];
4077 MonoClass
*pclass
= mono_class_from_mono_type (pt
);
4078 switch (marshal_types
[i
]) {
4079 case MONO_MARSHAL_SERIALIZE
: {
4080 /* take the value from the serialized array */
4081 mono_mb_emit_ldloc (mb
, loc_array
);
4082 mono_mb_emit_icon (mb
, j
++);
4084 if (pclass
->valuetype
) {
4085 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4086 mono_mb_emit_op (mb
, CEE_UNBOX
, pclass
);
4088 mono_mb_emit_op (mb
, CEE_LDELEMA
, pclass
);
4091 if (pclass
->valuetype
) {
4092 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4093 mono_mb_emit_op (mb
, CEE_UNBOX
, pclass
);
4094 mono_mb_emit_op (mb
, CEE_LDOBJ
, pclass
);
4096 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4097 if (pclass
!= mono_defaults
.object_class
) {
4098 mono_mb_emit_op (mb
, CEE_CASTCLASS
, pclass
);
4104 case MONO_MARSHAL_COPY_OUT
: {
4105 /* Keep a local copy of the value since we need to copy it back after the call */
4106 int copy_local
= mono_mb_add_local (mb
, &(pclass
->byval_arg
));
4107 mono_mb_emit_ldarg (mb
, param_index
++);
4108 mono_marshal_emit_xdomain_copy_value (mb
, pclass
);
4109 mono_mb_emit_byte (mb
, CEE_DUP
);
4110 mono_mb_emit_stloc (mb
, copy_local
);
4113 case MONO_MARSHAL_COPY
: {
4114 mono_mb_emit_ldarg (mb
, param_index
);
4116 mono_mb_emit_byte (mb
, CEE_DUP
);
4117 mono_mb_emit_byte (mb
, CEE_DUP
);
4118 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4119 mono_marshal_emit_xdomain_copy_value (mb
, pclass
);
4120 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4122 mono_marshal_emit_xdomain_copy_value (mb
, pclass
);
4127 case MONO_MARSHAL_NONE
:
4128 mono_mb_emit_ldarg (mb
, param_index
++);
4133 /* Make the call to the real object */
4135 emit_thread_force_interrupt_checkpoint (mb
);
4137 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4139 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
4140 mono_mb_emit_stloc (mb
, loc_return
);
4142 /* copy back MONO_MARSHAL_COPY_OUT parameters */
4146 for (i
= 0; i
< sig
->param_count
; i
++) {
4147 if (marshal_types
[i
] == MONO_MARSHAL_SERIALIZE
) continue;
4148 if (marshal_types
[i
] == MONO_MARSHAL_COPY_OUT
) {
4149 mono_mb_emit_ldloc (mb
, copy_locals_base
+ (j
++));
4150 mono_mb_emit_ldarg (mb
, param_index
);
4151 mono_marshal_emit_xdomain_copy_out_value (mb
, mono_class_from_mono_type (sig
->params
[i
]));
4156 /* Serialize the return values */
4158 if (complex_out_count
> 0) {
4159 /* Reset parameters in the array that don't need to be serialized back */
4161 for (i
= 0; i
< sig
->param_count
; i
++) {
4162 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
) continue;
4163 if (!sig
->params
[i
]->byref
) {
4164 mono_mb_emit_ldloc (mb
, loc_array
);
4165 mono_mb_emit_icon (mb
, j
);
4166 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4167 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
4172 /* Add the return value to the array */
4174 if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
4175 mono_mb_emit_ldloc (mb
, loc_array
);
4176 mono_mb_emit_icon (mb
, complex_count
); /* The array has an additional slot to hold the ret value */
4177 mono_mb_emit_ldloc (mb
, loc_return
);
4178 if (ret_class
->valuetype
) {
4179 mono_mb_emit_op (mb
, CEE_BOX
, ret_class
);
4181 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
4186 mono_mb_emit_ldarg (mb
, 1);
4187 mono_mb_emit_ldloc (mb
, loc_array
);
4188 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
4189 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4190 } else if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
4191 mono_mb_emit_ldarg (mb
, 1);
4192 mono_mb_emit_ldloc (mb
, loc_return
);
4193 if (ret_class
->valuetype
) {
4194 mono_mb_emit_op (mb
, CEE_BOX
, ret_class
);
4196 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
4197 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4199 mono_mb_emit_ldarg (mb
, 1);
4200 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4201 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
4202 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4205 mono_mb_emit_ldarg (mb
, 2);
4206 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4207 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4208 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4210 /* Main exception catch */
4211 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4212 main_clause
->try_len
= mb
->pos
- main_clause
->try_offset
;
4213 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
4216 main_clause
->handler_offset
= mb
->pos
;
4217 mono_mb_emit_managed_call (mb
, method_rs_serialize_exc
, NULL
);
4218 mono_mb_emit_stloc (mb
, loc_serialized_exc
);
4219 mono_mb_emit_ldarg (mb
, 2);
4220 mono_mb_emit_ldloc (mb
, loc_serialized_exc
);
4221 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4222 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4223 main_clause
->handler_len
= mb
->pos
- main_clause
->handler_offset
;
4226 mono_mb_patch_addr (mb
, pos_leave
, mb
->pos
- (pos_leave
+ 4));
4229 mono_mb_emit_ldloc (mb
, loc_return
);
4231 mono_mb_emit_byte (mb
, CEE_RET
);
4233 res
= mono_remoting_mb_create_and_cache (method
, mb
, csig
, csig
->param_count
+ 16);
4236 header
= ((MonoMethodNormal
*)res
)->header
;
4237 header
->num_clauses
= 1;
4238 header
->clauses
= main_clause
;
4243 /* mono_marshal_get_xappdomain_invoke ()
4244 * Generates a fast remoting wrapper for cross app domain calls.
4247 mono_marshal_get_xappdomain_invoke (MonoMethod
*method
)
4249 MonoMethodSignature
*sig
;
4250 MonoMethodBuilder
*mb
;
4252 int i
, j
, complex_count
, complex_out_count
, copy_locals_base
;
4254 MonoClass
*ret_class
= NULL
;
4255 MonoMethod
*xdomain_method
;
4256 int ret_marshal_type
= MONO_MARSHAL_NONE
;
4257 int loc_array
=0, loc_serialized_data
=-1, loc_real_proxy
;
4258 int loc_old_domainid
, loc_domainid
, loc_return
=0, loc_serialized_exc
=0, loc_context
;
4259 int pos
, pos_dispatch
, pos_noex
;
4260 gboolean copy_return
= FALSE
;
4264 if (method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE
|| method
->wrapper_type
== MONO_WRAPPER_XDOMAIN_INVOKE
)
4267 /* we cant remote methods without this pointer */
4268 if (!mono_method_signature (method
)->hasthis
)
4271 if (!mono_marshal_supports_fast_xdomain (method
))
4272 return mono_marshal_get_remoting_invoke (method
);
4274 mono_remoting_marshal_init ();
4276 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_XDOMAIN_INVOKE
)))
4279 sig
= signature_no_pinvoke (method
);
4281 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_XDOMAIN_INVOKE
);
4282 mb
->method
->save_lmf
= 1;
4284 /* Count the number of parameters that need to be serialized */
4286 marshal_types
= alloca (sizeof (int) * sig
->param_count
);
4287 complex_count
= complex_out_count
= 0;
4288 for (i
= 0; i
< sig
->param_count
; i
++) {
4289 MonoType
*ptype
= sig
->params
[i
];
4290 int mt
= mono_get_xdomain_marshal_type (ptype
);
4292 /* If the [Out] attribute is applied to a parameter that can be internally copied,
4293 * the copy will be made by reusing the original object instance
4295 if ((ptype
->attrs
& PARAM_ATTRIBUTE_OUT
) != 0 && mt
== MONO_MARSHAL_COPY
&& !ptype
->byref
)
4296 mt
= MONO_MARSHAL_COPY_OUT
;
4297 else if (mt
== MONO_MARSHAL_SERIALIZE
) {
4299 if (ptype
->byref
) complex_out_count
++;
4301 marshal_types
[i
] = mt
;
4304 if (sig
->ret
->type
!= MONO_TYPE_VOID
) {
4305 ret_marshal_type
= mono_get_xdomain_marshal_type (sig
->ret
);
4306 ret_class
= mono_class_from_mono_type (sig
->ret
);
4307 copy_return
= ret_marshal_type
!= MONO_MARSHAL_SERIALIZE
;
4312 if (complex_count
> 0)
4313 loc_array
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4314 loc_serialized_data
= mono_mb_add_local (mb
, &byte_array_class
->byval_arg
);
4315 loc_real_proxy
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4317 loc_return
= mono_mb_add_local (mb
, sig
->ret
);
4318 loc_old_domainid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
4319 loc_domainid
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
4320 loc_serialized_exc
= mono_mb_add_local (mb
, &byte_array_class
->byval_arg
);
4321 loc_context
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4323 /* Save thread domain data */
4325 mono_mb_emit_icall (mb
, mono_context_get
);
4326 mono_mb_emit_byte (mb
, CEE_DUP
);
4327 mono_mb_emit_stloc (mb
, loc_context
);
4329 /* If the thread is not running in the default context, it needs to go
4330 * through the whole remoting sink, since the context is going to change
4332 mono_mb_emit_managed_call (mb
, method_needs_context_sink
, NULL
);
4333 pos
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
4335 /* Another case in which the fast path can't be used: when the target domain
4336 * has a different image for the same assembly.
4339 /* Get the target domain id */
4341 mono_mb_emit_ldarg (mb
, 0);
4342 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
4343 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4344 mono_mb_emit_byte (mb
, CEE_DUP
);
4345 mono_mb_emit_stloc (mb
, loc_real_proxy
);
4347 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoRealProxy
, target_domain_id
));
4348 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
4349 mono_mb_emit_stloc (mb
, loc_domainid
);
4351 /* Check if the target domain has the same image for the required assembly */
4353 mono_mb_emit_ldloc (mb
, loc_domainid
);
4354 mono_mb_emit_ptr (mb
, method
->klass
->image
);
4355 mono_mb_emit_icall (mb
, mono_marshal_check_domain_image
);
4356 pos_dispatch
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
4358 /* Use the whole remoting sink to dispatch this message */
4360 mono_mb_patch_short_branch (mb
, pos
);
4362 mono_mb_emit_ldarg (mb
, 0);
4363 for (i
= 0; i
< sig
->param_count
; i
++)
4364 mono_mb_emit_ldarg (mb
, i
+ 1);
4366 mono_mb_emit_managed_call (mb
, mono_marshal_get_remoting_invoke (method
), NULL
);
4367 mono_mb_emit_byte (mb
, CEE_RET
);
4368 mono_mb_patch_short_branch (mb
, pos_dispatch
);
4370 /* Create the array that will hold the parameters to be serialized */
4372 if (complex_count
> 0) {
4373 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 */
4374 mono_mb_emit_op (mb
, CEE_NEWARR
, mono_defaults
.object_class
);
4377 for (i
= 0; i
< sig
->param_count
; i
++) {
4379 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
) continue;
4380 pclass
= mono_class_from_mono_type (sig
->params
[i
]);
4381 mono_mb_emit_byte (mb
, CEE_DUP
);
4382 mono_mb_emit_icon (mb
, j
);
4383 mono_mb_emit_ldarg (mb
, i
+ 1); /* 0=this */
4384 if (sig
->params
[i
]->byref
) {
4385 if (pclass
->valuetype
)
4386 mono_mb_emit_op (mb
, CEE_LDOBJ
, pclass
);
4388 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4390 if (pclass
->valuetype
)
4391 mono_mb_emit_op (mb
, CEE_BOX
, pclass
);
4392 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
4395 mono_mb_emit_stloc (mb
, loc_array
);
4397 /* Serialize parameters */
4399 mono_mb_emit_ldloc (mb
, loc_array
);
4400 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
4401 mono_mb_emit_stloc (mb
, loc_serialized_data
);
4403 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4404 mono_mb_emit_managed_call (mb
, method_rs_serialize
, NULL
);
4405 mono_mb_emit_stloc (mb
, loc_serialized_data
);
4410 mono_mb_emit_ldloc (mb
, loc_domainid
);
4411 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
4412 mono_marshal_emit_switch_domain (mb
);
4413 mono_mb_emit_stloc (mb
, loc_old_domainid
);
4415 /* Load the arguments */
4417 mono_mb_emit_ldloc (mb
, loc_real_proxy
);
4418 mono_mb_emit_ldloc_addr (mb
, loc_serialized_data
);
4419 mono_mb_emit_ldloc_addr (mb
, loc_serialized_exc
);
4421 copy_locals_base
= mb
->locals
;
4422 for (i
= 0; i
< sig
->param_count
; i
++) {
4423 switch (marshal_types
[i
]) {
4424 case MONO_MARSHAL_SERIALIZE
:
4426 case MONO_MARSHAL_COPY
: {
4427 mono_mb_emit_ldarg (mb
, i
+1);
4428 if (sig
->params
[i
]->byref
) {
4429 /* make a local copy of the byref parameter. The real parameter
4430 * will be updated after the xdomain call
4432 MonoClass
*pclass
= mono_class_from_mono_type (sig
->params
[i
]);
4433 int copy_local
= mono_mb_add_local (mb
, &(pclass
->byval_arg
));
4434 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4435 mono_mb_emit_stloc (mb
, copy_local
);
4436 mono_mb_emit_ldloc_addr (mb
, copy_local
);
4440 case MONO_MARSHAL_COPY_OUT
:
4441 case MONO_MARSHAL_NONE
:
4442 mono_mb_emit_ldarg (mb
, i
+1);
4447 /* Make the call to the invoke wrapper in the target domain */
4449 xdomain_method
= mono_marshal_get_xappdomain_dispatch (method
, marshal_types
, complex_count
, complex_out_count
, ret_marshal_type
);
4450 mono_marshal_emit_load_domain_method (mb
, xdomain_method
);
4451 mono_mb_emit_calli (mb
, mono_method_signature (xdomain_method
));
4454 mono_mb_emit_stloc (mb
, loc_return
);
4458 mono_mb_emit_ldloc (mb
, loc_old_domainid
);
4459 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
4460 mono_marshal_emit_switch_domain (mb
);
4461 mono_mb_emit_byte (mb
, CEE_POP
);
4463 /* Restore thread domain data */
4465 mono_mb_emit_ldloc (mb
, loc_context
);
4466 mono_mb_emit_icall (mb
, mono_context_set
);
4468 /* if (loc_serialized_exc != null) ... */
4470 mono_mb_emit_ldloc (mb
, loc_serialized_exc
);
4471 pos_noex
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
4473 mono_mb_emit_ldloc (mb
, loc_serialized_exc
);
4474 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
4475 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
4476 mono_mb_emit_op (mb
, CEE_CASTCLASS
, mono_defaults
.exception_class
);
4477 mono_mb_emit_managed_call (mb
, method_exc_fixexc
, NULL
);
4478 mono_mb_emit_byte (mb
, CEE_THROW
);
4479 mono_mb_patch_addr_s (mb
, pos_noex
, mb
->pos
- pos_noex
- 1);
4481 /* copy back non-serialized output parameters */
4484 for (i
= 0; i
< sig
->param_count
; i
++) {
4485 if (!sig
->params
[i
]->byref
|| marshal_types
[i
] != MONO_MARSHAL_COPY
) continue;
4486 mono_mb_emit_ldarg (mb
, i
+ 1);
4487 mono_mb_emit_ldloc (mb
, copy_locals_base
+ (j
++));
4488 mono_marshal_emit_xdomain_copy_value (mb
, mono_class_from_mono_type (sig
->params
[i
]));
4489 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4492 /* Deserialize out parameters */
4494 if (complex_out_count
> 0) {
4495 mono_mb_emit_ldloc (mb
, loc_serialized_data
);
4496 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
4497 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
4498 mono_mb_emit_stloc (mb
, loc_array
);
4500 /* Copy back output parameters and return type */
4503 for (i
= 0; i
< sig
->param_count
; i
++) {
4504 if (marshal_types
[i
] != MONO_MARSHAL_SERIALIZE
) continue;
4505 if (sig
->params
[i
]->byref
) {
4506 MonoClass
*pclass
= mono_class_from_mono_type (sig
->params
[i
]);
4507 mono_mb_emit_ldarg (mb
, i
+ 1);
4508 mono_mb_emit_ldloc (mb
, loc_array
);
4509 mono_mb_emit_icon (mb
, j
);
4510 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4511 if (pclass
->valuetype
) {
4512 mono_mb_emit_op (mb
, CEE_UNBOX
, pclass
);
4513 mono_mb_emit_op (mb
, CEE_LDOBJ
, pclass
);
4514 mono_mb_emit_op (mb
, CEE_STOBJ
, pclass
);
4516 if (pclass
!= mono_defaults
.object_class
)
4517 mono_mb_emit_op (mb
, CEE_CASTCLASS
, pclass
);
4518 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4524 if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
4525 mono_mb_emit_ldloc (mb
, loc_array
);
4526 mono_mb_emit_icon (mb
, complex_count
);
4527 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4528 if (ret_class
->valuetype
) {
4529 mono_mb_emit_op (mb
, CEE_UNBOX
, ret_class
);
4530 mono_mb_emit_op (mb
, CEE_LDOBJ
, ret_class
);
4533 } else if (ret_marshal_type
== MONO_MARSHAL_SERIALIZE
) {
4534 mono_mb_emit_ldloc (mb
, loc_serialized_data
);
4535 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
4536 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
4537 if (ret_class
->valuetype
) {
4538 mono_mb_emit_op (mb
, CEE_UNBOX
, ret_class
);
4539 mono_mb_emit_op (mb
, CEE_LDOBJ
, ret_class
);
4540 } else if (ret_class
!= mono_defaults
.object_class
) {
4541 mono_mb_emit_op (mb
, CEE_CASTCLASS
, ret_class
);
4544 mono_mb_emit_ldloc (mb
, loc_serialized_data
);
4545 mono_mb_emit_byte (mb
, CEE_DUP
);
4546 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
4547 mono_marshal_emit_xdomain_copy_value (mb
, byte_array_class
);
4549 mono_mb_patch_addr_s (mb
, pos
, mb
->pos
- (pos
+ 1));
4550 mono_mb_emit_managed_call (mb
, method_rs_deserialize
, NULL
);
4551 mono_mb_emit_byte (mb
, CEE_POP
);
4555 mono_mb_emit_ldloc (mb
, loc_return
);
4556 if (ret_marshal_type
== MONO_MARSHAL_COPY
)
4557 mono_marshal_emit_xdomain_copy_value (mb
, ret_class
);
4560 mono_mb_emit_byte (mb
, CEE_RET
);
4562 res
= mono_remoting_mb_create_and_cache (method
, mb
, sig
, sig
->param_count
+ 16);
4569 mono_marshal_get_remoting_invoke_for_target (MonoMethod
*method
, MonoRemotingTarget target_type
)
4571 if (target_type
== MONO_REMOTING_TARGET_APPDOMAIN
)
4572 return mono_marshal_get_xappdomain_invoke (method
);
4573 else if (target_type
== MONO_REMOTING_TARGET_COMINTEROP
)
4574 return cominterop_get_invoke (method
);
4576 return mono_marshal_get_remoting_invoke (method
);
4579 G_GNUC_UNUSED
static gpointer
4580 mono_marshal_load_remoting_wrapper (MonoRealProxy
*rp
, MonoMethod
*method
)
4582 if (rp
->target_domain_id
!= -1)
4583 return mono_compile_method (mono_marshal_get_xappdomain_invoke (method
));
4585 return mono_compile_method (mono_marshal_get_remoting_invoke (method
));
4589 mono_marshal_get_remoting_invoke_with_check (MonoMethod
*method
)
4591 MonoMethodSignature
*sig
;
4592 MonoMethodBuilder
*mb
;
4593 MonoMethod
*res
, *native
;
4594 int i
, pos
, pos_rem
;
4598 if (method
->wrapper_type
== MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)
4601 /* we cant remote methods without this pointer */
4602 g_assert (mono_method_signature (method
)->hasthis
);
4604 if ((res
= mono_marshal_remoting_find_in_cache (method
, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
)))
4607 sig
= signature_no_pinvoke (method
);
4609 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK
);
4611 for (i
= 0; i
<= sig
->param_count
; i
++)
4612 mono_mb_emit_ldarg (mb
, i
);
4614 mono_mb_emit_ldarg (mb
, 0);
4615 pos
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
4617 if (mono_marshal_supports_fast_xdomain (method
)) {
4618 mono_mb_emit_ldarg (mb
, 0);
4619 pos_rem
= mono_mb_emit_xdomain_check (mb
, CEE_BEQ
);
4621 /* wrapper for cross app domain calls */
4622 native
= mono_marshal_get_xappdomain_invoke (method
);
4623 mono_mb_emit_managed_call (mb
, native
, mono_method_signature (native
));
4624 mono_mb_emit_byte (mb
, CEE_RET
);
4626 mono_mb_patch_addr (mb
, pos_rem
, mb
->pos
- (pos_rem
+ 4));
4628 /* wrapper for normal remote calls */
4629 native
= mono_marshal_get_remoting_invoke (method
);
4630 mono_mb_emit_managed_call (mb
, native
, mono_method_signature (native
));
4631 mono_mb_emit_byte (mb
, CEE_RET
);
4634 mono_mb_patch_branch (mb
, pos
);
4635 mono_mb_emit_managed_call (mb
, method
, mono_method_signature (method
));
4636 mono_mb_emit_byte (mb
, CEE_RET
);
4638 res
= mono_remoting_mb_create_and_cache (method
, mb
, sig
, sig
->param_count
+ 16);
4645 * the returned method invokes all methods in a multicast delegate
4648 mono_marshal_get_delegate_invoke (MonoMethod
*method
)
4650 MonoMethodSignature
*sig
, *static_sig
;
4652 MonoMethodBuilder
*mb
;
4658 g_assert (method
&& method
->klass
->parent
== mono_defaults
.multicastdelegate_class
&&
4659 !strcmp (method
->name
, "Invoke"));
4661 sig
= signature_no_pinvoke (method
);
4663 cache
= method
->klass
->image
->delegate_invoke_cache
;
4664 if ((res
= mono_marshal_find_in_cache (cache
, sig
)))
4667 static_sig
= signature_dup (method
->klass
->image
, sig
);
4668 static_sig
->hasthis
= 0;
4670 name
= mono_signature_to_name (sig
, "invoke");
4671 mb
= mono_mb_new (mono_defaults
.multicastdelegate_class
, name
, MONO_WRAPPER_DELEGATE_INVOKE
);
4674 /* allocate local 0 (object) */
4675 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4677 g_assert (sig
->hasthis
);
4681 * prev.Invoke( args .. );
4682 * return this.<target>( args .. );
4685 /* this wrapper can be used in unmanaged-managed transitions */
4686 emit_thread_interrupt_checkpoint (mb
);
4688 /* get this->prev */
4689 mono_mb_emit_ldarg (mb
, 0);
4690 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoMulticastDelegate
, prev
));
4691 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4693 /* if prev != null */
4694 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4698 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4699 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
4701 mono_mb_emit_ldarg (mb
, 0);
4702 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoMulticastDelegate
, prev
));
4703 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4704 for (i
= 0; i
< sig
->param_count
; i
++)
4705 mono_mb_emit_ldarg (mb
, i
+ 1);
4706 mono_mb_emit_managed_call (mb
, method
, mono_method_signature (method
));
4707 if (sig
->ret
->type
!= MONO_TYPE_VOID
)
4708 mono_mb_emit_byte (mb
, CEE_POP
);
4710 /* continued or prev == null */
4711 mono_mb_patch_branch (mb
, pos0
);
4713 /* get this->target */
4714 mono_mb_emit_ldarg (mb
, 0);
4715 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoDelegate
, target
));
4716 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4717 mono_mb_emit_stloc (mb
, 0);
4719 /* if target != null */
4720 mono_mb_emit_ldloc (mb
, 0);
4721 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4723 /* then call this->method_ptr nonstatic */
4724 mono_mb_emit_ldloc (mb
, 0);
4725 for (i
= 0; i
< sig
->param_count
; ++i
)
4726 mono_mb_emit_ldarg (mb
, i
+ 1);
4727 mono_mb_emit_ldarg (mb
, 0);
4728 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
4729 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4730 mono_mb_emit_op (mb
, CEE_CALLI
, sig
);
4732 mono_mb_emit_byte (mb
, CEE_RET
);
4734 /* else [target == null] call this->method_ptr static */
4735 mono_mb_patch_branch (mb
, pos0
);
4737 for (i
= 0; i
< sig
->param_count
; ++i
)
4738 mono_mb_emit_ldarg (mb
, i
+ 1);
4739 mono_mb_emit_ldarg (mb
, 0);
4740 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoDelegate
, method_ptr
));
4741 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4742 mono_mb_emit_op (mb
, CEE_CALLI
, static_sig
);
4744 mono_mb_emit_byte (mb
, CEE_RET
);
4746 res
= mono_mb_create_and_cache (cache
, sig
,
4747 mb
, sig
, sig
->param_count
+ 16);
4754 * signature_dup_add_this:
4756 * Make a copy of @sig, adding an explicit this argument.
4758 static MonoMethodSignature
*
4759 signature_dup_add_this (MonoMethodSignature
*sig
, MonoClass
*klass
)
4761 MonoMethodSignature
*res
;
4764 res
= mono_metadata_signature_alloc (klass
->image
, sig
->param_count
+ 1);
4765 memcpy (res
, sig
, sizeof (MonoMethodSignature
));
4766 res
->param_count
= sig
->param_count
+ 1;
4767 res
->hasthis
= FALSE
;
4768 for (i
= sig
->param_count
- 1; i
>= 0; i
--)
4769 res
->params
[i
+ 1] = sig
->params
[i
];
4770 res
->params
[0] = &mono_ptr_class_get (&klass
->byval_arg
)->byval_arg
;
4776 MonoMethodSignature
*ctor_sig
;
4777 MonoMethodSignature
*sig
;
4780 /* protected by the marshal lock, contains CtorSigPair pointers */
4781 static GSList
*strsig_list
= NULL
;
4783 static MonoMethodSignature
*
4784 lookup_string_ctor_signature (MonoMethodSignature
*sig
)
4786 MonoMethodSignature
*callsig
;
4790 mono_marshal_lock ();
4792 for (item
= strsig_list
; item
; item
= item
->next
) {
4794 /* mono_metadata_signature_equal () is safe to call with the marshal lock
4795 * because it is lock-free.
4797 if (mono_metadata_signature_equal (sig
, cs
->ctor_sig
)) {
4802 mono_marshal_unlock ();
4806 static MonoMethodSignature
*
4807 add_string_ctor_signature (MonoMethod
*method
)
4809 MonoMethodSignature
*callsig
;
4812 callsig
= signature_dup (method
->klass
->image
, mono_method_signature (method
));
4813 callsig
->ret
= &mono_defaults
.string_class
->byval_arg
;
4814 cs
= g_new (CtorSigPair
, 1);
4816 cs
->ctor_sig
= mono_method_signature (method
);
4818 mono_marshal_lock ();
4819 strsig_list
= g_slist_prepend (strsig_list
, cs
);
4820 mono_marshal_unlock ();
4825 * generates IL code for the runtime invoke function
4826 * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
4828 * we also catch exceptions if exc != null
4831 mono_marshal_get_runtime_invoke (MonoMethod
*method
)
4833 MonoMethodSignature
*sig
, *csig
, *callsig
;
4834 MonoExceptionClause
*clause
;
4835 MonoMethodHeader
*header
;
4836 MonoMethodBuilder
*mb
;
4837 GHashTable
*cache
= NULL
;
4838 MonoClass
*target_klass
;
4839 MonoMethod
*res
= NULL
;
4840 static MonoString
*string_dummy
= NULL
;
4841 static MonoMethodSignature
*dealy_abort_sig
= NULL
;
4847 if (method
->string_ctor
) {
4848 callsig
= lookup_string_ctor_signature (mono_method_signature (method
));
4850 callsig
= add_string_ctor_signature (method
);
4852 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
) {
4854 * Valuetype methods receive a managed pointer as the this argument.
4855 * Create a new signature to reflect this.
4857 callsig
= signature_dup_add_this (mono_method_signature (method
), method
->klass
);
4859 callsig
= mono_method_signature (method
);
4863 /* See bug #80743 */
4864 target_klass
= method
->klass
;
4866 target_klass
= mono_defaults
.object_class
;
4868 * if types in the signature belong to non-mscorlib, we cache only
4869 * in the method image
4871 if (mono_class_from_mono_type (callsig
->ret
)->image
!= mono_defaults
.corlib
) {
4872 target_klass
= method
->klass
;
4874 for (i
= 0; i
< callsig
->param_count
; i
++) {
4875 if (mono_class_from_mono_type (callsig
->params
[i
])->image
!= mono_defaults
.corlib
) {
4876 target_klass
= method
->klass
;
4882 cache
= target_klass
->image
->runtime_invoke_cache
;
4884 /* from mono_marshal_find_in_cache */
4885 mono_marshal_lock ();
4886 res
= g_hash_table_lookup (cache
, callsig
);
4887 mono_marshal_unlock ();
4893 if (!dealy_abort_sig
) {
4894 dealy_abort_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
4895 dealy_abort_sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
4896 dealy_abort_sig
->pinvoke
= 0;
4899 /* to make it work with our special string constructors */
4900 if (!string_dummy
) {
4901 MONO_GC_REGISTER_ROOT (string_dummy
);
4902 string_dummy
= mono_string_new_wrapper ("dummy");
4905 sig
= mono_method_signature (method
);
4907 csig
= mono_metadata_signature_alloc (target_klass
->image
, 4);
4909 csig
->ret
= &mono_defaults
.object_class
->byval_arg
;
4910 if (method
->klass
->valuetype
&& mono_method_signature (method
)->hasthis
)
4911 csig
->params
[0] = callsig
->params
[0];
4913 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
4914 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
4915 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
4916 csig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
4918 name
= mono_signature_to_name (callsig
, "runtime_invoke");
4919 mb
= mono_mb_new (target_klass
, name
, MONO_WRAPPER_RUNTIME_INVOKE
);
4922 /* allocate local 0 (object) tmp */
4923 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4924 /* allocate local 1 (object) exc */
4925 mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
4927 /* cond set *exc to null */
4928 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4929 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
4930 mono_mb_emit_byte (mb
, 3);
4931 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
4932 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4933 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4935 emit_thread_force_interrupt_checkpoint (mb
);
4938 if (method
->string_ctor
) {
4939 mono_mb_emit_ptr (mb
, string_dummy
);
4941 mono_mb_emit_ldarg (mb
, 0);
4945 for (i
= 0; i
< sig
->param_count
; i
++) {
4946 MonoType
*t
= sig
->params
[i
];
4949 mono_mb_emit_ldarg (mb
, 1);
4951 mono_mb_emit_icon (mb
, sizeof (gpointer
) * i
);
4952 mono_mb_emit_byte (mb
, CEE_ADD
);
4954 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4959 type
= sig
->params
[i
]->type
;
4963 case MONO_TYPE_BOOLEAN
:
4967 case MONO_TYPE_CHAR
:
4976 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
4978 case MONO_TYPE_STRING
:
4979 case MONO_TYPE_CLASS
:
4980 case MONO_TYPE_ARRAY
:
4982 case MONO_TYPE_SZARRAY
:
4983 case MONO_TYPE_OBJECT
:
4986 case MONO_TYPE_GENERICINST
:
4987 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
4993 case MONO_TYPE_VALUETYPE
:
4994 if (type
== MONO_TYPE_VALUETYPE
&& t
->data
.klass
->enumtype
) {
4995 type
= t
->data
.klass
->enum_basetype
->type
;
4998 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->params
[i
]))) {
4999 /* Need to convert a boxed vtype to an mp to a Nullable struct */
5000 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type (sig
->params
[i
]));
5001 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
5003 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type (sig
->params
[i
]));
5007 g_assert_not_reached ();
5011 mono_mb_emit_ldarg (mb
, 3);
5012 mono_mb_emit_calli (mb
, callsig
);
5014 if (sig
->ret
->byref
) {
5016 g_assert_not_reached ();
5020 switch (sig
->ret
->type
) {
5021 case MONO_TYPE_VOID
:
5022 if (!method
->string_ctor
)
5023 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5025 case MONO_TYPE_BOOLEAN
:
5026 case MONO_TYPE_CHAR
:
5039 case MONO_TYPE_VALUETYPE
:
5040 case MONO_TYPE_TYPEDBYREF
:
5041 case MONO_TYPE_GENERICINST
:
5042 /* box value types */
5043 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (sig
->ret
));
5045 case MONO_TYPE_STRING
:
5046 case MONO_TYPE_CLASS
:
5047 case MONO_TYPE_ARRAY
:
5048 case MONO_TYPE_SZARRAY
:
5049 case MONO_TYPE_OBJECT
:
5054 g_assert_not_reached ();
5057 mono_mb_emit_stloc (mb
, 0);
5059 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
5061 mono_loader_lock ();
5062 clause
= mono_mempool_alloc0 (target_klass
->image
->mempool
, sizeof (MonoExceptionClause
));
5063 mono_loader_unlock ();
5064 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
5065 clause
->try_len
= mb
->pos
;
5068 clause
->data
.filter_offset
= mb
->pos
;
5070 mono_mb_emit_byte (mb
, CEE_POP
);
5071 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
5072 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5073 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5074 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
5075 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5076 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
5078 clause
->handler_offset
= mb
->pos
;
5081 /* store exception */
5082 mono_mb_emit_stloc (mb
, 1);
5084 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
5085 mono_mb_emit_ldloc (mb
, 1);
5086 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5088 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5089 mono_mb_emit_stloc (mb
, 0);
5091 /* Check for the abort exception */
5092 mono_mb_emit_ldloc (mb
, 1);
5093 mono_mb_emit_op (mb
, CEE_ISINST
, mono_defaults
.threadabortexception_class
);
5094 posna
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
5096 /* Delay the abort exception */
5097 mono_mb_emit_native_call (mb
, dealy_abort_sig
, ves_icall_System_Threading_Thread_ResetAbort
);
5099 mono_mb_patch_short_branch (mb
, posna
);
5100 mono_mb_emit_branch (mb
, CEE_LEAVE
);
5102 clause
->handler_len
= mb
->pos
- clause
->handler_offset
;
5105 mono_mb_patch_branch (mb
, pos
);
5106 mono_mb_emit_ldloc (mb
, 0);
5107 mono_mb_emit_byte (mb
, CEE_RET
);
5109 /* taken from mono_mb_create_and_cache */
5110 mono_marshal_lock ();
5111 res
= g_hash_table_lookup (cache
, callsig
);
5112 mono_marshal_unlock ();
5114 /* Somebody may have created it before us */
5117 newm
= mono_mb_create_method (mb
, csig
, sig
->param_count
+ 16);
5119 mono_marshal_lock ();
5120 res
= g_hash_table_lookup (cache
, callsig
);
5123 g_hash_table_insert (cache
, callsig
, res
);
5124 g_hash_table_insert (wrapper_hash
, res
, callsig
);
5126 mono_free_method (newm
);
5128 mono_marshal_unlock ();
5131 /* end mono_mb_create_and_cache */
5135 header
= ((MonoMethodNormal
*)res
)->header
;
5136 header
->num_clauses
= 1;
5137 header
->clauses
= clause
;
5143 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
5145 char *msg
= g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
5146 klass
->name_space
, klass
->name
);
5148 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5152 * mono_marshal_get_ldfld_remote_wrapper:
5153 * @klass: The return type
5155 * This method generates a wrapper for calling mono_load_remote_field_new with
5156 * the appropriate return type.
5159 mono_marshal_get_ldfld_remote_wrapper (MonoClass
*klass
)
5161 MonoMethodSignature
*sig
, *csig
;
5162 MonoMethodBuilder
*mb
;
5167 cache
= klass
->image
->ldfld_remote_wrapper_cache
;
5168 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
5172 * This wrapper is similar to an icall wrapper but all the wrappers
5173 * call the same C function, but with a different signature.
5175 name
= g_strdup_printf ("__mono_load_remote_field_new_wrapper_%s.%s", klass
->name_space
, klass
->name
);
5176 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_LDFLD_REMOTE
);
5179 mb
->method
->save_lmf
= 1;
5181 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
5182 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5183 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5184 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5185 sig
->ret
= &klass
->this_arg
;
5187 mono_mb_emit_ldarg (mb
, 0);
5188 mono_mb_emit_ldarg (mb
, 1);
5189 mono_mb_emit_ldarg (mb
, 2);
5191 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
5192 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5193 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5194 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5195 csig
->ret
= &klass
->this_arg
;
5198 mono_mb_emit_native_call (mb
, csig
, mono_load_remote_field_new
);
5199 emit_thread_interrupt_checkpoint (mb
);
5201 mono_mb_emit_byte (mb
, CEE_RET
);
5203 res
= mono_mb_create_and_cache (cache
, klass
,
5204 mb
, sig
, sig
->param_count
+ 16);
5211 * mono_marshal_get_ldfld_wrapper:
5212 * @type: the type of the field
5214 * This method generates a function which can be use to load a field with type
5215 * @type from an object. The generated function has the following signature:
5216 * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
5219 mono_marshal_get_ldfld_wrapper (MonoType
*type
)
5221 MonoMethodSignature
*sig
;
5222 MonoMethodBuilder
*mb
;
5227 int t
, pos0
, pos1
= 0;
5229 type
= mono_type_get_underlying_type (type
);
5234 if (type
->type
== MONO_TYPE_SZARRAY
) {
5235 klass
= mono_defaults
.array_class
;
5236 } else if (type
->type
== MONO_TYPE_VALUETYPE
) {
5237 klass
= type
->data
.klass
;
5238 } else if (t
== MONO_TYPE_OBJECT
|| t
== MONO_TYPE_CLASS
|| t
== MONO_TYPE_STRING
) {
5239 klass
= mono_defaults
.object_class
;
5240 } else if (t
== MONO_TYPE_PTR
|| t
== MONO_TYPE_FNPTR
) {
5241 klass
= mono_defaults
.int_class
;
5242 } else if (t
== MONO_TYPE_GENERICINST
) {
5243 if (mono_type_generic_inst_is_valuetype (type
))
5244 klass
= mono_class_from_mono_type (type
);
5246 klass
= mono_defaults
.object_class
;
5248 klass
= mono_class_from_mono_type (type
);
5251 klass
= mono_defaults
.int_class
;
5254 cache
= klass
->image
->ldfld_wrapper_cache
;
5255 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
5258 /* we add the %p pointer value of klass because class names are not unique */
5259 name
= g_strdup_printf ("__ldfld_wrapper_%p_%s.%s", klass
, klass
->name_space
, klass
->name
);
5260 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_LDFLD
);
5263 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
5264 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5265 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5266 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5267 sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
5268 sig
->ret
= &klass
->byval_arg
;
5270 mono_mb_emit_ldarg (mb
, 0);
5271 pos0
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
5273 mono_mb_emit_ldarg (mb
, 0);
5274 mono_mb_emit_ldarg (mb
, 1);
5275 mono_mb_emit_ldarg (mb
, 2);
5277 mono_mb_emit_managed_call (mb
, mono_marshal_get_ldfld_remote_wrapper (klass
), NULL
);
5280 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
5281 csig->params [0] = &mono_defaults.object_class->byval_arg;
5282 csig->params [1] = &mono_defaults.int_class->byval_arg;
5283 csig->params [2] = &mono_defaults.int_class->byval_arg;
5284 csig->ret = &klass->this_arg;
5287 mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
5288 emit_thread_interrupt_checkpoint (mb);
5291 if (klass
->valuetype
) {
5292 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
5293 pos1
= mono_mb_emit_branch (mb
, CEE_BR
);
5295 mono_mb_emit_byte (mb
, CEE_RET
);
5299 mono_mb_patch_branch (mb
, pos0
);
5301 mono_mb_emit_ldarg (mb
, 0);
5302 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5303 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5304 mono_mb_emit_ldarg (mb
, 3);
5305 mono_mb_emit_byte (mb
, CEE_ADD
);
5307 if (klass
->valuetype
)
5308 mono_mb_patch_branch (mb
, pos1
);
5313 case MONO_TYPE_BOOLEAN
:
5314 case MONO_TYPE_CHAR
:
5323 case MONO_TYPE_ARRAY
:
5324 case MONO_TYPE_SZARRAY
:
5325 case MONO_TYPE_OBJECT
:
5326 case MONO_TYPE_CLASS
:
5327 case MONO_TYPE_STRING
:
5331 case MONO_TYPE_FNPTR
:
5332 mono_mb_emit_byte (mb
, mono_type_to_ldind (type
));
5334 case MONO_TYPE_VALUETYPE
:
5335 g_assert (!klass
->enumtype
);
5336 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
5338 case MONO_TYPE_GENERICINST
:
5339 if (mono_type_generic_inst_is_valuetype (type
)) {
5340 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
5342 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5346 g_warning ("type %x not implemented", type
->type
);
5347 g_assert_not_reached ();
5350 mono_mb_emit_byte (mb
, CEE_RET
);
5352 res
= mono_mb_create_and_cache (cache
, klass
,
5353 mb
, sig
, sig
->param_count
+ 16);
5360 * mono_marshal_get_ldflda_wrapper:
5361 * @type: the type of the field
5363 * This method generates a function which can be used to load a field address
5364 * from an object. The generated function has the following signature:
5365 * gpointer ldflda_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset);
5368 mono_marshal_get_ldflda_wrapper (MonoType
*type
)
5370 MonoMethodSignature
*sig
;
5371 MonoMethodBuilder
*mb
;
5378 type
= mono_type_get_underlying_type (type
);
5382 if (type
->type
== MONO_TYPE_SZARRAY
) {
5383 klass
= mono_defaults
.array_class
;
5384 } else if (type
->type
== MONO_TYPE_VALUETYPE
) {
5385 klass
= type
->data
.klass
;
5386 } else if (t
== MONO_TYPE_OBJECT
|| t
== MONO_TYPE_CLASS
|| t
== MONO_TYPE_STRING
||
5387 t
== MONO_TYPE_CLASS
) {
5388 klass
= mono_defaults
.object_class
;
5389 } else if (t
== MONO_TYPE_PTR
|| t
== MONO_TYPE_FNPTR
) {
5390 klass
= mono_defaults
.int_class
;
5391 } else if (t
== MONO_TYPE_GENERICINST
) {
5392 if (mono_type_generic_inst_is_valuetype (type
))
5393 klass
= mono_class_from_mono_type (type
);
5395 klass
= mono_defaults
.object_class
;
5397 klass
= mono_class_from_mono_type (type
);
5400 klass
= mono_defaults
.int_class
;
5403 cache
= klass
->image
->ldflda_wrapper_cache
;
5404 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
5407 /* we add the %p pointer value of klass because class names are not unique */
5408 name
= g_strdup_printf ("__ldflda_wrapper_%p_%s.%s", klass
, klass
->name_space
, klass
->name
);
5409 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_LDFLDA
);
5412 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
5413 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5414 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5415 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5416 sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
5417 sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
5419 mono_mb_emit_ldarg (mb
, 0);
5420 pos0
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
5422 /* FIXME: Only throw this if the object is in another appdomain */
5423 mono_mb_emit_exception_full (mb
, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain.");
5425 mono_mb_patch_branch (mb
, pos0
);
5427 mono_mb_emit_ldarg (mb
, 0);
5428 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5429 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5430 mono_mb_emit_ldarg (mb
, 3);
5431 mono_mb_emit_byte (mb
, CEE_ADD
);
5433 mono_mb_emit_byte (mb
, CEE_RET
);
5435 res
= mono_mb_create_and_cache (cache
, klass
,
5436 mb
, sig
, sig
->param_count
+ 16);
5443 * mono_marshal_get_stfld_remote_wrapper:
5444 * klass: The type of the field
5446 * This function generates a wrapper for calling mono_store_remote_field_new
5447 * with the appropriate signature.
5450 mono_marshal_get_stfld_remote_wrapper (MonoClass
*klass
)
5452 MonoMethodSignature
*sig
, *csig
;
5453 MonoMethodBuilder
*mb
;
5458 cache
= klass
->image
->stfld_remote_wrapper_cache
;
5459 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
5462 name
= g_strdup_printf ("__mono_store_remote_field_new_wrapper_%s.%s", klass
->name_space
, klass
->name
);
5463 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STFLD_REMOTE
);
5466 mb
->method
->save_lmf
= 1;
5468 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
5469 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5470 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5471 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5472 sig
->params
[3] = &klass
->byval_arg
;
5473 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
5475 mono_mb_emit_ldarg (mb
, 0);
5476 mono_mb_emit_ldarg (mb
, 1);
5477 mono_mb_emit_ldarg (mb
, 2);
5478 mono_mb_emit_ldarg (mb
, 3);
5480 if (klass
->valuetype
)
5481 mono_mb_emit_op (mb
, CEE_BOX
, klass
);
5483 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 4);
5484 csig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5485 csig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5486 csig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5487 csig
->params
[3] = &klass
->byval_arg
;
5488 csig
->ret
= &mono_defaults
.void_class
->byval_arg
;
5491 mono_mb_emit_native_call (mb
, csig
, mono_store_remote_field_new
);
5492 emit_thread_interrupt_checkpoint (mb
);
5494 mono_mb_emit_byte (mb
, CEE_RET
);
5496 res
= mono_mb_create_and_cache (cache
, klass
,
5497 mb
, sig
, sig
->param_count
+ 16);
5504 * mono_marshal_get_stfld_wrapper:
5505 * @type: the type of the field
5507 * This method generates a function which can be use to store a field with type
5508 * @type. The generated function has the following signature:
5509 * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
5512 mono_marshal_get_stfld_wrapper (MonoType
*type
)
5514 MonoMethodSignature
*sig
;
5515 MonoMethodBuilder
*mb
;
5522 type
= mono_type_get_underlying_type (type
);
5526 if (type
->type
== MONO_TYPE_SZARRAY
) {
5527 klass
= mono_defaults
.array_class
;
5528 } else if (type
->type
== MONO_TYPE_VALUETYPE
) {
5529 klass
= type
->data
.klass
;
5530 } else if (t
== MONO_TYPE_OBJECT
|| t
== MONO_TYPE_CLASS
|| t
== MONO_TYPE_STRING
) {
5531 klass
= mono_defaults
.object_class
;
5532 } else if (t
== MONO_TYPE_PTR
|| t
== MONO_TYPE_FNPTR
) {
5533 klass
= mono_defaults
.int_class
;
5534 } else if (t
== MONO_TYPE_GENERICINST
) {
5535 if (mono_type_generic_inst_is_valuetype (type
))
5536 klass
= mono_class_from_mono_type (type
);
5538 klass
= mono_defaults
.object_class
;
5540 klass
= mono_class_from_mono_type (type
);
5543 klass
= mono_defaults
.int_class
;
5546 cache
= klass
->image
->stfld_wrapper_cache
;
5547 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
5550 /* we add the %p pointer value of klass because class names are not unique */
5551 name
= g_strdup_printf ("__stfld_wrapper_%p_%s.%s", klass
, klass
->name_space
, klass
->name
);
5552 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_STFLD
);
5555 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 5);
5556 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
5557 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
;
5558 sig
->params
[2] = &mono_defaults
.int_class
->byval_arg
;
5559 sig
->params
[3] = &mono_defaults
.int_class
->byval_arg
;
5560 sig
->params
[4] = &klass
->byval_arg
;
5561 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
5563 mono_mb_emit_ldarg (mb
, 0);
5564 pos
= mono_mb_emit_proxy_check (mb
, CEE_BNE_UN
);
5566 mono_mb_emit_ldarg (mb
, 0);
5567 mono_mb_emit_ldarg (mb
, 1);
5568 mono_mb_emit_ldarg (mb
, 2);
5569 mono_mb_emit_ldarg (mb
, 4);
5571 mono_mb_emit_managed_call (mb
, mono_marshal_get_stfld_remote_wrapper (klass
), NULL
);
5573 mono_mb_emit_byte (mb
, CEE_RET
);
5575 mono_mb_patch_branch (mb
, pos
);
5577 mono_mb_emit_ldarg (mb
, 0);
5578 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5579 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5580 mono_mb_emit_ldarg (mb
, 3);
5581 mono_mb_emit_byte (mb
, CEE_ADD
);
5582 mono_mb_emit_ldarg (mb
, 4);
5587 case MONO_TYPE_BOOLEAN
:
5588 case MONO_TYPE_CHAR
:
5597 case MONO_TYPE_ARRAY
:
5598 case MONO_TYPE_SZARRAY
:
5599 case MONO_TYPE_OBJECT
:
5600 case MONO_TYPE_CLASS
:
5601 case MONO_TYPE_STRING
:
5605 case MONO_TYPE_FNPTR
:
5606 mono_mb_emit_byte (mb
, mono_type_to_stind (type
));
5608 case MONO_TYPE_VALUETYPE
:
5609 g_assert (!klass
->enumtype
);
5610 mono_mb_emit_op (mb
, CEE_STOBJ
, klass
);
5612 case MONO_TYPE_GENERICINST
:
5613 mono_mb_emit_op (mb
, CEE_STOBJ
, klass
);
5616 g_warning ("type %x not implemented", type
->type
);
5617 g_assert_not_reached ();
5620 mono_mb_emit_byte (mb
, CEE_RET
);
5622 res
= mono_mb_create_and_cache (cache
, klass
,
5623 mb
, sig
, sig
->param_count
+ 16);
5630 * generates IL code for the icall wrapper (the generated method
5631 * calls the unmanaged code in func)
5634 mono_marshal_get_icall_wrapper (MonoMethodSignature
*sig
, const char *name
, gconstpointer func
)
5636 MonoMethodSignature
*csig
;
5637 MonoMethodBuilder
*mb
;
5641 g_assert (sig
->pinvoke
);
5643 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
5645 mb
->method
->save_lmf
= 1;
5647 /* we copy the signature, so that we can modify it */
5650 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
5652 for (i
= 0; i
< sig
->param_count
; i
++)
5653 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
5655 mono_mb_emit_native_call (mb
, sig
, (gpointer
) func
);
5656 emit_thread_interrupt_checkpoint (mb
);
5657 mono_mb_emit_byte (mb
, CEE_RET
);
5659 csig
= signature_dup (mono_defaults
.corlib
, sig
);
5661 if (csig
->call_convention
== MONO_CALL_VARARG
)
5662 csig
->call_convention
= 0;
5664 res
= mono_mb_create_method (mb
, csig
, csig
->param_count
+ 16);
5671 MonoMethodBuilder
*mb
;
5672 MonoMethodSignature
*sig
;
5673 MonoMethodPInvoke
*piinfo
;
5674 int *orig_conv_args
; /* Locals containing the original values of byref args */
5676 MonoClass
*retobj_class
;
5677 MonoMethodSignature
*csig
; /* Might need to be changed due to MarshalAs directives */
5678 MonoImage
*image
; /* The image to use for looking up custom marshallers */
5679 } EmitMarshalContext
;
5683 * This is invoked to convert arguments from the current types to
5684 * the underlying types expected by the platform routine. If required,
5685 * the methods create a temporary variable with the proper type, and return
5686 * the location for it (either the passed argument, or the newly allocated
5689 MARSHAL_ACTION_CONV_IN
,
5692 * This operation is called to push the actual value that was optionally
5693 * converted on the first stage
5695 MARSHAL_ACTION_PUSH
,
5698 * Convert byref arguments back or free resources allocated during the
5701 MARSHAL_ACTION_CONV_OUT
,
5704 * The result from the unmanaged call is at the top of the stack when
5705 * this action is invoked. The result should be stored in the
5706 * third local variable slot.
5708 MARSHAL_ACTION_CONV_RESULT
,
5710 MARSHAL_ACTION_MANAGED_CONV_IN
,
5711 MARSHAL_ACTION_MANAGED_CONV_OUT
,
5712 MARSHAL_ACTION_MANAGED_CONV_RESULT
5716 emit_marshal_custom (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5717 MonoMarshalSpec
*spec
,
5718 int conv_arg
, MonoType
**conv_arg_type
,
5719 MarshalAction action
)
5723 static MonoClass
*ICustomMarshaler
= NULL
;
5724 static MonoMethod
*cleanup_native
, *cleanup_managed
;
5725 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
5726 MonoMethod
*get_instance
;
5727 MonoMethodBuilder
*mb
= m
->mb
;
5728 char *exception_msg
= NULL
;
5732 if (!ICustomMarshaler
) {
5733 ICustomMarshaler
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "ICustomMarshaler");
5734 g_assert (ICustomMarshaler
);
5736 cleanup_native
= mono_class_get_method_from_name (ICustomMarshaler
, "CleanUpNativeData", 1);
5737 g_assert (cleanup_native
);
5738 cleanup_managed
= mono_class_get_method_from_name (ICustomMarshaler
, "CleanUpManagedData", 1);
5739 g_assert (cleanup_managed
);
5740 marshal_managed_to_native
= mono_class_get_method_from_name (ICustomMarshaler
, "MarshalManagedToNative", 1);
5741 g_assert (marshal_managed_to_native
);
5742 marshal_native_to_managed
= mono_class_get_method_from_name (ICustomMarshaler
, "MarshalNativeToManaged", 1);
5743 g_assert (marshal_native_to_managed
);
5746 mtype
= mono_reflection_type_from_name (spec
->data
.custom_data
.custom_name
, m
->image
);
5747 g_assert (mtype
!= NULL
);
5748 mklass
= mono_class_from_mono_type (mtype
);
5749 g_assert (mklass
!= NULL
);
5751 if (!mono_class_is_assignable_from (ICustomMarshaler
, mklass
))
5752 exception_msg
= g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass
->name
);
5754 get_instance
= mono_class_get_method_from_name_flags (mklass
, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC
);
5756 MonoMethodSignature
*get_sig
= mono_method_signature (get_instance
);
5757 if ((get_sig
->ret
->type
!= MONO_TYPE_CLASS
) ||
5758 (mono_class_from_mono_type (get_sig
->ret
) != ICustomMarshaler
) ||
5759 (get_sig
->params
[0]->type
!= MONO_TYPE_STRING
))
5760 get_instance
= NULL
;
5764 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
);
5766 /* Throw exception and emit compensation code if neccesary */
5767 if (exception_msg
) {
5769 case MARSHAL_ACTION_CONV_IN
:
5770 case MARSHAL_ACTION_CONV_RESULT
:
5771 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5772 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
5773 mono_mb_emit_byte (mb
, CEE_POP
);
5775 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
5776 g_free (exception_msg
);
5779 case MARSHAL_ACTION_PUSH
:
5780 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5788 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
5789 /* FIXME: MS.NET throws an exception if GetInstance returns null */
5792 case MARSHAL_ACTION_CONV_IN
:
5794 case MONO_TYPE_CLASS
:
5795 case MONO_TYPE_OBJECT
:
5796 case MONO_TYPE_STRING
:
5797 case MONO_TYPE_ARRAY
:
5798 case MONO_TYPE_SZARRAY
:
5799 case MONO_TYPE_VALUETYPE
:
5803 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
5804 g_assert_not_reached ();
5808 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5810 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5811 mono_mb_emit_stloc (mb
, conv_arg
);
5813 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5816 /* Minic MS.NET behavior */
5817 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
5820 /* Check for null */
5821 mono_mb_emit_ldarg (mb
, argnum
);
5823 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5824 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5826 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5828 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5830 mono_mb_emit_ldarg (mb
, argnum
);
5832 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5834 if (t
->type
== MONO_TYPE_VALUETYPE
) {
5836 * Since we can't determine the type of the argument, we
5837 * will assume the unmanaged function takes a pointer.
5839 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
5841 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type (t
));
5844 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
5845 mono_mb_emit_stloc (mb
, conv_arg
);
5847 mono_mb_patch_branch (mb
, pos2
);
5850 case MARSHAL_ACTION_CONV_OUT
:
5851 /* Check for null */
5852 mono_mb_emit_ldloc (mb
, conv_arg
);
5853 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5856 mono_mb_emit_ldarg (mb
, argnum
);
5858 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5860 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5862 mono_mb_emit_ldloc (mb
, conv_arg
);
5863 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5864 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5865 } else if (t
->attrs
&PARAM_ATTRIBUTE_OUT
) {
5866 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5868 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5870 mono_mb_emit_ldloc (mb
, conv_arg
);
5871 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5873 /* We have nowhere to store the result */
5874 mono_mb_emit_byte (mb
, CEE_POP
);
5877 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5879 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5881 mono_mb_emit_ldloc (mb
, conv_arg
);
5883 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
5885 mono_mb_patch_branch (mb
, pos2
);
5888 case MARSHAL_ACTION_PUSH
:
5890 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5892 mono_mb_emit_ldloc (mb
, conv_arg
);
5895 case MARSHAL_ACTION_CONV_RESULT
:
5896 loc1
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
5898 mono_mb_emit_stloc (mb
, 3);
5900 mono_mb_emit_ldloc (mb
, 3);
5901 mono_mb_emit_stloc (mb
, loc1
);
5903 /* Check for null */
5904 mono_mb_emit_ldloc (mb
, 3);
5905 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5907 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5909 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5910 mono_mb_emit_byte (mb
, CEE_DUP
);
5912 mono_mb_emit_ldloc (mb
, 3);
5913 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5914 mono_mb_emit_stloc (mb
, 3);
5916 mono_mb_emit_ldloc (mb
, loc1
);
5917 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
5919 mono_mb_patch_branch (mb
, pos2
);
5922 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5923 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
5925 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5926 mono_mb_emit_stloc (mb
, conv_arg
);
5928 /* Check for null */
5929 mono_mb_emit_ldarg (mb
, argnum
);
5931 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5932 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5934 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5935 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5937 mono_mb_emit_ldarg (mb
, argnum
);
5939 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5941 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
5942 mono_mb_emit_stloc (mb
, conv_arg
);
5944 mono_mb_patch_branch (mb
, pos2
);
5947 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5948 g_assert (!t
->byref
);
5950 loc1
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
5952 mono_mb_emit_stloc (mb
, 3);
5954 mono_mb_emit_ldloc (mb
, 3);
5955 mono_mb_emit_stloc (mb
, loc1
);
5957 /* Check for null */
5958 mono_mb_emit_ldloc (mb
, 3);
5959 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5961 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5962 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5963 mono_mb_emit_byte (mb
, CEE_DUP
);
5965 mono_mb_emit_ldloc (mb
, 3);
5966 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
5967 mono_mb_emit_stloc (mb
, 3);
5969 mono_mb_emit_ldloc (mb
, loc1
);
5970 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
5972 mono_mb_patch_branch (mb
, pos2
);
5975 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5977 /* Check for null */
5978 mono_mb_emit_ldloc (mb
, conv_arg
);
5979 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5982 mono_mb_emit_ldarg (mb
, argnum
);
5984 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5986 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5988 mono_mb_emit_ldloc (mb
, conv_arg
);
5989 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
5990 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5993 /* Call CleanUpManagedData */
5994 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
5996 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
5998 mono_mb_emit_ldloc (mb
, conv_arg
);
5999 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
6001 mono_mb_patch_branch (mb
, pos2
);
6005 g_assert_not_reached ();
6012 emit_marshal_asany (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6013 MonoMarshalSpec
*spec
,
6014 int conv_arg
, MonoType
**conv_arg_type
,
6015 MarshalAction action
)
6017 MonoMethodBuilder
*mb
= m
->mb
;
6020 case MARSHAL_ACTION_CONV_IN
: {
6021 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
6023 g_assert (t
->type
== MONO_TYPE_OBJECT
);
6024 g_assert (!t
->byref
);
6026 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6027 mono_mb_emit_ldarg (mb
, argnum
);
6028 mono_mb_emit_icon (mb
, encoding
);
6029 mono_mb_emit_icon (mb
, t
->attrs
);
6030 mono_mb_emit_icall (mb
, mono_marshal_asany
);
6031 mono_mb_emit_stloc (mb
, conv_arg
);
6035 case MARSHAL_ACTION_PUSH
:
6036 mono_mb_emit_ldloc (mb
, conv_arg
);
6039 case MARSHAL_ACTION_CONV_OUT
: {
6040 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
6042 mono_mb_emit_ldarg (mb
, argnum
);
6043 mono_mb_emit_ldloc (mb
, conv_arg
);
6044 mono_mb_emit_icon (mb
, encoding
);
6045 mono_mb_emit_icon (mb
, t
->attrs
);
6046 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
6051 g_assert_not_reached ();
6058 emit_marshal_vtype (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6059 MonoMarshalSpec
*spec
,
6060 int conv_arg
, MonoType
**conv_arg_type
,
6061 MarshalAction action
)
6063 MonoMethodBuilder
*mb
= m
->mb
;
6067 klass
= t
->data
.klass
;
6070 case MARSHAL_ACTION_CONV_IN
:
6071 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6072 klass
->blittable
|| klass
->enumtype
)
6075 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6077 /* store the address of the source into local variable 0 */
6079 mono_mb_emit_ldarg (mb
, argnum
);
6081 mono_mb_emit_ldarg_addr (mb
, argnum
);
6083 mono_mb_emit_stloc (mb
, 0);
6085 /* allocate space for the native struct and
6086 * store the address into local variable 1 (dest) */
6087 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6088 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6089 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
6090 mono_mb_emit_stloc (mb
, conv_arg
);
6093 mono_mb_emit_ldloc (mb
, 0);
6094 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6097 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
6099 mono_mb_emit_ldloc (mb
, conv_arg
);
6100 mono_mb_emit_stloc (mb
, 1);
6102 /* emit valuetype conversion code */
6103 emit_struct_conv (mb
, klass
, FALSE
);
6107 mono_mb_patch_branch (mb
, pos
);
6110 case MARSHAL_ACTION_PUSH
:
6111 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
6113 g_assert (!t
->byref
);
6115 /* Have to change the signature since the vtype is passed byref */
6116 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = &mono_defaults
.int_class
->byval_arg
;
6118 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6119 klass
->blittable
|| klass
->enumtype
)
6120 mono_mb_emit_ldarg_addr (mb
, argnum
);
6122 mono_mb_emit_ldloc (mb
, conv_arg
);
6126 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6127 klass
->blittable
|| klass
->enumtype
) {
6128 mono_mb_emit_ldarg (mb
, argnum
);
6131 mono_mb_emit_ldloc (mb
, conv_arg
);
6133 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6134 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
6138 case MARSHAL_ACTION_CONV_OUT
:
6139 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6140 klass
->blittable
|| klass
->enumtype
)
6144 /* dst = argument */
6145 mono_mb_emit_ldarg (mb
, argnum
);
6146 mono_mb_emit_stloc (mb
, 1);
6148 mono_mb_emit_ldloc (mb
, 1);
6149 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6151 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
6152 /* src = tmp_locals [i] */
6153 mono_mb_emit_ldloc (mb
, conv_arg
);
6154 mono_mb_emit_stloc (mb
, 0);
6156 /* emit valuetype conversion code */
6157 emit_struct_conv (mb
, klass
, TRUE
);
6161 emit_struct_free (mb
, klass
, conv_arg
);
6164 mono_mb_patch_branch (mb
, pos
);
6167 case MARSHAL_ACTION_CONV_RESULT
:
6168 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6170 mono_mb_emit_stloc (mb
, 3);
6173 /* load pointer to returned value type */
6174 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6175 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
6176 /* store the address of the source into local variable 0 */
6177 mono_mb_emit_stloc (mb
, 0);
6179 mono_mb_emit_ldloc_addr (mb
, 3);
6180 mono_mb_emit_stloc (mb
, 1);
6182 /* emit valuetype conversion code */
6183 emit_struct_conv (mb
, klass
, TRUE
);
6186 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6187 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6188 klass
->blittable
|| klass
->enumtype
) {
6193 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
6195 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6199 mono_mb_emit_ldarg (mb
, argnum
);
6201 mono_mb_emit_ldarg_addr (mb
, argnum
);
6202 mono_mb_emit_stloc (mb
, 0);
6205 mono_mb_emit_ldloc (mb
, 0);
6206 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6209 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6210 mono_mb_emit_stloc (mb
, 1);
6212 /* emit valuetype conversion code */
6213 emit_struct_conv (mb
, klass
, TRUE
);
6216 mono_mb_patch_branch (mb
, pos
);
6219 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6220 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6221 klass
->blittable
|| klass
->enumtype
) {
6225 /* Check for null */
6226 mono_mb_emit_ldarg (mb
, argnum
);
6227 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6230 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6231 mono_mb_emit_stloc (mb
, 0);
6234 mono_mb_emit_ldarg (mb
, argnum
);
6235 mono_mb_emit_stloc (mb
, 1);
6237 /* emit valuetype conversion code */
6238 emit_struct_conv (mb
, klass
, FALSE
);
6240 mono_mb_patch_branch (mb
, pos2
);
6243 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6244 if (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
6245 klass
->blittable
|| klass
->enumtype
) {
6246 mono_mb_emit_stloc (mb
, 3);
6251 /* load pointer to returned value type */
6252 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6253 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
6255 /* store the address of the source into local variable 0 */
6256 mono_mb_emit_stloc (mb
, 0);
6257 /* allocate space for the native struct and
6258 * store the address into dst_ptr */
6259 m
->retobj_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6260 m
->retobj_class
= klass
;
6261 g_assert (m
->retobj_var
);
6262 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6263 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6264 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
6265 mono_mb_emit_stloc (mb
, 1);
6266 mono_mb_emit_ldloc (mb
, 1);
6267 mono_mb_emit_stloc (mb
, m
->retobj_var
);
6269 /* emit valuetype conversion code */
6270 emit_struct_conv (mb
, klass
, FALSE
);
6274 g_assert_not_reached ();
6281 emit_marshal_string (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6282 MonoMarshalSpec
*spec
,
6283 int conv_arg
, MonoType
**conv_arg_type
,
6284 MarshalAction action
)
6286 MonoMethodBuilder
*mb
= m
->mb
;
6287 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6288 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
6292 case MARSHAL_ACTION_CONV_IN
:
6293 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6294 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6297 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6300 mono_mb_emit_ldarg (mb
, argnum
);
6301 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6303 mono_mb_emit_ldarg (mb
, argnum
);
6307 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
6308 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
6311 mono_raise_exception (exc
);
6314 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6316 mono_mb_emit_stloc (mb
, conv_arg
);
6319 case MARSHAL_ACTION_CONV_OUT
:
6320 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6321 mono_mb_emit_ldarg (mb
, argnum
);
6322 mono_mb_emit_ldloc (mb
, conv_arg
);
6323 if (conv
== MONO_MARSHAL_CONV_STR_BSTR
) {
6324 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_BSTR_STR
));
6325 // BSTRs always need freed
6326 mono_mb_emit_ldloc (mb
, conv_arg
);
6327 mono_mb_emit_icall (mb
, mono_free_bstr
);
6330 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR
));
6331 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6333 if (mono_marshal_need_free (t
, m
->piinfo
, spec
)) {
6334 mono_mb_emit_ldloc (mb
, conv_arg
);
6335 if (conv
== MONO_MARSHAL_CONV_STR_BSTR
)
6336 mono_mb_emit_icall (mb
, mono_free_bstr
);
6338 mono_mb_emit_icall (mb
, mono_marshal_free
);
6343 case MARSHAL_ACTION_PUSH
:
6345 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6347 mono_mb_emit_ldloc (mb
, conv_arg
);
6350 case MARSHAL_ACTION_CONV_RESULT
:
6351 mono_mb_emit_stloc (mb
, 0);
6353 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
6355 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
6356 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6360 mono_mb_emit_ldloc (mb
, 0);
6361 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6362 mono_mb_emit_stloc (mb
, 3);
6364 /* free the string */
6365 mono_mb_emit_ldloc (mb
, 0);
6366 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
6367 mono_mb_emit_icall (mb
, mono_free_bstr
);
6369 mono_mb_emit_icall (mb
, g_free
);
6372 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6378 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
6379 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6381 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
6383 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
6384 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6388 mono_mb_emit_ldarg (mb
, argnum
);
6389 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6390 mono_mb_emit_stloc (mb
, conv_arg
);
6393 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6394 if (conv_to_icall (conv
) == mono_marshal_string_to_utf16
)
6395 /* We need to make a copy so the caller is able to free it */
6396 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
6398 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6399 mono_mb_emit_stloc (mb
, 3);
6403 g_assert_not_reached ();
6410 emit_marshal_safehandle (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6411 MonoMarshalSpec
*spec
, int conv_arg
,
6412 MonoType
**conv_arg_type
, MarshalAction action
)
6414 MonoMethodBuilder
*mb
= m
->mb
;
6417 case MARSHAL_ACTION_CONV_IN
: {
6418 MonoType
*intptr_type
;
6419 int dar_release_slot
, pos
;
6421 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
6422 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
6423 *conv_arg_type
= intptr_type
;
6425 if (!sh_dangerous_add_ref
)
6426 init_safe_handle ();
6428 mono_mb_emit_ldarg (mb
, argnum
);
6429 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6430 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
6432 mono_mb_patch_branch (mb
, pos
);
6435 * My tests in show that ref SafeHandles are not really
6436 * passed as ref objects. Instead a NULL is passed as the
6439 mono_mb_emit_icon (mb
, 0);
6440 mono_mb_emit_stloc (mb
, conv_arg
);
6444 /* Create local to hold the ref parameter to DangerousAddRef */
6445 dar_release_slot
= mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
6447 /* set release = false; */
6448 mono_mb_emit_icon (mb
, 0);
6449 mono_mb_emit_stloc (mb
, dar_release_slot
);
6451 /* safehandle.DangerousAddRef (ref release) */
6452 mono_mb_emit_ldarg (mb
, argnum
);
6453 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
6454 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
6456 /* Pull the handle field from SafeHandle */
6457 mono_mb_emit_ldarg (mb
, argnum
);
6458 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
6459 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6460 mono_mb_emit_stloc (mb
, conv_arg
);
6465 case MARSHAL_ACTION_PUSH
:
6467 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6469 mono_mb_emit_ldloc (mb
, conv_arg
);
6472 case MARSHAL_ACTION_CONV_OUT
: {
6473 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
6474 int dar_release_slot
= conv_arg
+ 1;
6477 if (!sh_dangerous_release
)
6478 init_safe_handle ();
6484 * My tests indicate that ref SafeHandles parameters are not actually
6485 * passed by ref, but instead a new Handle is created regardless of
6486 * whether a change happens in the unmanaged side.
6488 * Also, the Handle is created before calling into unmanaged code,
6489 * but we do not support that mechanism (getting to the original
6490 * handle) and it makes no difference where we create this
6492 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
6494 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
6497 /* refval = new SafeHandleDerived ()*/
6498 mono_mb_emit_ldarg (mb
, argnum
);
6499 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
6500 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6502 /* refval.handle = returned_handle */
6503 mono_mb_emit_ldarg (mb
, argnum
);
6504 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6505 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
6506 mono_mb_emit_ldloc (mb
, conv_arg
);
6507 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6509 mono_mb_emit_ldloc (mb
, dar_release_slot
);
6510 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6511 mono_mb_emit_ldarg (mb
, argnum
);
6512 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
6513 mono_mb_patch_addr (mb
, label_next
, mb
->pos
- (label_next
+ 4));
6518 case MARSHAL_ACTION_CONV_RESULT
: {
6519 MonoMethod
*ctor
= NULL
;
6520 int intptr_handle_slot
;
6522 if (t
->data
.klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
){
6523 mono_mb_emit_byte (mb
, CEE_POP
);
6524 mono_mb_emit_exception_marshal_directive (mb
, "Returned SafeHandles should not be abstract");
6528 ctor
= mono_class_get_method_from_name (t
->data
.klass
, ".ctor", 0);
6530 mono_mb_emit_byte (mb
, CEE_POP
);
6531 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
6534 /* Store the IntPtr results into a local */
6535 intptr_handle_slot
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6536 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
6538 /* Create return value */
6539 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
6540 mono_mb_emit_stloc (mb
, 3);
6542 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
6543 mono_mb_emit_ldloc (mb
, 3);
6544 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoSafeHandle
, handle
));
6545 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
6546 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6550 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6551 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6554 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6555 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6558 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6559 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6562 printf ("Unhandled case for MarshalAction: %d\n", action
);
6569 emit_marshal_handleref (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6570 MonoMarshalSpec
*spec
, int conv_arg
,
6571 MonoType
**conv_arg_type
, MarshalAction action
)
6573 MonoMethodBuilder
*mb
= m
->mb
;
6576 case MARSHAL_ACTION_CONV_IN
: {
6577 MonoType
*intptr_type
;
6579 intptr_type
= &mono_defaults
.int_class
->byval_arg
;
6580 conv_arg
= mono_mb_add_local (mb
, intptr_type
);
6581 *conv_arg_type
= intptr_type
;
6584 mono_mb_emit_exception_marshal_directive (mb
,
6585 "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6588 mono_mb_emit_ldarg_addr (mb
, argnum
);
6589 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoHandleRef
, handle
));
6590 mono_mb_emit_byte (mb
, CEE_ADD
);
6591 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6592 mono_mb_emit_stloc (mb
, conv_arg
);
6596 case MARSHAL_ACTION_PUSH
:
6597 mono_mb_emit_ldloc (mb
, conv_arg
);
6600 case MARSHAL_ACTION_CONV_OUT
: {
6601 /* no resource release required */
6605 case MARSHAL_ACTION_CONV_RESULT
: {
6606 mono_mb_emit_exception_marshal_directive (mb
,
6607 "HandleRefs can not be returned from unmanaged code (or passed by ref)");
6611 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6612 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
6615 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6616 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
6619 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6620 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
6623 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
6630 emit_marshal_object (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6631 MonoMarshalSpec
*spec
,
6632 int conv_arg
, MonoType
**conv_arg_type
,
6633 MarshalAction action
)
6635 MonoMethodBuilder
*mb
= m
->mb
;
6636 MonoClass
*klass
= t
->data
.klass
;
6639 if (mono_class_from_mono_type (t
) == mono_defaults
.object_class
) {
6640 mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
6644 case MARSHAL_ACTION_CONV_IN
:
6645 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
6646 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6648 m
->orig_conv_args
[argnum
] = 0;
6650 if (klass
->delegate
) {
6651 g_assert (!t
->byref
);
6652 mono_mb_emit_ldarg (mb
, argnum
);
6653 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
));
6654 mono_mb_emit_stloc (mb
, conv_arg
);
6655 } else if (klass
== mono_defaults
.stringbuilder_class
) {
6656 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6657 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
6659 g_assert (!t
->byref
);
6660 mono_mb_emit_ldarg (mb
, argnum
);
6663 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6665 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
6666 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
6669 mono_raise_exception (exc
);
6672 mono_mb_emit_stloc (mb
, conv_arg
);
6673 } else if (klass
->blittable
) {
6674 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6675 mono_mb_emit_stloc (mb
, conv_arg
);
6677 mono_mb_emit_ldarg (mb
, argnum
);
6678 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6680 mono_mb_emit_ldarg (mb
, argnum
);
6681 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6682 mono_mb_emit_stloc (mb
, conv_arg
);
6684 mono_mb_patch_branch (mb
, pos
);
6687 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6688 mono_mb_emit_stloc (mb
, conv_arg
);
6691 /* we dont need any conversions for out parameters */
6692 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6695 mono_mb_emit_ldarg (mb
, argnum
);
6696 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6699 mono_mb_emit_ldarg (mb
, argnum
);
6700 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6701 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
6704 /* store the address of the source into local variable 0 */
6705 mono_mb_emit_stloc (mb
, 0);
6706 mono_mb_emit_ldloc (mb
, 0);
6707 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6709 /* allocate space for the native struct and store the address */
6710 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6711 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6712 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
6713 mono_mb_emit_stloc (mb
, conv_arg
);
6716 /* Need to store the original buffer so we can free it later */
6717 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6718 mono_mb_emit_ldloc (mb
, conv_arg
);
6719 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
6722 /* set the src_ptr */
6723 mono_mb_emit_ldloc (mb
, 0);
6724 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6725 mono_mb_emit_stloc (mb
, 0);
6728 mono_mb_emit_ldloc (mb
, conv_arg
);
6729 mono_mb_emit_stloc (mb
, 1);
6731 /* emit valuetype conversion code */
6732 emit_struct_conv (mb
, klass
, FALSE
);
6734 mono_mb_patch_branch (mb
, pos
);
6738 case MARSHAL_ACTION_CONV_OUT
:
6739 if (klass
== mono_defaults
.stringbuilder_class
) {
6741 MonoMarshalNative encoding
;
6742 MonoMarshalConv conv
;
6744 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
6745 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
6747 g_assert (!t
->byref
);
6748 g_assert (encoding
!= -1);
6750 mono_mb_emit_ldarg (mb
, argnum
);
6751 mono_mb_emit_ldloc (mb
, conv_arg
);
6753 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
6756 mono_mb_emit_ldloc (mb
, conv_arg
);
6757 mono_mb_emit_icall (mb
, mono_marshal_free
);
6762 if (klass
->delegate
)
6765 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6766 /* allocate a new object */
6767 mono_mb_emit_ldarg (mb
, argnum
);
6768 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6769 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, t
->data
.klass
);
6770 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6773 /* dst = *argument */
6774 mono_mb_emit_ldarg (mb
, argnum
);
6777 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6779 mono_mb_emit_stloc (mb
, 1);
6781 mono_mb_emit_ldloc (mb
, 1);
6782 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6784 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6785 mono_mb_emit_ldloc (mb
, 1);
6786 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
6787 mono_mb_emit_byte (mb
, CEE_ADD
);
6788 mono_mb_emit_stloc (mb
, 1);
6790 /* src = tmp_locals [i] */
6791 mono_mb_emit_ldloc (mb
, conv_arg
);
6792 mono_mb_emit_stloc (mb
, 0);
6794 /* emit valuetype conversion code */
6795 emit_struct_conv (mb
, t
->data
.klass
, TRUE
);
6797 /* Free the structure returned by the native code */
6798 emit_struct_free (mb
, klass
, conv_arg
);
6800 if (m
->orig_conv_args
[argnum
]) {
6802 * If the native function changed the pointer, then free
6803 * the original structure plus the new pointer.
6805 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
6806 mono_mb_emit_ldloc (mb
, conv_arg
);
6807 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
6809 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
6810 g_assert (m
->orig_conv_args
[argnum
]);
6812 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
6815 mono_mb_emit_ldloc (mb
, conv_arg
);
6816 mono_mb_emit_icall (mb
, g_free
);
6818 mono_mb_patch_branch (mb
, pos2
);
6822 /* Free the original structure passed to native code */
6823 emit_struct_free (mb
, klass
, conv_arg
);
6825 mono_mb_patch_branch (mb
, pos
);
6828 case MARSHAL_ACTION_PUSH
:
6830 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6832 mono_mb_emit_ldloc (mb
, conv_arg
);
6835 case MARSHAL_ACTION_CONV_RESULT
:
6836 if (klass
->delegate
) {
6837 g_assert (!t
->byref
);
6838 mono_mb_emit_stloc (mb
, 0);
6839 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6840 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6841 mono_mb_emit_ldloc (mb
, 0);
6842 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
));
6843 mono_mb_emit_stloc (mb
, 3);
6846 mono_mb_emit_stloc (mb
, 0);
6848 /* Make a copy since emit_conv modifies local 0 */
6849 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
6850 mono_mb_emit_ldloc (mb
, 0);
6851 mono_mb_emit_stloc (mb
, loc
);
6853 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6854 mono_mb_emit_stloc (mb
, 3);
6856 mono_mb_emit_ldloc (mb
, 0);
6857 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6859 /* allocate result object */
6861 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6862 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6863 mono_mb_emit_stloc (mb
, 3);
6867 mono_mb_emit_ldloc (mb
, 3);
6868 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6869 mono_mb_emit_stloc (mb
, 1);
6871 /* emit conversion code */
6872 emit_struct_conv (mb
, klass
, TRUE
);
6874 emit_struct_free (mb
, klass
, loc
);
6876 /* Free the pointer allocated by unmanaged code */
6877 mono_mb_emit_ldloc (mb
, loc
);
6878 mono_mb_emit_icall (mb
, g_free
);
6879 mono_mb_patch_branch (mb
, pos
);
6883 case MARSHAL_ACTION_MANAGED_CONV_IN
:
6884 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
6886 if (klass
->delegate
) {
6887 g_assert (!t
->byref
);
6888 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6889 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
6890 mono_mb_emit_ldarg (mb
, argnum
);
6891 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
));
6892 mono_mb_emit_stloc (mb
, conv_arg
);
6896 /* The class can not have an automatic layout */
6897 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
6898 mono_mb_emit_auto_layout_exception (mb
, klass
);
6902 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
6903 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6904 mono_mb_emit_stloc (mb
, conv_arg
);
6909 mono_mb_emit_ldarg (mb
, argnum
);
6913 /* Check for NULL and raise an exception */
6914 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6916 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
6918 mono_mb_patch_branch (mb
, pos2
);
6919 mono_mb_emit_ldarg (mb
, argnum
);
6920 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
6923 mono_mb_emit_stloc (mb
, 0);
6925 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6926 mono_mb_emit_stloc (mb
, conv_arg
);
6928 mono_mb_emit_ldloc (mb
, 0);
6929 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
6931 /* Create and set dst */
6932 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6933 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
6934 mono_mb_emit_stloc (mb
, conv_arg
);
6935 mono_mb_emit_ldloc (mb
, conv_arg
);
6936 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6937 mono_mb_emit_stloc (mb
, 1);
6939 /* emit valuetype conversion code */
6940 emit_struct_conv (mb
, klass
, TRUE
);
6942 mono_mb_patch_branch (mb
, pos
);
6945 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
6947 /* Check for null */
6948 mono_mb_emit_ldloc (mb
, conv_arg
);
6949 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6950 mono_mb_emit_ldarg (mb
, argnum
);
6951 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
6952 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6953 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6955 mono_mb_patch_branch (mb
, pos
);
6958 mono_mb_emit_ldloc (mb
, conv_arg
);
6959 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6960 mono_mb_emit_stloc (mb
, 0);
6962 /* Allocate and set dest */
6963 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6964 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6965 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
6966 mono_mb_emit_stloc (mb
, 1);
6968 /* Update argument pointer */
6969 mono_mb_emit_ldarg (mb
, argnum
);
6970 mono_mb_emit_ldloc (mb
, 1);
6971 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6973 /* emit valuetype conversion code */
6974 emit_struct_conv (mb
, klass
, FALSE
);
6976 mono_mb_patch_branch (mb
, pos2
);
6978 /* byval [Out] marshalling */
6980 /* FIXME: Handle null */
6983 mono_mb_emit_ldloc (mb
, conv_arg
);
6984 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
6985 mono_mb_emit_stloc (mb
, 0);
6988 mono_mb_emit_ldarg (mb
, argnum
);
6989 mono_mb_emit_stloc (mb
, 1);
6991 /* emit valuetype conversion code */
6992 emit_struct_conv (mb
, klass
, FALSE
);
6996 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6997 if (klass
->delegate
) {
6998 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
));
6999 mono_mb_emit_stloc (mb
, 3);
7003 /* The class can not have an automatic layout */
7004 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
7005 mono_mb_emit_auto_layout_exception (mb
, klass
);
7009 mono_mb_emit_stloc (mb
, 0);
7010 /* Check for null */
7011 mono_mb_emit_ldloc (mb
, 0);
7012 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
7013 mono_mb_emit_byte (mb
, CEE_LDNULL
);
7014 mono_mb_emit_stloc (mb
, 3);
7015 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
7017 mono_mb_patch_branch (mb
, pos
);
7020 mono_mb_emit_ldloc (mb
, 0);
7021 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
7022 mono_mb_emit_stloc (mb
, 0);
7024 /* Allocate and set dest */
7025 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
7026 mono_mb_emit_byte (mb
, CEE_CONV_I
);
7027 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
7028 mono_mb_emit_byte (mb
, CEE_DUP
);
7029 mono_mb_emit_stloc (mb
, 1);
7030 mono_mb_emit_stloc (mb
, 3);
7032 emit_struct_conv (mb
, klass
, FALSE
);
7034 mono_mb_patch_branch (mb
, pos2
);
7038 g_assert_not_reached ();
7045 emit_marshal_com_interface (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7046 MonoMarshalSpec
*spec
,
7047 int conv_arg
, MonoType
**conv_arg_type
,
7048 MarshalAction action
)
7050 MonoMethodBuilder
*mb
= m
->mb
;
7051 MonoClass
*klass
= t
->data
.klass
;
7052 static MonoMethod
* get_object_for_iunknown
= NULL
;
7053 static MonoMethod
* get_iunknown_for_object_internal
= NULL
;
7054 static MonoMethod
* get_com_interface_for_object_internal
= NULL
;
7055 static MonoMethod
* get_idispatch_for_object_internal
= NULL
;
7056 static MonoMethod
* marshal_release
= NULL
;
7057 static MonoMethod
* AddRef
= NULL
;
7058 if (!get_object_for_iunknown
)
7059 get_object_for_iunknown
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForIUnknown", 1);
7060 if (!get_iunknown_for_object_internal
)
7061 get_iunknown_for_object_internal
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetIUnknownForObjectInternal", 1);
7062 if (!get_idispatch_for_object_internal
)
7063 get_idispatch_for_object_internal
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetIDispatchForObjectInternal", 1);
7064 if (!get_com_interface_for_object_internal
)
7065 get_com_interface_for_object_internal
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetComInterfaceForObjectInternal", 2);
7066 if (!marshal_release
)
7067 marshal_release
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "Release", 1);
7069 /* COM types are initialized lazily */
7070 mono_init_com_types ();
7073 case MARSHAL_ACTION_CONV_IN
: {
7074 guint32 pos_null
= 0;
7076 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7077 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7079 mono_mb_emit_ptr (mb
, NULL
);
7080 mono_mb_emit_stloc (mb
, conv_arg
);
7082 /* we dont need any conversions for out parameters */
7083 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
7086 mono_mb_emit_ldarg (mb
, argnum
);
7088 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7089 /* if null just break, conv arg was already inited to 0 */
7090 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
7092 mono_mb_emit_ldarg (mb
, argnum
);
7094 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7096 if (klass
&& klass
!= mono_defaults
.object_class
) {
7097 mono_mb_emit_ptr (mb
, t
);
7098 mono_mb_emit_icall (mb
, type_from_handle
);
7099 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
7101 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
7102 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
7103 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
7104 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
7105 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
7106 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
7108 g_assert_not_reached ();
7109 mono_mb_emit_stloc (mb
, conv_arg
);
7110 mono_mb_patch_short_branch (mb
, pos_null
);
7114 case MARSHAL_ACTION_CONV_OUT
: {
7115 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
7117 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
7118 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7120 mono_mb_emit_ldarg (mb
, argnum
);
7121 mono_mb_emit_byte (mb
, CEE_LDNULL
);
7122 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
7124 mono_mb_emit_ldloc (mb
, conv_arg
);
7125 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
7127 mono_mb_emit_ldloc (mb
, conv_arg
);
7128 mono_mb_emit_icon (mb
, TRUE
);
7129 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
7130 mono_mb_emit_stloc (mb
, ccw_obj
);
7131 mono_mb_emit_ldloc (mb
, ccw_obj
);
7132 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
7134 mono_mb_emit_ldarg (mb
, argnum
);
7135 mono_mb_emit_ldloc (mb
, conv_arg
);
7136 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
7138 if (klass
&& klass
!= mono_defaults
.object_class
)
7139 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
7140 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
7142 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
7144 /* is already managed object */
7145 mono_mb_patch_short_branch (mb
, pos_ccw
);
7146 mono_mb_emit_ldarg (mb
, argnum
);
7147 mono_mb_emit_ldloc (mb
, ccw_obj
);
7149 if (klass
&& klass
!= mono_defaults
.object_class
)
7150 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
7151 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
7153 mono_mb_patch_short_branch (mb
, pos_end
);
7155 /* need to call Release to follow COM rules of ownership */
7156 mono_mb_emit_ldloc (mb
, conv_arg
);
7157 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
7158 mono_mb_emit_byte (mb
, CEE_POP
);
7161 mono_mb_patch_short_branch (mb
, pos_null
);
7165 case MARSHAL_ACTION_PUSH
:
7167 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7169 mono_mb_emit_ldloc (mb
, conv_arg
);
7172 case MARSHAL_ACTION_CONV_RESULT
: {
7173 int ccw_obj
, ret_ptr
;
7174 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
7175 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7176 ret_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7178 /* store return value */
7179 mono_mb_emit_stloc (mb
, ret_ptr
);
7181 mono_mb_emit_ldloc (mb
, ret_ptr
);
7182 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
7184 mono_mb_emit_ldloc (mb
, ret_ptr
);
7185 mono_mb_emit_icon (mb
, TRUE
);
7186 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
7187 mono_mb_emit_stloc (mb
, ccw_obj
);
7188 mono_mb_emit_ldloc (mb
, ccw_obj
);
7189 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
7191 mono_mb_emit_ldloc (mb
, ret_ptr
);
7192 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
7194 if (klass
&& klass
!= mono_defaults
.object_class
)
7195 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
7196 mono_mb_emit_stloc (mb
, 3);
7198 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
7200 /* is already managed object */
7201 mono_mb_patch_short_branch (mb
, pos_ccw
);
7202 mono_mb_emit_ldloc (mb
, ccw_obj
);
7204 if (klass
&& klass
!= mono_defaults
.object_class
)
7205 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
7206 mono_mb_emit_stloc (mb
, 3);
7208 mono_mb_patch_short_branch (mb
, pos_end
);
7210 /* need to call Release to follow COM rules of ownership */
7211 mono_mb_emit_ldloc (mb
, ret_ptr
);
7212 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
7213 mono_mb_emit_byte (mb
, CEE_POP
);
7216 mono_mb_patch_short_branch (mb
, pos_null
);
7220 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7222 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
7223 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7225 klass
= mono_class_from_mono_type (t
);
7226 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
7227 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7229 mono_mb_emit_byte (mb
, CEE_LDNULL
);
7230 mono_mb_emit_stloc (mb
, conv_arg
);
7231 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
7234 mono_mb_emit_ldarg (mb
, argnum
);
7236 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7237 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
7239 mono_mb_emit_ldarg (mb
, argnum
);
7241 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7242 mono_mb_emit_icon (mb
, TRUE
);
7243 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
7244 mono_mb_emit_stloc (mb
, ccw_obj
);
7245 mono_mb_emit_ldloc (mb
, ccw_obj
);
7246 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
7249 mono_mb_emit_ldarg (mb
, argnum
);
7251 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7252 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
7254 if (klass
&& klass
!= mono_defaults
.object_class
)
7255 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
7256 mono_mb_emit_stloc (mb
, conv_arg
);
7257 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
7259 /* is already managed object */
7260 mono_mb_patch_short_branch (mb
, pos_ccw
);
7261 mono_mb_emit_ldloc (mb
, ccw_obj
);
7262 if (klass
&& klass
!= mono_defaults
.object_class
)
7263 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
7264 mono_mb_emit_stloc (mb
, conv_arg
);
7266 mono_mb_patch_short_branch (mb
, pos_end
);
7268 mono_mb_patch_short_branch (mb
, pos_null
);
7272 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7273 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
7274 guint32 pos_null
= 0;
7277 AddRef
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "AddRef", 1);
7279 mono_mb_emit_ldloc (mb
, conv_arg
);
7280 /* if null just break, conv arg was already inited to 0 */
7281 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
7283 /* to store later */
7284 mono_mb_emit_ldarg (mb
, argnum
);
7285 mono_mb_emit_ldloc (mb
, conv_arg
);
7286 if (klass
&& klass
!= mono_defaults
.object_class
) {
7287 mono_mb_emit_ptr (mb
, t
);
7288 mono_mb_emit_icall (mb
, type_from_handle
);
7289 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
7291 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
7292 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
7293 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
7294 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
7295 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
7296 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
7298 g_assert_not_reached ();
7299 mono_mb_emit_byte (mb
, CEE_STIND_I
);
7301 mono_mb_emit_ldarg (mb
, argnum
);
7302 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7303 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
7304 mono_mb_emit_byte (mb
, CEE_POP
);
7306 mono_mb_patch_short_branch (mb
, pos_null
);
7311 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
7312 guint32 pos_null
= 0;
7314 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7317 AddRef
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "AddRef", 1);
7319 /* store return value */
7320 mono_mb_emit_stloc (mb
, ccw_obj
);
7322 mono_mb_emit_ldloc (mb
, ccw_obj
);
7324 /* if null just break, conv arg was already inited to 0 */
7325 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
7327 /* to store later */
7328 mono_mb_emit_ldloc (mb
, ccw_obj
);
7329 if (klass
&& klass
!= mono_defaults
.object_class
) {
7330 mono_mb_emit_ptr (mb
, t
);
7331 mono_mb_emit_icall (mb
, type_from_handle
);
7332 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
7334 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
7335 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
7336 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
7337 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
7338 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
7339 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
7341 g_assert_not_reached ();
7342 mono_mb_emit_stloc (mb
, 3);
7343 mono_mb_emit_ldloc (mb
, 3);
7345 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
7346 mono_mb_emit_byte (mb
, CEE_POP
);
7348 mono_mb_patch_short_branch (mb
, pos_null
);
7353 g_assert_not_reached ();
7360 emit_marshal_variant (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7361 MonoMarshalSpec
*spec
,
7362 int conv_arg
, MonoType
**conv_arg_type
,
7363 MarshalAction action
)
7365 MonoMethodBuilder
*mb
= m
->mb
;
7366 static MonoMethod
*get_object_for_native_variant
= NULL
;
7367 static MonoMethod
*get_native_variant_for_object
= NULL
;
7369 mono_init_com_types ();
7371 if (!get_object_for_native_variant
)
7372 get_object_for_native_variant
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1);
7373 g_assert (get_object_for_native_variant
);
7375 if (!get_native_variant_for_object
)
7376 get_native_variant_for_object
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2);
7377 g_assert (get_native_variant_for_object
);
7380 case MARSHAL_ACTION_CONV_IN
: {
7381 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.variant_class
->byval_arg
);
7384 *conv_arg_type
= &mono_defaults
.variant_class
->this_arg
;
7386 *conv_arg_type
= &mono_defaults
.variant_class
->byval_arg
;
7388 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
7391 mono_mb_emit_ldarg (mb
, argnum
);
7393 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
7394 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7395 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
7399 case MARSHAL_ACTION_CONV_OUT
: {
7400 static MonoMethod
*variant_clear
= NULL
;
7403 variant_clear
= mono_class_get_method_from_name (mono_defaults
.variant_class
, "Clear", 0);
7404 g_assert (variant_clear
);
7408 mono_mb_emit_ldarg (mb
, argnum
);
7409 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7410 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
7411 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
7414 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7415 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
7419 case MARSHAL_ACTION_PUSH
:
7421 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7423 mono_mb_emit_ldloc (mb
, conv_arg
);
7426 case MARSHAL_ACTION_CONV_RESULT
: {
7427 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
7428 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7432 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7433 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7436 *conv_arg_type
= &mono_defaults
.variant_class
->this_arg
;
7438 *conv_arg_type
= &mono_defaults
.variant_class
->byval_arg
;
7440 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
7444 mono_mb_emit_ldarg (mb
, argnum
);
7446 mono_mb_emit_ldarg_addr (mb
, argnum
);
7447 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
7448 mono_mb_emit_stloc (mb
, conv_arg
);
7452 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7454 mono_mb_emit_ldloc (mb
, conv_arg
);
7455 mono_mb_emit_ldarg (mb
, argnum
);
7456 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
7461 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
7462 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
7463 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7468 g_assert_not_reached ();
7475 emit_marshal_array (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
7476 MonoMarshalSpec
*spec
,
7477 int conv_arg
, MonoType
**conv_arg_type
,
7478 MarshalAction action
)
7480 MonoMethodBuilder
*mb
= m
->mb
;
7481 MonoClass
*klass
= mono_class_from_mono_type (t
);
7482 gboolean need_convert
, need_free
;
7483 MonoMarshalNative encoding
;
7485 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
7488 case MARSHAL_ACTION_CONV_IN
:
7489 *conv_arg_type
= &mono_defaults
.object_class
->byval_arg
;
7490 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7492 if (klass
->element_class
->blittable
) {
7493 mono_mb_emit_ldarg (mb
, argnum
);
7495 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7496 mono_mb_emit_icall (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
));
7497 mono_mb_emit_stloc (mb
, conv_arg
);
7500 guint32 label1
, label2
, label3
;
7501 int index_var
, src_var
, dest_ptr
, esize
;
7502 MonoMarshalConv conv
;
7503 gboolean is_string
= FALSE
;
7505 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7507 eklass
= klass
->element_class
;
7509 if (eklass
== mono_defaults
.string_class
) {
7511 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
7513 else if (eklass
== mono_defaults
.stringbuilder_class
) {
7515 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
7520 src_var
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7521 mono_mb_emit_ldarg (mb
, argnum
);
7523 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7524 mono_mb_emit_stloc (mb
, src_var
);
7527 mono_mb_emit_ldloc (mb
, src_var
);
7528 mono_mb_emit_stloc (mb
, conv_arg
);
7529 mono_mb_emit_ldloc (mb
, src_var
);
7530 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7534 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
7535 MonoException
*exc
= mono_get_exception_not_implemented (msg
);
7538 mono_raise_exception (exc
);
7543 esize
= sizeof (gpointer
);
7545 esize
= mono_class_native_size (eklass
, NULL
);
7547 /* allocate space for the native struct and store the address */
7548 mono_mb_emit_icon (mb
, esize
);
7549 mono_mb_emit_ldloc (mb
, src_var
);
7550 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7552 if (eklass
== mono_defaults
.string_class
) {
7553 /* Make the array bigger for the terminating null */
7554 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
7555 mono_mb_emit_byte (mb
, CEE_ADD
);
7557 mono_mb_emit_byte (mb
, CEE_MUL
);
7558 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
7559 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
7560 mono_mb_emit_stloc (mb
, conv_arg
);
7562 mono_mb_emit_ldloc (mb
, conv_arg
);
7563 mono_mb_emit_stloc (mb
, dest_ptr
);
7565 /* Emit marshalling loop */
7566 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7567 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7568 mono_mb_emit_stloc (mb
, index_var
);
7570 mono_mb_emit_ldloc (mb
, index_var
);
7571 mono_mb_emit_ldloc (mb
, src_var
);
7572 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7573 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7575 /* Emit marshalling code */
7578 mono_mb_emit_ldloc (mb
, dest_ptr
);
7579 mono_mb_emit_ldloc (mb
, src_var
);
7580 mono_mb_emit_ldloc (mb
, index_var
);
7581 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
7582 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7583 mono_mb_emit_byte (mb
, CEE_STIND_I
);
7585 /* set the src_ptr */
7586 mono_mb_emit_ldloc (mb
, src_var
);
7587 mono_mb_emit_ldloc (mb
, index_var
);
7588 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
7589 mono_mb_emit_stloc (mb
, 0);
7592 mono_mb_emit_ldloc (mb
, dest_ptr
);
7593 mono_mb_emit_stloc (mb
, 1);
7595 /* emit valuetype conversion code */
7596 emit_struct_conv (mb
, eklass
, FALSE
);
7599 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7600 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
7602 mono_mb_emit_byte (mb
, CEE_BR
);
7603 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
7605 mono_mb_patch_branch (mb
, label3
);
7607 if (eklass
== mono_defaults
.string_class
) {
7608 /* Null terminate */
7609 mono_mb_emit_ldloc (mb
, dest_ptr
);
7610 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7611 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
7614 mono_mb_patch_branch (mb
, label1
);
7619 case MARSHAL_ACTION_CONV_OUT
:
7620 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
7621 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
);
7622 need_free
= mono_marshal_need_free (&klass
->element_class
->byval_arg
,
7625 if (need_convert
|| need_free
) {
7626 /* FIXME: Optimize blittable case */
7628 guint32 label1
, label2
, label3
;
7629 int index_var
, src_ptr
, loc
, esize
;
7631 eklass
= klass
->element_class
;
7632 if ((eklass
== mono_defaults
.stringbuilder_class
) || (eklass
== mono_defaults
.string_class
))
7633 esize
= sizeof (gpointer
);
7635 esize
= mono_class_native_size (eklass
, NULL
);
7636 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7637 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7640 mono_mb_emit_ldarg (mb
, argnum
);
7642 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7643 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7645 mono_mb_emit_ldloc (mb
, conv_arg
);
7646 mono_mb_emit_stloc (mb
, src_ptr
);
7648 /* Emit marshalling loop */
7649 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7650 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7651 mono_mb_emit_stloc (mb
, index_var
);
7653 mono_mb_emit_ldloc (mb
, index_var
);
7654 mono_mb_emit_ldarg (mb
, argnum
);
7656 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
7657 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7658 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7660 /* Emit marshalling code */
7662 if (eklass
== mono_defaults
.stringbuilder_class
) {
7663 gboolean need_free2
;
7664 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
7666 g_assert (conv
!= -1);
7669 mono_mb_emit_ldarg (mb
, argnum
);
7671 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7672 mono_mb_emit_ldloc (mb
, index_var
);
7673 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
7676 mono_mb_emit_ldloc (mb
, src_ptr
);
7677 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7679 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7683 mono_mb_emit_ldloc (mb
, src_ptr
);
7684 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7686 mono_mb_emit_icall (mb
, mono_marshal_free
);
7689 else if (eklass
== mono_defaults
.string_class
) {
7692 mono_mb_emit_ldloc (mb
, src_ptr
);
7693 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7695 mono_mb_emit_icall (mb
, mono_marshal_free
);
7700 /* set the src_ptr */
7701 mono_mb_emit_ldloc (mb
, src_ptr
);
7702 mono_mb_emit_stloc (mb
, 0);
7705 mono_mb_emit_ldarg (mb
, argnum
);
7707 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7708 mono_mb_emit_ldloc (mb
, index_var
);
7709 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
7710 mono_mb_emit_stloc (mb
, 1);
7712 /* emit valuetype conversion code */
7713 emit_struct_conv (mb
, eklass
, TRUE
);
7717 mono_mb_emit_ldloc (mb
, src_ptr
);
7718 mono_mb_emit_stloc (mb
, loc
);
7719 mono_mb_emit_ldloc (mb
, loc
);
7721 emit_struct_free (mb
, eklass
, loc
);
7725 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7726 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
7728 mono_mb_emit_byte (mb
, CEE_BR
);
7729 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
7731 mono_mb_patch_branch (mb
, label1
);
7732 mono_mb_patch_branch (mb
, label3
);
7736 case MARSHAL_ACTION_PUSH
:
7738 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
7740 mono_mb_emit_ldloc (mb
, conv_arg
);
7743 case MARSHAL_ACTION_CONV_RESULT
:
7744 /* fixme: we need conversions here */
7745 mono_mb_emit_stloc (mb
, 3);
7748 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
7750 guint32 label1
, label2
, label3
;
7751 int index_var
, src_ptr
, loc
, esize
, param_num
, num_elem
;
7752 MonoMarshalConv conv
;
7753 gboolean is_string
= FALSE
;
7755 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
7756 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
7759 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
7760 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7764 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
7765 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7768 if (spec
->native
!= MONO_NATIVE_LPARRAY
) {
7769 char *msg
= g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
7770 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7774 /* FIXME: t is from the method which is wrapped, not the delegate type */
7775 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
7777 param_num
= spec
->data
.array_data
.param_num
;
7778 num_elem
= spec
->data
.array_data
.num_elem
;
7779 if (spec
->data
.array_data
.elem_mult
== 0)
7780 /* param_num is not specified */
7783 if (param_num
== -1) {
7784 if (num_elem
<= 0) {
7785 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
7786 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7791 /* FIXME: Optimize blittable case */
7793 eklass
= klass
->element_class
;
7794 if (eklass
== mono_defaults
.string_class
) {
7796 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
7798 else if (eklass
== mono_defaults
.stringbuilder_class
) {
7800 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
7805 mono_marshal_load_type_info (eklass
);
7808 esize
= sizeof (gpointer
);
7810 esize
= mono_class_native_size (eklass
, NULL
);
7811 src_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7812 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7814 mono_mb_emit_byte (mb
, CEE_LDNULL
);
7815 mono_mb_emit_stloc (mb
, conv_arg
);
7817 /* Check param index */
7818 if (param_num
!= -1) {
7819 if (param_num
>= m
->sig
->param_count
) {
7820 char *msg
= g_strdup ("Array size control parameter index is out of range.");
7821 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7824 switch (m
->sig
->params
[param_num
]->type
) {
7837 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
7838 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7845 mono_mb_emit_ldarg (mb
, argnum
);
7846 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7848 mono_mb_emit_ldarg (mb
, argnum
);
7849 mono_mb_emit_stloc (mb
, src_ptr
);
7851 /* Create managed array */
7853 * The LPArray marshalling spec says that sometimes param_num starts
7854 * from 1, sometimes it starts from 0. But MS seems to allways start
7858 if (param_num
== -1)
7859 mono_mb_emit_icon (mb
, num_elem
);
7861 /* FIXME: Add the two together */
7862 mono_mb_emit_ldarg (mb
, param_num
);
7864 mono_mb_emit_icon (mb
, num_elem
);
7865 mono_mb_emit_byte (mb
, CEE_ADD
);
7869 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
7870 mono_mb_emit_stloc (mb
, conv_arg
);
7872 if (eklass
->blittable
) {
7873 mono_mb_emit_ldloc (mb
, conv_arg
);
7874 mono_mb_emit_byte (mb
, CEE_CONV_I
);
7875 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
7876 mono_mb_emit_byte (mb
, CEE_ADD
);
7877 mono_mb_emit_ldarg (mb
, argnum
);
7878 mono_mb_emit_ldloc (mb
, conv_arg
);
7879 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7880 mono_mb_emit_icon (mb
, esize
);
7881 mono_mb_emit_byte (mb
, CEE_MUL
);
7882 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
7883 mono_mb_emit_byte (mb
, CEE_CPBLK
);
7887 /* Emit marshalling loop */
7888 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7889 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
7890 mono_mb_emit_stloc (mb
, index_var
);
7892 mono_mb_emit_ldloc (mb
, index_var
);
7893 mono_mb_emit_ldloc (mb
, conv_arg
);
7894 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7895 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
7897 /* Emit marshalling code */
7899 g_assert (conv
!= -1);
7901 mono_mb_emit_ldloc (mb
, conv_arg
);
7902 mono_mb_emit_ldloc (mb
, index_var
);
7904 mono_mb_emit_ldloc (mb
, src_ptr
);
7905 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
7907 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
7908 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
7911 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7912 mono_mb_emit_exception_marshal_directive (mb
, msg
);
7916 mono_mb_emit_add_to_local (mb
, index_var
, 1);
7917 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
7919 mono_mb_emit_byte (mb
, CEE_BR
);
7920 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
7922 mono_mb_patch_branch (mb
, label1
);
7923 mono_mb_patch_branch (mb
, label3
);
7927 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
7929 guint32 label1
, label2
, label3
;
7930 int index_var
, dest_ptr
, loc
, esize
, param_num
, num_elem
;
7931 MonoMarshalConv conv
;
7932 gboolean is_string
= FALSE
;
7935 /* Already handled in CONV_IN */
7938 /* These are already checked in CONV_IN */
7939 g_assert (!t
->byref
);
7940 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
7941 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
7943 param_num
= spec
->data
.array_data
.param_num
;
7944 num_elem
= spec
->data
.array_data
.num_elem
;
7946 if (spec
->data
.array_data
.elem_mult
== 0)
7947 /* param_num is not specified */
7950 if (param_num
== -1) {
7951 if (num_elem
<= 0) {
7952 g_assert_not_reached ();
7956 /* FIXME: Optimize blittable case */
7958 eklass
= klass
->element_class
;
7959 if (eklass
== mono_defaults
.string_class
) {
7961 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
7963 else if (eklass
== mono_defaults
.stringbuilder_class
) {
7965 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
7970 mono_marshal_load_type_info (eklass
);
7973 esize
= sizeof (gpointer
);
7975 esize
= mono_class_native_size (eklass
, NULL
);
7977 dest_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7978 loc
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
7981 mono_mb_emit_ldloc (mb
, conv_arg
);
7982 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
7984 mono_mb_emit_ldarg (mb
, argnum
);
7985 mono_mb_emit_stloc (mb
, dest_ptr
);
7987 if (eklass
->blittable
) {
7989 mono_mb_emit_ldarg (mb
, argnum
);
7991 mono_mb_emit_ldloc (mb
, conv_arg
);
7992 mono_mb_emit_byte (mb
, CEE_CONV_I
);
7993 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
7994 mono_mb_emit_byte (mb
, CEE_ADD
);
7996 mono_mb_emit_ldloc (mb
, conv_arg
);
7997 mono_mb_emit_byte (mb
, CEE_LDLEN
);
7998 mono_mb_emit_icon (mb
, esize
);
7999 mono_mb_emit_byte (mb
, CEE_MUL
);
8000 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
8001 mono_mb_emit_byte (mb
, CEE_CPBLK
);
8005 /* Emit marshalling loop */
8006 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8007 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
8008 mono_mb_emit_stloc (mb
, index_var
);
8010 mono_mb_emit_ldloc (mb
, index_var
);
8011 mono_mb_emit_ldloc (mb
, conv_arg
);
8012 mono_mb_emit_byte (mb
, CEE_LDLEN
);
8013 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
8015 /* Emit marshalling code */
8017 g_assert (conv
!= -1);
8020 mono_mb_emit_ldloc (mb
, dest_ptr
);
8023 mono_mb_emit_ldloc (mb
, conv_arg
);
8024 mono_mb_emit_ldloc (mb
, index_var
);
8026 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
8028 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
8029 mono_mb_emit_byte (mb
, CEE_STIND_I
);
8032 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
8033 mono_mb_emit_exception_marshal_directive (mb
, msg
);
8037 mono_mb_emit_add_to_local (mb
, index_var
, 1);
8038 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
8040 mono_mb_emit_byte (mb
, CEE_BR
);
8041 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
8043 mono_mb_patch_branch (mb
, label1
);
8044 mono_mb_patch_branch (mb
, label3
);
8048 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
8050 guint32 label1
, label2
, label3
;
8051 int index_var
, src
, dest
, esize
;
8052 MonoMarshalConv conv
= -1;
8053 gboolean is_string
= FALSE
;
8055 g_assert (!t
->byref
);
8057 eklass
= klass
->element_class
;
8059 mono_marshal_load_type_info (eklass
);
8061 if (eklass
== mono_defaults
.string_class
) {
8063 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
8066 g_assert_not_reached ();
8070 esize
= sizeof (gpointer
);
8072 esize
= mono_class_native_size (eklass
, NULL
);
8074 src
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
8075 dest
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8077 mono_mb_emit_stloc (mb
, src
);
8078 mono_mb_emit_ldloc (mb
, src
);
8079 mono_mb_emit_stloc (mb
, 3);
8081 /* Check for null */
8082 mono_mb_emit_ldloc (mb
, src
);
8083 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
8085 /* Allocate native array */
8086 mono_mb_emit_icon (mb
, esize
);
8087 mono_mb_emit_ldloc (mb
, src
);
8088 mono_mb_emit_byte (mb
, CEE_LDLEN
);
8090 if (eklass
== mono_defaults
.string_class
) {
8091 /* Make the array bigger for the terminating null */
8092 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
8093 mono_mb_emit_byte (mb
, CEE_ADD
);
8095 mono_mb_emit_byte (mb
, CEE_MUL
);
8096 mono_mb_emit_icall (mb
, mono_marshal_alloc
);
8097 mono_mb_emit_stloc (mb
, dest
);
8098 mono_mb_emit_ldloc (mb
, dest
);
8099 mono_mb_emit_stloc (mb
, 3);
8101 /* Emit marshalling loop */
8102 index_var
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8103 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
8104 mono_mb_emit_stloc (mb
, index_var
);
8106 mono_mb_emit_ldloc (mb
, index_var
);
8107 mono_mb_emit_ldloc (mb
, src
);
8108 mono_mb_emit_byte (mb
, CEE_LDLEN
);
8109 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
8111 /* Emit marshalling code */
8113 g_assert (conv
!= -1);
8116 mono_mb_emit_ldloc (mb
, dest
);
8119 mono_mb_emit_ldloc (mb
, src
);
8120 mono_mb_emit_ldloc (mb
, index_var
);
8122 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
8124 mono_mb_emit_icall (mb
, conv_to_icall (conv
));
8125 mono_mb_emit_byte (mb
, CEE_STIND_I
);
8128 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
8129 mono_mb_emit_exception_marshal_directive (mb
, msg
);
8133 mono_mb_emit_add_to_local (mb
, index_var
, 1);
8134 mono_mb_emit_add_to_local (mb
, dest
, esize
);
8136 mono_mb_emit_byte (mb
, CEE_BR
);
8137 mono_mb_emit_i4 (mb
, label2
- (mb
->pos
+ 4));
8139 mono_mb_patch_branch (mb
, label3
);
8140 mono_mb_patch_branch (mb
, label1
);
8144 g_assert_not_reached ();
8151 emit_marshal_boolean (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
8152 MonoMarshalSpec
*spec
,
8153 int conv_arg
, MonoType
**conv_arg_type
,
8154 MarshalAction action
)
8156 MonoMethodBuilder
*mb
= m
->mb
;
8159 case MARSHAL_ACTION_CONV_IN
: {
8160 MonoType
*local_type
;
8161 int variant_bool
= 0;
8165 local_type
= &mono_defaults
.int32_class
->byval_arg
;
8167 switch (spec
->native
) {
8168 case MONO_NATIVE_I1
:
8169 local_type
= &mono_defaults
.byte_class
->byval_arg
;
8171 case MONO_NATIVE_VARIANTBOOL
:
8172 local_type
= &mono_defaults
.int16_class
->byval_arg
;
8176 g_warning ("marshalling bool as native type %x is currently not supported", spec
->native
);
8177 local_type
= &mono_defaults
.int32_class
->byval_arg
;
8181 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
8182 conv_arg
= mono_mb_add_local (mb
, local_type
);
8183 mono_mb_emit_ldarg (mb
, argnum
);
8184 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
8186 mono_mb_emit_byte (mb
, CEE_NEG
);
8187 mono_mb_emit_stloc (mb
, conv_arg
);
8191 case MARSHAL_ACTION_CONV_OUT
:
8194 mono_mb_emit_ldarg (mb
, argnum
);
8195 mono_mb_emit_ldloc (mb
, conv_arg
);
8196 if (spec
!= NULL
&& spec
->native
== MONO_NATIVE_VARIANTBOOL
)
8197 mono_mb_emit_byte (mb
, CEE_NEG
);
8198 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
8201 case MARSHAL_ACTION_PUSH
:
8203 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
8205 mono_mb_emit_ldarg (mb
, argnum
);
8208 case MARSHAL_ACTION_CONV_RESULT
:
8209 /* maybe we need to make sure that it fits within 8 bits */
8210 mono_mb_emit_stloc (mb
, 3);
8214 g_assert_not_reached ();
8221 emit_marshal_ptr (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
8222 MonoMarshalSpec
*spec
, int conv_arg
,
8223 MonoType
**conv_arg_type
, MarshalAction action
)
8225 MonoMethodBuilder
*mb
= m
->mb
;
8228 case MARSHAL_ACTION_CONV_IN
:
8229 if (MONO_TYPE_ISSTRUCT (t
->data
.type
)) {
8230 char *msg
= g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum
+ 1);
8231 mono_mb_emit_exception_marshal_directive (m
->mb
, msg
);
8235 case MARSHAL_ACTION_PUSH
:
8236 mono_mb_emit_ldarg (mb
, argnum
);
8239 case MARSHAL_ACTION_CONV_RESULT
:
8240 /* no conversions necessary */
8241 mono_mb_emit_stloc (mb
, 3);
8252 emit_marshal_char (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
8253 MonoMarshalSpec
*spec
, int conv_arg
,
8254 MonoType
**conv_arg_type
, MarshalAction action
)
8256 MonoMethodBuilder
*mb
= m
->mb
;
8259 case MARSHAL_ACTION_PUSH
:
8260 /* fixme: dont know how to marshal that. We cant simply
8261 * convert it to a one byte UTF8 character, because an
8262 * unicode character may need more that one byte in UTF8 */
8263 mono_mb_emit_ldarg (mb
, argnum
);
8266 case MARSHAL_ACTION_CONV_RESULT
:
8267 /* fixme: we need conversions here */
8268 mono_mb_emit_stloc (mb
, 3);
8279 emit_marshal_scalar (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
8280 MonoMarshalSpec
*spec
, int conv_arg
,
8281 MonoType
**conv_arg_type
, MarshalAction action
)
8283 MonoMethodBuilder
*mb
= m
->mb
;
8286 case MARSHAL_ACTION_PUSH
:
8287 mono_mb_emit_ldarg (mb
, argnum
);
8290 case MARSHAL_ACTION_CONV_RESULT
:
8291 /* no conversions necessary */
8292 mono_mb_emit_stloc (mb
, 3);
8303 emit_marshal (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
8304 MonoMarshalSpec
*spec
, int conv_arg
,
8305 MonoType
**conv_arg_type
, MarshalAction action
)
8307 /* Ensure that we have marshalling info for this param */
8308 mono_marshal_load_type_info (mono_class_from_mono_type (t
));
8310 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
)
8311 return emit_marshal_custom (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8313 if (spec
&& spec
->native
== MONO_NATIVE_ASANY
)
8314 return emit_marshal_asany (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8317 case MONO_TYPE_VALUETYPE
:
8318 if (t
->data
.klass
== mono_defaults
.handleref_class
)
8319 return emit_marshal_handleref (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8321 return emit_marshal_vtype (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8322 case MONO_TYPE_STRING
:
8323 return emit_marshal_string (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8324 case MONO_TYPE_CLASS
:
8325 case MONO_TYPE_OBJECT
:
8326 if (spec
&& spec
->native
== MONO_NATIVE_STRUCT
)
8327 return emit_marshal_variant (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8329 if (spec
&& (spec
->native
== MONO_NATIVE_IUNKNOWN
||
8330 spec
->native
== MONO_NATIVE_IDISPATCH
||
8331 spec
->native
== MONO_NATIVE_INTERFACE
))
8332 return emit_marshal_com_interface (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8334 if (mono_defaults
.safehandle_class
!= NULL
&&
8335 mono_class_is_subclass_of (t
->data
.klass
, mono_defaults
.safehandle_class
, FALSE
))
8336 return emit_marshal_safehandle (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8338 return emit_marshal_object (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8339 case MONO_TYPE_ARRAY
:
8340 case MONO_TYPE_SZARRAY
:
8341 return emit_marshal_array (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8342 case MONO_TYPE_BOOLEAN
:
8343 return emit_marshal_boolean (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8345 return emit_marshal_ptr (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8346 case MONO_TYPE_CHAR
:
8347 return emit_marshal_char (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8360 case MONO_TYPE_FNPTR
:
8361 return emit_marshal_scalar (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
8368 * mono_marshal_emit_native_wrapper:
8369 * @image: the image to use for looking up custom marshallers
8370 * @sig: The signature of the native function
8371 * @piinfo: Marshalling information
8372 * @mspecs: Marshalling information
8373 * @func: the native function to call
8375 * generates IL code for the pinvoke wrapper, the generated code calls @func.
8378 mono_marshal_emit_native_wrapper (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
8380 EmitMarshalContext m
;
8381 MonoMethodSignature
*csig
;
8383 int i
, argnum
, *tmp_locals
;
8385 static MonoMethodSignature
*get_last_error_sig
= NULL
;
8390 /* we copy the signature, so that we can set pinvoke to 0 */
8391 csig
= signature_dup (mb
->method
->klass
->image
, sig
);
8396 /* we allocate local for use with emit_struct_conv() */
8397 /* allocate local 0 (pointer) src_ptr */
8398 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8399 /* allocate local 1 (pointer) dst_ptr */
8400 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8401 /* allocate local 2 (boolean) delete_old */
8402 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
8404 /* delete_old = FALSE */
8405 mono_mb_emit_icon (mb
, 0);
8406 mono_mb_emit_stloc (mb
, 2);
8408 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
8409 /* allocate local 3 to store the return value */
8410 mono_mb_add_local (mb
, sig
->ret
);
8413 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
8414 /* Return type custom marshaling */
8416 * Since we can't determine the return type of the unmanaged function,
8417 * we assume it returns a pointer, and pass that pointer to
8418 * MarshalNativeToManaged.
8420 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8423 /* we first do all conversions */
8424 tmp_locals
= alloca (sizeof (int) * sig
->param_count
);
8425 m
.orig_conv_args
= alloca (sizeof (int) * (sig
->param_count
+ 1));
8427 for (i
= 0; i
< sig
->param_count
; i
++) {
8428 tmp_locals
[i
] = emit_marshal (&m
, i
+ sig
->hasthis
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
8431 /* push all arguments */
8434 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8437 for (i
= 0; i
< sig
->param_count
; i
++) {
8438 emit_marshal (&m
, i
+ sig
->hasthis
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
8441 /* call the native method */
8442 if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
8443 mono_mb_emit_cominterop_call (mb
, csig
, &piinfo
->method
);
8446 mono_mb_emit_native_call (mb
, csig
, func
);
8449 /* Set LastError if needed */
8450 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
8451 if (!get_last_error_sig
) {
8452 get_last_error_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 0);
8453 get_last_error_sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8454 get_last_error_sig
->pinvoke
= 1;
8457 #ifdef PLATFORM_WIN32
8459 * Have to call GetLastError () early and without a wrapper, since various runtime components could
8460 * clobber its value.
8462 mono_mb_emit_native_call (mb
, get_last_error_sig
, GetLastError
);
8463 mono_mb_emit_icall (mb
, mono_marshal_set_last_error_windows
);
8465 mono_mb_emit_icall (mb
, mono_marshal_set_last_error
);
8469 /* convert the result */
8470 if (!sig
->ret
->byref
) {
8471 MonoMarshalSpec
*spec
= mspecs
[0];
8472 type
= sig
->ret
->type
;
8474 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
8475 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
8480 case MONO_TYPE_VOID
:
8482 case MONO_TYPE_VALUETYPE
:
8483 klass
= sig
->ret
->data
.klass
;
8484 if (klass
->enumtype
) {
8485 type
= sig
->ret
->data
.klass
->enum_basetype
->type
;
8488 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
8502 case MONO_TYPE_FNPTR
:
8503 case MONO_TYPE_STRING
:
8504 case MONO_TYPE_CLASS
:
8505 case MONO_TYPE_OBJECT
:
8506 case MONO_TYPE_BOOLEAN
:
8507 case MONO_TYPE_ARRAY
:
8508 case MONO_TYPE_SZARRAY
:
8509 case MONO_TYPE_CHAR
:
8511 emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
8513 case MONO_TYPE_TYPEDBYREF
:
8515 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
8516 g_assert_not_reached ();
8520 mono_mb_emit_stloc (mb
, 3);
8524 * Need to call this after converting the result since MONO_VTADDR needs
8525 * to be adjacent to the call instruction.
8527 emit_thread_interrupt_checkpoint (mb
);
8529 /* we need to convert byref arguments back and free string arrays */
8530 for (i
= 0; i
< sig
->param_count
; i
++) {
8531 MonoType
*t
= sig
->params
[i
];
8532 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
8534 argnum
= i
+ sig
->hasthis
;
8536 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
8537 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
8542 case MONO_TYPE_STRING
:
8543 case MONO_TYPE_VALUETYPE
:
8544 case MONO_TYPE_CLASS
:
8545 case MONO_TYPE_OBJECT
:
8546 case MONO_TYPE_SZARRAY
:
8547 case MONO_TYPE_BOOLEAN
:
8548 emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
8553 if (!MONO_TYPE_IS_VOID(sig
->ret
))
8554 mono_mb_emit_ldloc (mb
, 3);
8556 mono_mb_emit_byte (mb
, CEE_RET
);
8560 * mono_marshal_get_native_wrapper:
8561 * @method: The MonoMethod to wrap.
8563 * generates IL code for the pinvoke wrapper (the generated method
8564 * calls the unmanaged code in piinfo->addr)
8567 mono_marshal_get_native_wrapper (MonoMethod
*method
)
8569 MonoMethodSignature
*sig
, *csig
;
8570 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
8571 MonoMethodBuilder
*mb
;
8572 MonoMarshalSpec
**mspecs
;
8575 gboolean pinvoke
= FALSE
;
8578 const char *exc_class
= "MissingMethodException";
8579 const char *exc_arg
= NULL
;
8581 g_assert (method
!= NULL
);
8582 g_assert (mono_method_signature (method
)->pinvoke
);
8584 cache
= method
->klass
->image
->native_wrapper_cache
;
8585 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
8588 if (MONO_CLASS_IS_IMPORT (method
->klass
))
8589 return cominterop_get_native_wrapper (method
);
8591 sig
= mono_method_signature (method
);
8593 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) &&
8594 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
))
8597 if (!piinfo
->addr
) {
8599 mono_lookup_pinvoke_call (method
, &exc_class
, &exc_arg
);
8601 piinfo
->addr
= mono_lookup_internal_call (method
);
8604 /* hack - redirect certain string constructors to CreateString */
8605 if (piinfo
->addr
== ves_icall_System_String_ctor_RedirectToCreateString
) {
8606 g_assert (!pinvoke
);
8607 g_assert (method
->string_ctor
);
8608 g_assert (sig
->hasthis
);
8610 /* CreateString returns a value */
8611 csig
= signature_dup (method
->klass
->image
, sig
);
8612 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
8616 while ((res
= mono_class_get_methods (mono_defaults
.string_class
, &iter
))) {
8617 if (!strcmp ("CreateString", res
->name
) &&
8618 mono_metadata_signature_equal (csig
, mono_method_signature (res
))) {
8620 g_assert (!(res
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
));
8621 g_assert (!(res
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
));
8623 /* create a wrapper to preserve .ctor in stack trace */
8624 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
8626 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8627 for (i
= 1; i
<= csig
->param_count
; i
++)
8628 mono_mb_emit_ldarg (mb
, i
);
8629 mono_mb_emit_managed_call (mb
, res
, NULL
);
8630 mono_mb_emit_byte (mb
, CEE_RET
);
8632 /* use native_wrapper_cache because internal calls are looked up there */
8633 res
= mono_mb_create_and_cache (cache
, method
,
8634 mb
, csig
, csig
->param_count
+ 1);
8642 /* exception will be thrown */
8643 piinfo
->addr
= NULL
;
8644 g_warning ("cannot find CreateString for .ctor");
8647 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8649 mb
->method
->save_lmf
= 1;
8651 if (!piinfo
->addr
) {
8652 mono_mb_emit_exception (mb
, exc_class
, exc_arg
);
8653 csig
= signature_dup (method
->klass
->image
, sig
);
8655 res
= mono_mb_create_and_cache (cache
, method
,
8656 mb
, csig
, csig
->param_count
+ 16);
8661 /* internal calls: we simply push all arguments and call the method (no conversions) */
8662 if (method
->iflags
& (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
| METHOD_IMPL_ATTRIBUTE_RUNTIME
)) {
8664 /* hack - string constructors returns a value */
8665 if (method
->string_ctor
) {
8666 csig
= signature_dup (method
->klass
->image
, sig
);
8667 csig
->ret
= &mono_defaults
.string_class
->byval_arg
;
8672 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
8674 for (i
= 0; i
< sig
->param_count
; i
++)
8675 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
8677 g_assert (piinfo
->addr
);
8678 mono_mb_emit_native_call (mb
, csig
, piinfo
->addr
);
8679 emit_thread_interrupt_checkpoint (mb
);
8680 mono_mb_emit_byte (mb
, CEE_RET
);
8682 csig
= signature_dup (method
->klass
->image
, csig
);
8684 res
= mono_mb_create_and_cache (cache
, method
,
8685 mb
, csig
, csig
->param_count
+ 16);
8692 mspecs
= g_new (MonoMarshalSpec
*, sig
->param_count
+ 1);
8693 mono_method_get_marshal_info (method
, mspecs
);
8695 mono_marshal_emit_native_wrapper (mb
->method
->klass
->image
, mb
, sig
, piinfo
, mspecs
, piinfo
->addr
);
8697 csig
= signature_dup (method
->klass
->image
, sig
);
8699 res
= mono_mb_create_and_cache (cache
, method
,
8700 mb
, csig
, csig
->param_count
+ 16);
8703 for (i
= sig
->param_count
; i
>= 0; i
--)
8705 mono_metadata_free_marshal_spec (mspecs
[i
]);
8708 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
8714 * mono_marshal_get_native_func_wrapper:
8715 * @image: The image to use for memory allocation and for looking up custom marshallers.
8716 * @sig: The signature of the function
8717 * @func: The native function to wrap
8719 * Returns a wrapper method around native functions, similar to the pinvoke
8723 mono_marshal_get_native_func_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
,
8724 MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
)
8726 MonoMethodSignature
*csig
;
8728 MonoMethodBuilder
*mb
;
8733 cache
= image
->native_wrapper_cache
;
8734 if ((res
= mono_marshal_find_in_cache (cache
, func
)))
8737 name
= g_strdup_printf ("wrapper_native_%p", func
);
8738 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
8739 mb
->method
->save_lmf
= 1;
8741 mono_marshal_emit_native_wrapper (image
, mb
, sig
, piinfo
, mspecs
, func
);
8743 csig
= signature_dup (image
, sig
);
8745 res
= mono_mb_create_and_cache (cache
, func
,
8746 mb
, csig
, csig
->param_count
+ 16);
8749 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
8754 /* FIXME: moving GC */
8756 mono_marshal_emit_managed_wrapper (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, MonoObject
* this)
8758 MonoMethodSignature
*sig
, *csig
;
8764 /* allocate local 0 (pointer) src_ptr */
8765 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8766 /* allocate local 1 (pointer) dst_ptr */
8767 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
8768 /* allocate local 2 (boolean) delete_old */
8769 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
8771 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
8772 /* allocate local 3 to store the return value */
8773 mono_mb_add_local (mb
, sig
->ret
);
8776 mono_mb_emit_icon (mb
, 0);
8777 mono_mb_emit_stloc (mb
, 2);
8779 /* fixme: howto handle this ? */
8782 /* FIXME: need a solution for the moving GC here */
8783 mono_mb_emit_ptr (mb
, this);
8786 g_assert_not_reached ();
8790 /* we first do all conversions */
8791 tmp_locals
= alloca (sizeof (int) * sig
->param_count
);
8792 for (i
= 0; i
< sig
->param_count
; i
++) {
8793 MonoType
*t
= sig
->params
[i
];
8796 case MONO_TYPE_OBJECT
:
8797 case MONO_TYPE_CLASS
:
8798 case MONO_TYPE_VALUETYPE
:
8799 case MONO_TYPE_ARRAY
:
8800 case MONO_TYPE_SZARRAY
:
8801 case MONO_TYPE_STRING
:
8802 tmp_locals
[i
] = emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
8811 emit_thread_interrupt_checkpoint (mb
);
8813 for (i
= 0; i
< sig
->param_count
; i
++) {
8814 MonoType
*t
= sig
->params
[i
];
8816 if (tmp_locals
[i
]) {
8818 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
8820 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
8823 mono_mb_emit_ldarg (mb
, i
);
8826 mono_mb_emit_managed_call (mb
, method
, NULL
);
8828 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
8829 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8832 if (!sig
->ret
->byref
) {
8833 switch (sig
->ret
->type
) {
8834 case MONO_TYPE_VOID
:
8836 case MONO_TYPE_BOOLEAN
:
8850 case MONO_TYPE_OBJECT
:
8851 mono_mb_emit_stloc (mb
, 3);
8853 case MONO_TYPE_STRING
:
8854 csig
->ret
= &mono_defaults
.int_class
->byval_arg
;
8855 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8857 case MONO_TYPE_VALUETYPE
:
8858 case MONO_TYPE_CLASS
:
8859 case MONO_TYPE_SZARRAY
:
8860 emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
8863 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
8864 g_assert_not_reached ();
8867 mono_mb_emit_stloc (mb
, 3);
8870 /* Convert byref arguments back */
8871 for (i
= 0; i
< sig
->param_count
; i
++) {
8872 MonoType
*t
= sig
->params
[i
];
8873 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
8875 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
8876 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8878 else if (t
->byref
) {
8880 case MONO_TYPE_CLASS
:
8881 case MONO_TYPE_VALUETYPE
:
8882 case MONO_TYPE_OBJECT
:
8883 emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8887 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
8888 /* The [Out] information is encoded in the delegate signature */
8890 case MONO_TYPE_SZARRAY
:
8891 case MONO_TYPE_CLASS
:
8892 case MONO_TYPE_VALUETYPE
:
8893 emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
8896 g_assert_not_reached ();
8901 if (m
->retobj_var
) {
8902 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
8903 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
8904 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
8907 if (!MONO_TYPE_IS_VOID(sig
->ret
))
8908 mono_mb_emit_ldloc (mb
, 3);
8909 mono_mb_emit_byte (mb
, CEE_RET
);
8915 * generates IL code to call managed methods from unmanaged code
8918 mono_marshal_get_managed_wrapper (MonoMethod
*method
, MonoClass
*delegate_klass
, MonoObject
*this)
8920 static MonoClass
*UnmanagedFunctionPointerAttribute
;
8921 MonoMethodSignature
*sig
, *csig
, *invoke_sig
;
8922 MonoMethodBuilder
*mb
;
8923 MonoMethod
*res
, *invoke
;
8924 MonoMarshalSpec
**mspecs
;
8925 MonoMethodPInvoke piinfo
;
8928 EmitMarshalContext m
;
8930 g_assert (method
!= NULL
);
8931 g_assert (!mono_method_signature (method
)->pinvoke
);
8934 * FIXME: Should cache the method+delegate type pair, since the same method
8935 * could be called with different delegates, thus different marshalling
8938 cache
= method
->klass
->image
->managed_wrapper_cache
;
8939 if (!this && (res
= mono_marshal_find_in_cache (cache
, method
)))
8942 invoke
= mono_class_get_method_from_name (delegate_klass
, "Invoke", mono_method_signature (method
)->param_count
);
8943 invoke_sig
= mono_method_signature (invoke
);
8945 mspecs
= g_new0 (MonoMarshalSpec
*, mono_method_signature (invoke
)->param_count
+ 1);
8946 mono_method_get_marshal_info (invoke
, mspecs
);
8948 sig
= mono_method_signature (method
);
8950 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
8953 /* we copy the signature, so that we can modify it */
8955 /* Need to free this later */
8956 csig
= mono_metadata_signature_dup (sig
);
8958 csig
= signature_dup (method
->klass
->image
, sig
);
8967 m
.image
= method
->klass
->image
;
8969 #ifdef PLATFORM_WIN32
8971 * Under windows, delegates passed to native code must use the STDCALL
8972 * calling convention.
8974 csig
->call_convention
= MONO_CALL_STDCALL
;
8977 /* Change default calling convention if needed */
8978 /* Why is this a modopt ? */
8979 if (invoke_sig
->ret
&& invoke_sig
->ret
->num_mods
) {
8980 for (i
= 0; i
< invoke_sig
->ret
->num_mods
; ++i
) {
8981 MonoClass
*cmod_class
= mono_class_get (delegate_klass
->image
, invoke_sig
->ret
->modifiers
[i
].token
);
8982 g_assert (cmod_class
);
8983 if ((cmod_class
->image
== mono_defaults
.corlib
) && !strcmp (cmod_class
->name_space
, "System.Runtime.CompilerServices")) {
8984 if (!strcmp (cmod_class
->name
, "CallConvCdecl"))
8985 csig
->call_convention
= MONO_CALL_C
;
8986 else if (!strcmp (cmod_class
->name
, "CallConvStdcall"))
8987 csig
->call_convention
= MONO_CALL_STDCALL
;
8988 else if (!strcmp (cmod_class
->name
, "CallConvFastcall"))
8989 csig
->call_convention
= MONO_CALL_FASTCALL
;
8990 else if (!strcmp (cmod_class
->name
, "CallConvThiscall"))
8991 csig
->call_convention
= MONO_CALL_THISCALL
;
8996 /* Handle the UnmanagedFunctionPointerAttribute */
8997 if (!UnmanagedFunctionPointerAttribute
)
8998 UnmanagedFunctionPointerAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
9000 /* The attribute is only available in Net 2.0 */
9001 if (UnmanagedFunctionPointerAttribute
) {
9002 MonoReflectionUnmanagedFunctionPointerAttribute
*attr
;
9003 MonoCustomAttrInfo
*cinfo
;
9006 * The pinvoke attributes are stored in a real custom attribute so we have to
9009 cinfo
= mono_custom_attrs_from_class (delegate_klass
);
9011 attr
= (MonoReflectionUnmanagedFunctionPointerAttribute
*)mono_custom_attrs_get_attr (cinfo
, UnmanagedFunctionPointerAttribute
);
9013 memset (&piinfo
, 0, sizeof (piinfo
));
9015 piinfo
.piflags
= (attr
->call_conv
<< 8) | (attr
->charset
? (attr
->charset
- 1) * 2 : 1) | attr
->set_last_error
;
9017 csig
->call_convention
= attr
->call_conv
- 1;
9020 mono_custom_attrs_free (cinfo
);
9024 mono_marshal_emit_managed_wrapper (mb
, invoke_sig
, mspecs
, &m
, method
, this);
9027 res
= mono_mb_create_and_cache (cache
, method
,
9028 mb
, csig
, sig
->param_count
+ 16);
9031 res
= mono_mb_create_method (mb
, csig
, sig
->param_count
+ 16);
9035 for (i
= mono_method_signature (invoke
)->param_count
; i
>= 0; i
--)
9037 mono_metadata_free_marshal_spec (mspecs
[i
]);
9040 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
9045 static MonoReflectionType
*
9046 type_from_handle (MonoType
*handle
)
9048 MonoDomain
*domain
= mono_domain_get ();
9049 MonoClass
*klass
= mono_class_from_mono_type (handle
);
9051 MONO_ARCH_SAVE_REGS
;
9053 mono_class_init (klass
);
9054 return mono_type_get_object (domain
, handle
);
9058 * mono_marshal_get_isinst:
9059 * @klass: the type of the field
9061 * This method generates a function which can be used to check if an object is
9062 * an instance of the given type, icluding the case where the object is a proxy.
9063 * The generated function has the following signature:
9064 * MonoObject* __isinst_wrapper_ (MonoObject *obj)
9067 mono_marshal_get_isinst (MonoClass
*klass
)
9069 static MonoMethodSignature
*isint_sig
= NULL
;
9072 int pos_was_ok
, pos_failed
, pos_end
, pos_end2
;
9074 MonoMethodBuilder
*mb
;
9076 cache
= klass
->image
->isinst_cache
;
9077 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9081 isint_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9082 isint_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9083 isint_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9084 isint_sig
->pinvoke
= 0;
9087 name
= g_strdup_printf ("__isinst_wrapper_%s", klass
->name
);
9088 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_ISINST
);
9091 mb
->method
->save_lmf
= 1;
9093 /* check if the object is a proxy that needs special cast */
9094 mono_mb_emit_ldarg (mb
, 0);
9095 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
9096 mono_mb_emit_op (mb
, CEE_MONO_CISINST
, klass
);
9098 /* The result of MONO_ISINST can be:
9099 0) the type check succeeded
9100 1) the type check did not succeed
9101 2) a CanCastTo call is needed */
9103 mono_mb_emit_byte (mb
, CEE_DUP
);
9104 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9106 mono_mb_emit_byte (mb
, CEE_LDC_I4_2
);
9107 pos_failed
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9109 /* get the real proxy from the transparent proxy*/
9111 mono_mb_emit_ldarg (mb
, 0);
9112 mono_mb_emit_managed_call (mb
, mono_marshal_get_proxy_cancast (klass
), NULL
);
9113 pos_end
= mono_mb_emit_branch (mb
, CEE_BR
);
9117 mono_mb_patch_addr (mb
, pos_failed
, mb
->pos
- (pos_failed
+ 4));
9118 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9119 pos_end2
= mono_mb_emit_branch (mb
, CEE_BR
);
9123 mono_mb_patch_addr (mb
, pos_was_ok
, mb
->pos
- (pos_was_ok
+ 4));
9124 mono_mb_emit_byte (mb
, CEE_POP
);
9125 mono_mb_emit_ldarg (mb
, 0);
9129 mono_mb_patch_addr (mb
, pos_end
, mb
->pos
- (pos_end
+ 4));
9130 mono_mb_patch_addr (mb
, pos_end2
, mb
->pos
- (pos_end2
+ 4));
9131 mono_mb_emit_byte (mb
, CEE_RET
);
9133 res
= mono_mb_create_and_cache (cache
, klass
, mb
, isint_sig
, isint_sig
->param_count
+ 16);
9140 * mono_marshal_get_castclass:
9141 * @klass: the type of the field
9143 * This method generates a function which can be used to cast an object to
9144 * an instance of the given type, icluding the case where the object is a proxy.
9145 * The generated function has the following signature:
9146 * MonoObject* __castclass_wrapper_ (MonoObject *obj)
9149 mono_marshal_get_castclass (MonoClass
*klass
)
9151 static MonoMethodSignature
*castclass_sig
= NULL
;
9154 int pos_was_ok
, pos_was_ok2
;
9156 MonoMethodBuilder
*mb
;
9158 cache
= klass
->image
->castclass_cache
;
9159 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9162 if (!castclass_sig
) {
9163 castclass_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9164 castclass_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9165 castclass_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9166 castclass_sig
->pinvoke
= 0;
9169 name
= g_strdup_printf ("__castclass_wrapper_%s", klass
->name
);
9170 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_CASTCLASS
);
9173 mb
->method
->save_lmf
= 1;
9175 /* check if the object is a proxy that needs special cast */
9176 mono_mb_emit_ldarg (mb
, 0);
9177 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
9178 mono_mb_emit_op (mb
, CEE_MONO_CCASTCLASS
, klass
);
9180 /* The result of MONO_ISINST can be:
9181 0) the cast is valid
9182 1) cast of unknown proxy type
9183 or an exception if the cast is is invalid
9186 pos_was_ok
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9188 /* get the real proxy from the transparent proxy*/
9190 mono_mb_emit_ldarg (mb
, 0);
9191 mono_mb_emit_managed_call (mb
, mono_marshal_get_proxy_cancast (klass
), NULL
);
9192 pos_was_ok2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
9195 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
9198 mono_mb_patch_addr (mb
, pos_was_ok
, mb
->pos
- (pos_was_ok
+ 4));
9199 mono_mb_patch_addr (mb
, pos_was_ok2
, mb
->pos
- (pos_was_ok2
+ 4));
9200 mono_mb_emit_ldarg (mb
, 0);
9203 mono_mb_emit_byte (mb
, CEE_RET
);
9205 res
= mono_mb_create_and_cache (cache
, klass
, mb
, castclass_sig
, castclass_sig
->param_count
+ 16);
9212 mono_marshal_get_proxy_cancast (MonoClass
*klass
)
9214 static MonoMethodSignature
*isint_sig
= NULL
;
9217 int pos_failed
, pos_end
;
9219 MonoMethod
*can_cast_to
;
9220 MonoMethodDesc
*desc
;
9221 MonoMethodBuilder
*mb
;
9223 cache
= klass
->image
->proxy_isinst_cache
;
9224 if ((res
= mono_marshal_find_in_cache (cache
, klass
)))
9228 isint_sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1);
9229 isint_sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9230 isint_sig
->ret
= &mono_defaults
.object_class
->byval_arg
;
9231 isint_sig
->pinvoke
= 0;
9234 name
= g_strdup_printf ("__proxy_isinst_wrapper_%s", klass
->name
);
9235 mb
= mono_mb_new (mono_defaults
.object_class
, name
, MONO_WRAPPER_PROXY_ISINST
);
9238 mb
->method
->save_lmf
= 1;
9240 /* get the real proxy from the transparent proxy*/
9241 mono_mb_emit_ldarg (mb
, 0);
9242 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
9243 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
9245 /* get the reflection type from the type handle */
9246 mono_mb_emit_ptr (mb
, &klass
->byval_arg
);
9247 mono_mb_emit_icall (mb
, type_from_handle
);
9249 mono_mb_emit_ldarg (mb
, 0);
9251 /* make the call to CanCastTo (type, ob) */
9252 desc
= mono_method_desc_new ("IRemotingTypeInfo:CanCastTo", FALSE
);
9253 can_cast_to
= mono_method_desc_search_in_class (desc
, mono_defaults
.iremotingtypeinfo_class
);
9254 g_assert (can_cast_to
);
9255 mono_method_desc_free (desc
);
9256 mono_mb_emit_op (mb
, CEE_CALLVIRT
, can_cast_to
);
9258 pos_failed
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9260 /* Upgrade the proxy vtable by calling: mono_upgrade_remote_class_wrapper (type, ob)*/
9261 mono_mb_emit_ptr (mb
, &klass
->byval_arg
);
9262 mono_mb_emit_icall (mb
, type_from_handle
);
9263 mono_mb_emit_ldarg (mb
, 0);
9265 mono_mb_emit_icall (mb
, mono_upgrade_remote_class_wrapper
);
9266 emit_thread_interrupt_checkpoint (mb
);
9268 mono_mb_emit_ldarg (mb
, 0);
9269 pos_end
= mono_mb_emit_branch (mb
, CEE_BR
);
9273 mono_mb_patch_addr (mb
, pos_failed
, mb
->pos
- (pos_failed
+ 4));
9274 mono_mb_emit_byte (mb
, CEE_LDNULL
);
9278 mono_mb_patch_addr (mb
, pos_end
, mb
->pos
- (pos_end
+ 4));
9279 mono_mb_emit_byte (mb
, CEE_RET
);
9281 res
= mono_mb_create_and_cache (cache
, klass
, mb
, isint_sig
, isint_sig
->param_count
+ 16);
9288 mono_upgrade_remote_class_wrapper (MonoReflectionType
*rtype
, MonoTransparentProxy
*tproxy
)
9291 MonoDomain
*domain
= ((MonoObject
*)tproxy
)->vtable
->domain
;
9292 klass
= mono_class_from_mono_type (rtype
->type
);
9293 mono_upgrade_remote_class (domain
, (MonoObject
*)tproxy
, klass
);
9297 * mono_marshal_get_struct_to_ptr:
9300 * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
9303 mono_marshal_get_struct_to_ptr (MonoClass
*klass
)
9305 MonoMethodBuilder
*mb
;
9306 static MonoMethod
*stoptr
= NULL
;
9309 g_assert (klass
!= NULL
);
9311 mono_marshal_load_type_info (klass
);
9313 if (klass
->marshal_info
->str_to_ptr
)
9314 return klass
->marshal_info
->str_to_ptr
;
9317 stoptr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "StructureToPtr", 3);
9320 mb
= mono_mb_new (klass
, stoptr
->name
, MONO_WRAPPER_UNKNOWN
);
9322 if (klass
->blittable
) {
9323 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9324 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9325 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9326 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9327 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9328 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9331 /* allocate local 0 (pointer) src_ptr */
9332 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9333 /* allocate local 1 (pointer) dst_ptr */
9334 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9335 /* allocate local 2 (boolean) delete_old */
9336 mono_mb_add_local (mb
, &mono_defaults
.boolean_class
->byval_arg
);
9337 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
9338 mono_mb_emit_stloc (mb
, 2);
9340 /* initialize src_ptr to point to the start of object data */
9341 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9342 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9343 mono_mb_emit_stloc (mb
, 0);
9345 /* initialize dst_ptr */
9346 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9347 mono_mb_emit_stloc (mb
, 1);
9349 emit_struct_conv (mb
, klass
, FALSE
);
9352 mono_mb_emit_byte (mb
, CEE_RET
);
9354 res
= mono_mb_create_method (mb
, mono_method_signature (stoptr
), 0);
9357 klass
->marshal_info
->str_to_ptr
= res
;
9362 * mono_marshal_get_ptr_to_struct:
9365 * generates IL code for PtrToStructure (IntPtr src, object structure)
9368 mono_marshal_get_ptr_to_struct (MonoClass
*klass
)
9370 MonoMethodBuilder
*mb
;
9371 static MonoMethodSignature
*ptostr
= NULL
;
9374 g_assert (klass
!= NULL
);
9376 mono_marshal_load_type_info (klass
);
9378 if (klass
->marshal_info
->ptr_to_str
)
9379 return klass
->marshal_info
->ptr_to_str
;
9382 /* Create the signature corresponding to
9383 static void PtrToStructure (IntPtr ptr, object structure);
9384 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9385 ptostr
= mono_create_icall_signature ("void ptr object");
9387 mb
= mono_mb_new (klass
, "PtrToStructure", MONO_WRAPPER_UNKNOWN
);
9389 if (klass
->blittable
) {
9390 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9391 mono_mb_emit_ldflda (mb
, sizeof (MonoObject
));
9392 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9393 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
9394 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9395 mono_mb_emit_byte (mb
, CEE_CPBLK
);
9398 /* allocate local 0 (pointer) src_ptr */
9399 mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9400 /* allocate local 1 (pointer) dst_ptr */
9401 mono_mb_add_local (mb
, &klass
->this_arg
);
9403 /* initialize src_ptr to point to the start of object data */
9404 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
9405 mono_mb_emit_stloc (mb
, 0);
9407 /* initialize dst_ptr */
9408 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
9409 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
9410 mono_mb_emit_stloc (mb
, 1);
9412 emit_struct_conv (mb
, klass
, TRUE
);
9415 mono_mb_emit_byte (mb
, CEE_RET
);
9417 res
= mono_mb_create_method (mb
, ptostr
, 0);
9420 klass
->marshal_info
->ptr_to_str
= res
;
9425 * generates IL code for the synchronized wrapper: the generated method
9426 * calls METHOD while locking 'this' or the parent type.
9429 mono_marshal_get_synchronized_wrapper (MonoMethod
*method
)
9431 static MonoMethod
*enter_method
, *exit_method
;
9432 MonoMethodSignature
*sig
;
9433 MonoExceptionClause
*clause
;
9434 MonoMethodHeader
*header
;
9435 MonoMethodBuilder
*mb
;
9438 int i
, pos
, this_local
, ret_local
= 0;
9442 if (method
->wrapper_type
== MONO_WRAPPER_SYNCHRONIZED
)
9445 cache
= method
->klass
->image
->synchronized_cache
;
9446 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9449 sig
= signature_dup (method
->klass
->image
, mono_method_signature (method
));
9452 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_SYNCHRONIZED
);
9455 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9456 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
9459 this_local
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
9461 mono_loader_lock ();
9462 clause
= mono_mempool_alloc0 (method
->klass
->image
->mempool
, sizeof (MonoExceptionClause
));
9463 mono_loader_unlock ();
9464 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
9466 if (!enter_method
) {
9467 MonoMethodDesc
*desc
;
9469 desc
= mono_method_desc_new ("Monitor:Enter", FALSE
);
9470 enter_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9471 g_assert (enter_method
);
9472 mono_method_desc_free (desc
);
9473 desc
= mono_method_desc_new ("Monitor:Exit", FALSE
);
9474 exit_method
= mono_method_desc_search_in_class (desc
, mono_defaults
.monitor_class
);
9475 g_assert (exit_method
);
9476 mono_method_desc_free (desc
);
9479 /* Push this or the type object */
9480 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
9482 * GetTypeFromHandle isn't called as a managed method because it has
9483 * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
9484 * transformed into something else by the JIT.
9486 mono_mb_emit_ptr (mb
, &method
->klass
->byval_arg
);
9487 mono_mb_emit_icall (mb
, type_from_handle
);
9490 mono_mb_emit_ldarg (mb
, 0);
9491 mono_mb_emit_stloc (mb
, this_local
);
9493 /* Call Monitor::Enter() */
9494 mono_mb_emit_ldloc (mb
, this_local
);
9495 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
9497 clause
->try_offset
= mb
->pos
;
9499 /* Call the method */
9501 mono_mb_emit_ldarg (mb
, 0);
9502 for (i
= 0; i
< sig
->param_count
; i
++)
9503 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
9505 /* this is needed to avoid recursion */
9506 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
9507 mono_mb_emit_op (mb
, CEE_LDFTN
, method
);
9508 mono_mb_emit_calli (mb
, mono_method_signature (method
));
9510 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9511 mono_mb_emit_stloc (mb
, ret_local
);
9513 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
9515 clause
->try_len
= mb
->pos
- clause
->try_offset
;
9516 clause
->handler_offset
= mb
->pos
;
9518 /* Call Monitor::Exit() */
9519 mono_mb_emit_ldloc (mb
, this_local
);
9520 /* mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */
9521 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
9522 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
9524 clause
->handler_len
= mb
->pos
- clause
->handler_offset
;
9526 mono_mb_patch_branch (mb
, pos
);
9527 if (!MONO_TYPE_IS_VOID (sig
->ret
))
9528 mono_mb_emit_ldloc (mb
, ret_local
);
9529 mono_mb_emit_byte (mb
, CEE_RET
);
9531 res
= mono_mb_create_and_cache (cache
, method
,
9532 mb
, sig
, sig
->param_count
+ 16);
9535 header
= ((MonoMethodNormal
*)res
)->header
;
9536 header
->num_clauses
= 1;
9537 header
->clauses
= clause
;
9544 * the returned method calls 'method' unboxing the this argument
9547 mono_marshal_get_unbox_wrapper (MonoMethod
*method
)
9549 MonoMethodSignature
*sig
= mono_method_signature (method
);
9551 MonoMethodBuilder
*mb
;
9555 cache
= method
->klass
->image
->unbox_wrapper_cache
;
9556 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
9559 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_UNBOX
);
9561 g_assert (sig
->hasthis
);
9563 mono_mb_emit_ldarg (mb
, 0);
9564 mono_mb_emit_icon (mb
, sizeof (MonoObject
));
9565 mono_mb_emit_byte (mb
, CEE_ADD
);
9566 for (i
= 0; i
< sig
->param_count
; ++i
)
9567 mono_mb_emit_ldarg (mb
, i
+ 1);
9568 mono_mb_emit_managed_call (mb
, method
, NULL
);
9569 mono_mb_emit_byte (mb
, CEE_RET
);
9571 res
= mono_mb_create_and_cache (cache
, method
,
9572 mb
, sig
, sig
->param_count
+ 16);
9575 /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
9581 mono_marshal_get_stelemref ()
9583 static MonoMethod
* ret
= NULL
;
9584 MonoMethodSignature
*sig
;
9585 MonoMethodBuilder
*mb
;
9587 guint32 b1
, b2
, b3
, b4
;
9590 int array_slot_addr
;
9595 mb
= mono_mb_new (mono_defaults
.object_class
, "stelemref", MONO_WRAPPER_STELEMREF
);
9598 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
9600 /* void stelemref (void* array, int idx, void* value) */
9601 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9602 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9603 sig
->params
[1] = &mono_defaults
.int_class
->byval_arg
; /* this is a natural sized int */
9604 sig
->params
[2] = &mono_defaults
.object_class
->byval_arg
;
9606 aklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9607 vklass
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9608 array_slot_addr
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->this_arg
);
9612 <ldelema (bound check)>
9616 aklass = array->vtable->klass->element_class;
9617 vklass = value->vtable->klass;
9619 if (vklass->idepth < aklass->idepth)
9622 if (vklass->supertypes [aklass->idepth - 1] != aklass)
9626 *array_slot_addr = value;
9630 if (mono_object_isinst (value, aklass))
9633 throw new ArrayTypeMismatchException ();
9636 /* ldelema (implicit bound check) */
9637 mono_mb_emit_ldarg (mb
, 0);
9638 mono_mb_emit_ldarg (mb
, 1);
9639 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
9640 mono_mb_emit_stloc (mb
, array_slot_addr
);
9642 /* if (!value) goto do_store */
9643 mono_mb_emit_ldarg (mb
, 2);
9644 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
9646 /* aklass = array->vtable->klass->element_class */
9647 mono_mb_emit_ldarg (mb
, 0);
9648 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
9649 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9650 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
9651 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9652 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, element_class
));
9653 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9654 mono_mb_emit_stloc (mb
, aklass
);
9656 /* vklass = value->vtable->klass */
9657 mono_mb_emit_ldarg (mb
, 2);
9658 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoObject
, vtable
));
9659 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9660 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoVTable
, klass
));
9661 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9662 mono_mb_emit_stloc (mb
, vklass
);
9664 /* if (vklass->idepth < aklass->idepth) goto failue */
9665 mono_mb_emit_ldloc (mb
, vklass
);
9666 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
9667 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9669 mono_mb_emit_ldloc (mb
, aklass
);
9670 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
9671 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9673 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
9675 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
9676 mono_mb_emit_ldloc (mb
, vklass
);
9677 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, supertypes
));
9678 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9680 mono_mb_emit_ldloc (mb
, aklass
);
9681 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoClass
, idepth
));
9682 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
9683 mono_mb_emit_icon (mb
, 1);
9684 mono_mb_emit_byte (mb
, CEE_SUB
);
9685 mono_mb_emit_icon (mb
, sizeof (void*));
9686 mono_mb_emit_byte (mb
, CEE_MUL
);
9687 mono_mb_emit_byte (mb
, CEE_ADD
);
9688 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9690 mono_mb_emit_ldloc (mb
, aklass
);
9692 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
9696 mono_mb_patch_branch (mb
, b1
);
9697 mono_mb_emit_ldloc (mb
, array_slot_addr
);
9698 mono_mb_emit_ldarg (mb
, 2);
9699 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
9701 mono_mb_emit_byte (mb
, CEE_RET
);
9704 mono_mb_patch_branch (mb
, b2
);
9705 mono_mb_patch_branch (mb
, b3
);
9707 mono_mb_emit_ldarg (mb
, 2);
9708 mono_mb_emit_ldloc (mb
, aklass
);
9709 mono_mb_emit_icall (mb
, mono_object_isinst
);
9711 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
9712 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
9713 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
9715 mono_mb_emit_byte (mb
, CEE_RET
);
9716 ret
= mono_mb_create_method (mb
, sig
, 4);
9727 /* LOCKING: vars accessed under the marshal lock */
9728 static ArrayElemAddr
*elem_addr_cache
= NULL
;
9729 static int elem_addr_cache_size
= 0;
9730 static int elem_addr_cache_next
= 0;
9733 * mono_marshal_get_array_address:
9734 * @rank: rank of the array type
9735 * @elem_size: size in bytes of an element of an array.
9737 * Returns a MonoMethd that implements the code to get the address
9738 * of an element in a multi-dimenasional array of @rank dimensions.
9739 * The returned method takes an array as the first argument and then
9740 * @rank indexes for the @rank dimensions.
9743 mono_marshal_get_array_address (int rank
, int elem_size
)
9746 MonoMethodBuilder
*mb
;
9747 MonoMethodSignature
*sig
;
9748 int i
, bounds
, ind
, realidx
;
9749 int branch_pos
, *branch_positions
;
9753 mono_marshal_lock ();
9754 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
9755 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
9756 ret
= elem_addr_cache
[i
].method
;
9760 mono_marshal_unlock ();
9764 branch_positions
= g_new0 (int, rank
);
9766 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 1 + rank
);
9768 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
9769 sig
->ret
= &mono_defaults
.int_class
->byval_arg
;
9770 sig
->params
[0] = &mono_defaults
.object_class
->byval_arg
;
9771 for (i
= 0; i
< rank
; ++i
) {
9772 sig
->params
[i
+ 1] = &mono_defaults
.int32_class
->byval_arg
;
9775 mb
= mono_mb_new (mono_defaults
.object_class
, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED
);
9777 bounds
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
9778 ind
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
9779 realidx
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
9781 /* bounds = array->bounds; */
9782 mono_mb_emit_ldarg (mb
, 0);
9783 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoArray
, bounds
));
9784 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
9785 mono_mb_emit_stloc (mb
, bounds
);
9787 /* ind is the overall element index, realidx is the partial index in a single dimension */
9788 /* ind = idx0 - bounds [0].lower_bound */
9789 mono_mb_emit_ldarg (mb
, 1);
9790 mono_mb_emit_ldloc (mb
, bounds
);
9791 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
9792 mono_mb_emit_byte (mb
, CEE_ADD
);
9793 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
9794 mono_mb_emit_byte (mb
, CEE_SUB
);
9795 mono_mb_emit_stloc (mb
, ind
);
9796 /* if (ind >= bounds [0].length) goto exeception; */
9797 mono_mb_emit_ldloc (mb
, ind
);
9798 mono_mb_emit_ldloc (mb
, bounds
);
9799 mono_mb_emit_icon (mb
, G_STRUCT_OFFSET (MonoArrayBounds
, length
));
9800 mono_mb_emit_byte (mb
, CEE_ADD
);
9801 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
9802 /* note that we use unsigned comparison */
9803 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
9805 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
9806 * We could also decide to ignore the passed elem_size and get it
9807 * from the array object, to reduce the number of methods we generate:
9808 * the additional cost is 3 memory loads and a non-immediate mul.
9810 for (i
= 1; i
< rank
; ++i
) {
9811 /* realidx = idxi - bounds [i].lower_bound */
9812 mono_mb_emit_ldarg (mb
, 1 + i
);
9813 mono_mb_emit_ldloc (mb
, bounds
);
9814 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + G_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
9815 mono_mb_emit_byte (mb
, CEE_ADD
);
9816 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
9817 mono_mb_emit_byte (mb
, CEE_SUB
);
9818 mono_mb_emit_stloc (mb
, realidx
);
9819 /* if (realidx >= bounds [i].length) goto exeception; */
9820 mono_mb_emit_ldloc (mb
, realidx
);
9821 mono_mb_emit_ldloc (mb
, bounds
);
9822 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + G_STRUCT_OFFSET (MonoArrayBounds
, length
));
9823 mono_mb_emit_byte (mb
, CEE_ADD
);
9824 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
9825 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
9826 /* ind = ind * bounds [i].length + realidx */
9827 mono_mb_emit_ldloc (mb
, ind
);
9828 mono_mb_emit_ldloc (mb
, bounds
);
9829 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + G_STRUCT_OFFSET (MonoArrayBounds
, length
));
9830 mono_mb_emit_byte (mb
, CEE_ADD
);
9831 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
9832 mono_mb_emit_byte (mb
, CEE_MUL
);
9833 mono_mb_emit_ldloc (mb
, realidx
);
9834 mono_mb_emit_byte (mb
, CEE_ADD
);
9835 mono_mb_emit_stloc (mb
, ind
);
9838 /* return array->vector + ind * element_size */
9839 mono_mb_emit_ldarg (mb
, 0);
9840 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoArray
, vector
));
9841 mono_mb_emit_ldloc (mb
, ind
);
9842 mono_mb_emit_icon (mb
, elem_size
);
9843 mono_mb_emit_byte (mb
, CEE_MUL
);
9844 mono_mb_emit_byte (mb
, CEE_ADD
);
9845 mono_mb_emit_byte (mb
, CEE_RET
);
9847 /* patch the branches to get here and throw */
9848 for (i
= 1; i
< rank
; ++i
) {
9849 mono_mb_patch_branch (mb
, branch_positions
[i
]);
9851 mono_mb_patch_branch (mb
, branch_pos
);
9852 /* throw exception */
9853 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
9855 g_free (branch_positions
);
9856 ret
= mono_mb_create_method (mb
, sig
, 4);
9859 /* cache the result */
9861 mono_marshal_lock ();
9862 for (i
= 0; i
< elem_addr_cache_next
; ++i
) {
9863 if (elem_addr_cache
[i
].rank
== rank
&& elem_addr_cache
[i
].elem_size
== elem_size
) {
9864 /* FIXME: free ret */
9865 ret
= elem_addr_cache
[i
].method
;
9871 if (elem_addr_cache_next
>= elem_addr_cache_size
) {
9872 int new_size
= elem_addr_cache_size
+ 4;
9873 ArrayElemAddr
*new_array
= g_new0 (ArrayElemAddr
, new_size
);
9874 memcpy (new_array
, elem_addr_cache
, elem_addr_cache_size
* sizeof (ArrayElemAddr
));
9875 g_free (elem_addr_cache
);
9876 elem_addr_cache
= new_array
;
9877 elem_addr_cache_size
= new_size
;
9879 elem_addr_cache
[elem_addr_cache_next
].rank
= rank
;
9880 elem_addr_cache
[elem_addr_cache_next
].elem_size
= elem_size
;
9881 elem_addr_cache
[elem_addr_cache_next
].method
= ret
;
9883 mono_marshal_unlock ();
9888 mono_marshal_get_write_barrier (void)
9890 static MonoMethod
* ret
= NULL
;
9891 MonoMethodSignature
*sig
;
9892 MonoMethodBuilder
*mb
;
9898 mb
= mono_mb_new (mono_defaults
.object_class
, "writebarrier", MONO_WRAPPER_WRITE_BARRIER
);
9900 sig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 2);
9902 /* void writebarrier (MonoObject** addr, MonoObject* obj) */
9903 sig
->ret
= &mono_defaults
.void_class
->byval_arg
;
9904 sig
->params
[0] = &mono_defaults
.object_class
->this_arg
;
9905 sig
->params
[1] = &mono_defaults
.object_class
->byval_arg
;
9907 /* just the store right now: add an hook for the GC to use, maybe something
9908 * that can be used for stelemref as well
9909 * We need a write barrier variant to be used with struct copies as well, though
9910 * there are also other approaches possible, like writing a wrapper specific to
9911 * the struct or to the reference pattern in the struct...
9912 * Depending on the GC, we may want variants that take the object we store to
9913 * when it is available.
9915 mono_mb_emit_ldarg (mb
, 0);
9916 mono_mb_emit_ldarg (mb
, 1);
9917 mono_mb_emit_icall (mb
, mono_gc_wbarrier_generic_store
);
9918 /*mono_mb_emit_byte (mb, CEE_STIND_REF);*/
9920 mono_mb_emit_byte (mb
, CEE_RET
);
9922 ret
= mono_mb_create_method (mb
, sig
, max_stack
);
9928 mono_marshal_alloc (gulong size
)
9932 #ifdef PLATFORM_WIN32
9933 res
= CoTaskMemAlloc (size
);
9935 res
= g_try_malloc ((gulong
)size
);
9937 mono_gc_out_of_memory ((gulong
)size
);
9943 mono_marshal_free (gpointer ptr
)
9945 #ifdef PLATFORM_WIN32
9946 CoTaskMemFree (ptr
);
9953 mono_marshal_free_array (gpointer
*ptr
, int size
)
9960 for (i
= 0; i
< size
; i
++)
9966 mono_marshal_string_to_utf16 (MonoString
*s
)
9968 return s
? mono_string_chars (s
) : NULL
;
9972 mono_marshal_string_to_utf16_copy (MonoString
*s
)
9977 gunichar2
*res
= mono_marshal_alloc ((mono_string_length (s
) * 2) + 2);
9978 memcpy (res
, mono_string_chars (s
), mono_string_length (s
) * 2);
9979 res
[mono_string_length (s
)] = 0;
9985 * mono_marshal_set_last_error:
9987 * This function is invoked to set the last error value from a P/Invoke call
9988 * which has SetLastError set.
9991 mono_marshal_set_last_error (void)
9994 TlsSetValue (last_error_tls_id
, GINT_TO_POINTER (GetLastError ()));
9996 TlsSetValue (last_error_tls_id
, GINT_TO_POINTER (errno
));
10001 mono_marshal_set_last_error_windows (int error
)
10004 TlsSetValue (last_error_tls_id
, GINT_TO_POINTER (error
));
10009 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray
*src
, gint32 start_index
,
10010 gpointer dest
, gint32 length
)
10015 MONO_ARCH_SAVE_REGS
;
10017 MONO_CHECK_ARG_NULL (src
);
10018 MONO_CHECK_ARG_NULL (dest
);
10020 if (src
->obj
.vtable
->klass
->rank
!= 1)
10021 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10022 if (start_index
< 0)
10023 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10025 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10026 if (start_index
+ length
> mono_array_length (src
))
10027 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10029 element_size
= mono_array_element_size (src
->obj
.vtable
->klass
);
10031 /* no references should be involved */
10032 source_addr
= mono_array_addr_with_size (src
, element_size
, start_index
);
10034 memcpy (dest
, source_addr
, length
* element_size
);
10038 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src
, gint32 start_index
,
10039 MonoArray
*dest
, gint32 length
)
10044 MONO_ARCH_SAVE_REGS
;
10046 MONO_CHECK_ARG_NULL (src
);
10047 MONO_CHECK_ARG_NULL (dest
);
10049 if (dest
->obj
.vtable
->klass
->rank
!= 1)
10050 mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10051 if (start_index
< 0)
10052 mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10054 mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10055 if (start_index
+ length
> mono_array_length (dest
))
10056 mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10058 element_size
= mono_array_element_size (dest
->obj
.vtable
->klass
);
10060 /* no references should be involved */
10061 dest_addr
= mono_array_addr_with_size (dest
, element_size
, start_index
);
10063 memcpy (dest_addr
, src
, length
* element_size
);
10066 #if NO_UNALIGNED_ACCESS
10067 #define RETURN_UNALIGNED(type, addr) \
10070 memcpy(&val, p + offset, sizeof(val)); \
10073 #define WRITE_UNALIGNED(type, addr, val) \
10074 memcpy(addr, &val, sizeof(type))
10076 #define RETURN_UNALIGNED(type, addr) \
10077 return *(type*)(p + offset);
10078 #define WRITE_UNALIGNED(type, addr, val) \
10079 (*(type *)(addr) = (val))
10083 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr
, gint32 offset
)
10087 MONO_ARCH_SAVE_REGS
;
10089 RETURN_UNALIGNED(gpointer
, p
+ offset
);
10093 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr
, gint32 offset
)
10097 MONO_ARCH_SAVE_REGS
;
10099 return *(unsigned char*)(p
+ offset
);
10103 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr
, gint32 offset
)
10107 MONO_ARCH_SAVE_REGS
;
10109 RETURN_UNALIGNED(gint16
, p
+ offset
);
10113 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr
, gint32 offset
)
10117 MONO_ARCH_SAVE_REGS
;
10119 RETURN_UNALIGNED(gint32
, p
+ offset
);
10123 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr
, gint32 offset
)
10127 MONO_ARCH_SAVE_REGS
;
10129 RETURN_UNALIGNED(gint64
, p
+ offset
);
10133 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr
, gint32 offset
, unsigned char val
)
10137 MONO_ARCH_SAVE_REGS
;
10139 *(unsigned char*)(p
+ offset
) = val
;
10143 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr
, gint32 offset
, gpointer val
)
10147 MONO_ARCH_SAVE_REGS
;
10149 WRITE_UNALIGNED(gpointer
, p
+ offset
, val
);
10153 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr
, gint32 offset
, gint16 val
)
10157 MONO_ARCH_SAVE_REGS
;
10159 WRITE_UNALIGNED(gint16
, p
+ offset
, val
);
10163 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr
, gint32 offset
, gint32 val
)
10167 MONO_ARCH_SAVE_REGS
;
10169 WRITE_UNALIGNED(gint32
, p
+ offset
, val
);
10173 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr
, gint32 offset
, gint64 val
)
10177 MONO_ARCH_SAVE_REGS
;
10179 WRITE_UNALIGNED(gint64
, p
+ offset
, val
);
10183 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr
)
10185 MONO_ARCH_SAVE_REGS
;
10190 return mono_string_new (mono_domain_get (), ptr
);
10194 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr
, gint32 len
)
10196 MONO_ARCH_SAVE_REGS
;
10199 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10200 g_assert_not_reached ();
10203 return mono_string_new_len (mono_domain_get (), ptr
, len
);
10208 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16
*ptr
)
10210 MonoDomain
*domain
= mono_domain_get ();
10214 MONO_ARCH_SAVE_REGS
;
10222 return mono_string_new_utf16 (domain
, ptr
, len
);
10226 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16
*ptr
, gint32 len
)
10228 MonoDomain
*domain
= mono_domain_get ();
10230 MONO_ARCH_SAVE_REGS
;
10233 mono_raise_exception (mono_get_exception_argument_null ("ptr"));
10234 g_assert_not_reached ();
10237 return mono_string_new_utf16 (domain
, ptr
, len
);
10242 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr
)
10244 MONO_ARCH_SAVE_REGS
;
10246 return mono_string_from_bstr(ptr
);
10250 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString
* ptr
)
10252 MONO_ARCH_SAVE_REGS
;
10254 return mono_string_to_bstr(ptr
);
10259 int (STDCALL
*QueryInterface
)(gpointer pUnk
, gpointer riid
, gpointer
* ppv
);
10260 int (STDCALL
*AddRef
)(gpointer pUnk
);
10261 int (STDCALL
*Release
)(gpointer pUnk
);
10265 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr
)
10267 MONO_ARCH_SAVE_REGS
;
10269 mono_free_bstr (ptr
);
10273 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk
)
10276 return (*(MonoIUnknown
**)pUnk
)->AddRef(pUnk
);
10280 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk
, gpointer riid
, gpointer
* ppv
)
10283 return (*(MonoIUnknown
**)pUnk
)->QueryInterface(pUnk
, riid
, ppv
);
10287 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk
)
10290 return (*(MonoIUnknown
**)pUnk
)->Release(pUnk
);
10294 cominterop_get_idispatch_for_object (MonoObject
* object
)
10299 if (cominterop_object_is_rcw (object
)) {
10300 return cominterop_get_interface (((MonoComInteropProxy
*)((MonoTransparentProxy
*)object
)->rp
)->com_object
,
10301 mono_defaults
.idispatch_class
, TRUE
);
10304 return cominterop_get_ccw (object
, mono_defaults
.idispatch_class
);
10309 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject
* object
)
10314 if (cominterop_object_is_rcw (object
)) {
10315 MonoClass
*klass
= NULL
;
10316 MonoRealProxy
* real_proxy
= NULL
;
10319 klass
= mono_object_class (object
);
10320 if (klass
!= mono_defaults
.transparent_proxy_class
) {
10321 g_assert_not_reached ();
10325 real_proxy
= ((MonoTransparentProxy
*)object
)->rp
;
10327 g_assert_not_reached ();
10331 klass
= mono_object_class (real_proxy
);
10332 if (klass
!= mono_defaults
.com_interop_proxy_class
) {
10333 g_assert_not_reached ();
10337 if (!((MonoComInteropProxy
*)real_proxy
)->com_object
) {
10338 g_assert_not_reached ();
10342 return ((MonoComInteropProxy
*)real_proxy
)->com_object
->iunknown
;
10345 return cominterop_get_ccw (object
, mono_defaults
.iunknown_class
);
10350 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk
)
10352 MonoObject
* object
= NULL
;
10357 /* see if it is a CCW */
10358 object
= cominterop_get_ccw_object ((MonoCCWInterface
*)pUnk
, TRUE
);
10364 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject
* object
)
10366 return cominterop_get_idispatch_for_object (object
);
10370 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject
* object
, MonoReflectionType
* type
)
10372 MonoClass
* klass
= NULL
;
10375 g_assert (type
->type
);
10376 klass
= mono_type_get_class (type
->type
);
10378 itf
= cominterop_get_ccw (object
, klass
);
10385 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject
* object
)
10387 return (MonoBoolean
)cominterop_object_is_rcw (object
);
10391 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject
* object
)
10393 MonoComInteropProxy
* proxy
= NULL
;
10394 gint32 ref_count
= 0;
10397 g_assert (cominterop_object_is_rcw (object
));
10399 proxy
= (MonoComInteropProxy
*)((MonoTransparentProxy
*)object
)->rp
;
10402 ref_count
= InterlockedDecrement (&proxy
->ref_count
);
10403 g_assert (ref_count
>= 0);
10405 if (ref_count
== 0)
10406 ves_icall_System_ComObject_ReleaseInterfaces (proxy
->com_object
);
10412 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod
*m
)
10414 MONO_ARCH_SAVE_REGS
;
10416 return cominterop_get_com_slot_for_method (m
->method
);
10420 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
10422 MONO_ARCH_SAVE_REGS
;
10424 return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id
)));
10428 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType
*rtype
)
10434 MONO_ARCH_SAVE_REGS
;
10436 MONO_CHECK_ARG_NULL (rtype
);
10438 type
= rtype
->type
;
10439 klass
= mono_class_from_mono_type (type
);
10440 layout
= (klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
);
10442 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
10444 MonoException
*exc
;
10446 msg
= g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass
->name
);
10447 exc
= mono_get_exception_argument ("t", msg
);
10449 mono_raise_exception (exc
);
10453 return mono_class_native_size (klass
, NULL
);
10457 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject
*obj
, gpointer dst
, MonoBoolean delete_old
)
10459 MonoMethod
*method
;
10462 MONO_ARCH_SAVE_REGS
;
10464 MONO_CHECK_ARG_NULL (obj
);
10465 MONO_CHECK_ARG_NULL (dst
);
10467 method
= mono_marshal_get_struct_to_ptr (obj
->vtable
->klass
);
10471 pa
[2] = &delete_old
;
10473 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
10477 ptr_to_structure (gpointer src
, MonoObject
*dst
)
10479 MonoMethod
*method
;
10482 method
= mono_marshal_get_ptr_to_struct (dst
->vtable
->klass
);
10487 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
10491 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src
, MonoObject
*dst
)
10495 MONO_ARCH_SAVE_REGS
;
10497 MONO_CHECK_ARG_NULL (src
);
10498 MONO_CHECK_ARG_NULL (dst
);
10500 t
= mono_type_get_underlying_type (mono_class_get_type (dst
->vtable
->klass
));
10502 if (t
->type
== MONO_TYPE_VALUETYPE
) {
10503 MonoException
*exc
;
10506 tmp
= g_strdup_printf ("Destination is a boxed value type.");
10507 exc
= mono_get_exception_argument ("dst", tmp
);
10510 mono_raise_exception (exc
);
10514 ptr_to_structure (src
, dst
);
10518 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src
, MonoReflectionType
*type
)
10520 MonoDomain
*domain
= mono_domain_get ();
10523 MONO_ARCH_SAVE_REGS
;
10525 MONO_CHECK_ARG_NULL (src
);
10526 MONO_CHECK_ARG_NULL (type
);
10528 res
= mono_object_new (domain
, mono_class_from_mono_type (type
->type
));
10530 ptr_to_structure (src
, res
);
10536 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType
*type
, MonoString
*field_name
)
10538 MonoMarshalType
*info
;
10541 int match_index
= -1;
10543 MONO_ARCH_SAVE_REGS
;
10545 MONO_CHECK_ARG_NULL (type
);
10546 MONO_CHECK_ARG_NULL (field_name
);
10548 fname
= mono_string_to_utf8 (field_name
);
10549 klass
= mono_class_from_mono_type (type
->type
);
10551 while (klass
&& match_index
== -1) {
10552 MonoClassField
* field
;
10554 gpointer iter
= NULL
;
10555 while ((field
= mono_class_get_fields (klass
, &iter
))) {
10556 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10558 if (!strcmp (fname
, field
->name
)) {
10565 if (match_index
== -1)
10566 klass
= klass
->parent
;
10571 if(match_index
== -1) {
10572 MonoException
* exc
;
10575 /* Get back original class instance */
10576 klass
= mono_class_from_mono_type (type
->type
);
10578 tmp
= g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass
->name
);
10579 exc
= mono_get_exception_argument ("fieldName", tmp
);
10582 mono_raise_exception ((MonoException
*)exc
);
10585 info
= mono_marshal_load_type_info (klass
);
10586 return info
->fields
[match_index
].offset
;
10590 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString
*string
)
10592 MONO_ARCH_SAVE_REGS
;
10594 return mono_string_to_utf8 (string
);
10598 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString
*string
)
10600 MONO_ARCH_SAVE_REGS
;
10602 if (string
== NULL
)
10605 gunichar2
*res
= g_malloc ((mono_string_length (string
) + 1) * 2);
10606 memcpy (res
, mono_string_chars (string
), mono_string_length (string
) * 2);
10607 res
[mono_string_length (string
)] = 0;
10613 mono_struct_delete_old (MonoClass
*klass
, char *ptr
)
10615 MonoMarshalType
*info
;
10618 info
= mono_marshal_load_type_info (klass
);
10620 for (i
= 0; i
< info
->num_fields
; i
++) {
10621 MonoMarshalNative ntype
;
10622 MonoMarshalConv conv
;
10623 MonoType
*ftype
= info
->fields
[i
].field
->type
;
10626 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10629 ntype
= mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
,
10630 klass
->unicode
, &conv
);
10632 cpos
= ptr
+ info
->fields
[i
].offset
;
10635 case MONO_MARSHAL_CONV_NONE
:
10636 if (MONO_TYPE_ISSTRUCT (ftype
)) {
10637 mono_struct_delete_old (ftype
->data
.klass
, cpos
);
10641 case MONO_MARSHAL_CONV_STR_LPWSTR
:
10642 /* We assume this field points inside a MonoString */
10644 case MONO_MARSHAL_CONV_STR_LPTSTR
:
10645 #ifdef PLATFORM_WIN32
10646 /* We assume this field points inside a MonoString
10650 case MONO_MARSHAL_CONV_STR_LPSTR
:
10651 case MONO_MARSHAL_CONV_STR_BSTR
:
10652 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
10653 case MONO_MARSHAL_CONV_STR_TBSTR
:
10654 mono_marshal_free (*(gpointer
*)cpos
);
10664 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src
, MonoReflectionType
*type
)
10668 MONO_ARCH_SAVE_REGS
;
10670 MONO_CHECK_ARG_NULL (src
);
10671 MONO_CHECK_ARG_NULL (type
);
10673 klass
= mono_class_from_mono_type (type
->type
);
10675 mono_struct_delete_old (klass
, (char *)src
);
10679 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size
)
10683 MONO_ARCH_SAVE_REGS
;
10685 if ((gulong
)size
== 0)
10686 /* This returns a valid pointer for size 0 on MS.NET */
10689 #ifdef PLATFORM_WIN32
10690 res
= GlobalAlloc (GMEM_FIXED
, (gulong
)size
);
10692 res
= g_try_malloc ((gulong
)size
);
10695 mono_gc_out_of_memory ((gulong
)size
);
10701 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr
, int size
)
10706 mono_gc_out_of_memory ((gulong
)size
);
10710 #ifdef PLATFORM_WIN32
10711 res
= GlobalReAlloc (ptr
, (gulong
)size
, 0);
10713 res
= g_try_realloc (ptr
, (gulong
)size
);
10716 mono_gc_out_of_memory ((gulong
)size
);
10722 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr
)
10724 MONO_ARCH_SAVE_REGS
;
10726 #ifdef PLATFORM_WIN32
10734 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size
)
10736 MONO_ARCH_SAVE_REGS
;
10738 #ifdef PLATFORM_WIN32
10739 return CoTaskMemAlloc (size
);
10741 return g_try_malloc ((gulong
)size
);
10746 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr
)
10748 MONO_ARCH_SAVE_REGS
;
10750 #ifdef PLATFORM_WIN32
10751 CoTaskMemFree (ptr
);
10758 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr
, int size
)
10760 MONO_ARCH_SAVE_REGS
;
10762 #ifdef PLATFORM_WIN32
10763 return CoTaskMemRealloc (ptr
, size
);
10765 return g_try_realloc (ptr
, (gulong
)size
);
10770 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray
*arrayobj
, int index
)
10772 return mono_array_addr_with_size (arrayobj
, mono_array_element_size (arrayobj
->obj
.vtable
->klass
), index
);
10776 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn
, MonoReflectionType
*type
)
10778 return mono_ftnptr_to_delegate (mono_type_get_class (type
->type
), ftn
);
10781 /* Only used for COM RCWs */
10783 ves_icall_System_ComObject_CreateRCW (MonoReflectionType
*type
)
10786 MonoDomain
*domain
;
10789 MONO_ARCH_SAVE_REGS
;
10791 domain
= mono_object_domain (type
);
10792 klass
= mono_class_from_mono_type (type
->type
);
10794 /* call mono_object_new_alloc_specific instead of mono_object_new
10795 * because we want to actually create object. mono_object_new checks
10796 * to see if type is import and creates transparent proxy. this method
10797 * is called by the corresponding real proxy to create the real RCW.
10798 * Constructor does not need to be called. Will be called later.
10800 obj
= mono_object_new_alloc_specific (mono_class_vtable (domain
, klass
));
10805 cominterop_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
10807 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value
);
10812 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject
* obj
)
10815 if (obj
->itf_hash
) {
10816 guint32 gchandle
= 0;
10817 mono_cominterop_lock ();
10818 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, obj
->iunknown
));
10820 mono_gchandle_free (gchandle
);
10821 g_hash_table_remove (rcw_hash
, obj
->iunknown
);
10824 g_hash_table_foreach_remove (obj
->itf_hash
, cominterop_finalizer
, NULL
);
10825 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj
->iunknown
);
10826 obj
->itf_hash
= obj
->iunknown
= NULL
;
10827 mono_cominterop_unlock ();
10832 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject
* obj
, MonoReflectionType
* type
, MonoBoolean throw_exception
)
10834 return cominterop_get_interface (obj
, mono_type_get_class (type
->type
), (gboolean
)throw_exception
);
10838 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk
, MonoComInteropProxy
* proxy
)
10840 guint32 gchandle
= 0;
10842 mono_cominterop_lock ();
10843 rcw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
10844 mono_cominterop_unlock ();
10847 gchandle
= mono_gchandle_new_weakref ((MonoObject
*)proxy
, FALSE
);
10849 mono_cominterop_lock ();
10850 g_hash_table_insert (rcw_hash
, pUnk
, GUINT_TO_POINTER (gchandle
));
10851 mono_cominterop_unlock ();
10854 MonoComInteropProxy
*
10855 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk
)
10857 MonoComInteropProxy
* proxy
= NULL
;
10858 guint32 gchandle
= 0;
10860 mono_cominterop_lock ();
10862 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, pUnk
));
10863 mono_cominterop_unlock ();
10865 proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target (gchandle
);
10866 /* proxy is null means we need to free up old RCW */
10868 mono_gchandle_free (gchandle
);
10869 g_hash_table_remove (rcw_hash
, pUnk
);
10876 * mono_marshal_is_loading_type_info:
10878 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
10882 mono_marshal_is_loading_type_info (MonoClass
*klass
)
10884 GSList
*loads_list
= TlsGetValue (load_type_info_tls_id
);
10886 return g_slist_find (loads_list
, klass
) != NULL
;
10890 * mono_marshal_load_type_info:
10892 * Initialize klass->marshal_info using information from metadata. This function can
10893 * recursively call itself, and the caller is responsible to avoid that by calling
10894 * mono_marshal_is_loading_type_info () beforehand.
10896 * LOCKING: Acquires the loader lock.
10899 mono_marshal_load_type_info (MonoClass
* klass
)
10902 guint32 native_size
= 0, min_align
= 1;
10903 MonoMarshalType
*info
;
10904 MonoClassField
* field
;
10907 GSList
*loads_list
;
10909 g_assert (klass
!= NULL
);
10911 if (klass
->marshal_info
)
10912 return klass
->marshal_info
;
10914 if (!klass
->inited
)
10915 mono_class_init (klass
);
10917 mono_loader_lock ();
10919 if (klass
->marshal_info
) {
10920 mono_loader_unlock ();
10921 return klass
->marshal_info
;
10925 * This function can recursively call itself, so we keep the list of classes which are
10926 * under initialization in a TLS list.
10928 g_assert (!mono_marshal_is_loading_type_info (klass
));
10929 loads_list
= TlsGetValue (load_type_info_tls_id
);
10930 loads_list
= g_slist_prepend (loads_list
, klass
);
10931 TlsSetValue (load_type_info_tls_id
, loads_list
);
10934 while ((field
= mono_class_get_fields (klass
, &iter
))) {
10935 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10937 if (mono_field_is_deleted (field
))
10942 layout
= klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
;
10944 /* The mempool is protected by the loader lock */
10945 info
= mono_mempool_alloc0 (klass
->image
->mempool
, sizeof (MonoMarshalType
) + sizeof (MonoMarshalField
) * count
);
10946 info
->num_fields
= count
;
10948 /* Try to find a size for this type in metadata */
10949 mono_metadata_packing_from_typedef (klass
->image
, klass
->type_token
, NULL
, &native_size
);
10951 if (klass
->parent
) {
10952 int parent_size
= mono_class_native_size (klass
->parent
, NULL
);
10954 /* Add parent size to real size */
10955 native_size
+= parent_size
;
10956 info
->native_size
= parent_size
;
10961 while ((field
= mono_class_get_fields (klass
, &iter
))) {
10965 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
10968 if (mono_field_is_deleted (field
))
10970 if (field
->type
->attrs
& FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL
)
10971 mono_metadata_field_info (klass
->image
, mono_metadata_token_index (mono_class_get_field_token (field
)) - 1,
10972 NULL
, NULL
, &info
->fields
[j
].mspec
);
10974 info
->fields
[j
].field
= field
;
10976 if ((mono_class_num_fields (klass
) == 1) && (klass
->instance_size
== sizeof (MonoObject
)) &&
10977 (strcmp (field
->name
, "$PRIVATE$") == 0)) {
10978 /* This field is a hack inserted by MCS to empty structures */
10983 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
10984 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
10985 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
10986 &align
, TRUE
, klass
->unicode
);
10987 align
= klass
->packing_size
? MIN (klass
->packing_size
, align
): align
;
10988 min_align
= MAX (align
, min_align
);
10989 info
->fields
[j
].offset
= info
->native_size
;
10990 info
->fields
[j
].offset
+= align
- 1;
10991 info
->fields
[j
].offset
&= ~(align
- 1);
10992 info
->native_size
= info
->fields
[j
].offset
+ size
;
10994 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
:
10995 size
= mono_marshal_type_size (field
->type
, info
->fields
[j
].mspec
,
10996 &align
, TRUE
, klass
->unicode
);
10997 align
= klass
->packing_size
? MIN (klass
->packing_size
, align
): align
;
10998 min_align
= MAX (align
, min_align
);
10999 info
->fields
[j
].offset
= field
->offset
- sizeof (MonoObject
);
11000 info
->native_size
= MAX (info
->native_size
, info
->fields
[j
].offset
+ size
);
11006 if(layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
11007 info
->native_size
= MAX (native_size
, info
->native_size
);
11010 if (info
->native_size
& (min_align
- 1)) {
11011 info
->native_size
+= min_align
- 1;
11012 info
->native_size
&= ~(min_align
- 1);
11015 /* Update the class's blittable info, if the layouts don't match */
11016 if (info
->native_size
!= mono_class_value_size (klass
, NULL
))
11017 klass
->blittable
= FALSE
;
11019 /* If this is an array type, ensure that we have element info */
11020 if (klass
->element_class
&& !mono_marshal_is_loading_type_info (klass
->element_class
)) {
11021 mono_marshal_load_type_info (klass
->element_class
);
11024 loads_list
= TlsGetValue (load_type_info_tls_id
);
11025 loads_list
= g_slist_remove (loads_list
, klass
);
11026 TlsSetValue (load_type_info_tls_id
, loads_list
);
11028 klass
->marshal_info
= info
;
11030 mono_loader_unlock ();
11032 return klass
->marshal_info
;
11036 * mono_class_native_size:
11039 * Returns: the native size of an object instance (when marshaled
11040 * to unmanaged code)
11043 mono_class_native_size (MonoClass
*klass
, guint32
*align
)
11045 if (!klass
->marshal_info
) {
11046 if (mono_marshal_is_loading_type_info (klass
))
11049 mono_marshal_load_type_info (klass
);
11053 *align
= klass
->min_align
;
11055 return klass
->marshal_info
->native_size
;
11059 * mono_type_native_stack_size:
11060 * @t: the type to return the size it uses on the stack
11062 * Returns: the number of bytes required to hold an instance of this
11063 * type on the native stack
11066 mono_type_native_stack_size (MonoType
*t
, guint32
*align
)
11070 g_assert (t
!= NULL
);
11081 case MONO_TYPE_BOOLEAN
:
11082 case MONO_TYPE_CHAR
:
11091 case MONO_TYPE_STRING
:
11092 case MONO_TYPE_OBJECT
:
11093 case MONO_TYPE_CLASS
:
11094 case MONO_TYPE_SZARRAY
:
11095 case MONO_TYPE_PTR
:
11096 case MONO_TYPE_FNPTR
:
11097 case MONO_TYPE_ARRAY
:
11098 case MONO_TYPE_TYPEDBYREF
:
11109 case MONO_TYPE_VALUETYPE
: {
11112 if (t
->data
.klass
->enumtype
)
11113 return mono_type_native_stack_size (t
->data
.klass
->enum_basetype
, align
);
11115 size
= mono_class_native_size (t
->data
.klass
, align
);
11116 *align
= *align
+ 3;
11126 g_error ("type 0x%02x unknown", t
->type
);
11131 /* __alignof__ returns the preferred alignment of values not the actual alignment used by
11132 the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
11133 but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
11134 #define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
11137 mono_marshal_type_size (MonoType
*type
, MonoMarshalSpec
*mspec
, guint32
*align
,
11138 gboolean as_field
, gboolean unicode
)
11140 MonoMarshalNative native_type
= mono_type_to_unmanaged (type
, mspec
, as_field
, unicode
, NULL
);
11143 switch (native_type
) {
11144 case MONO_NATIVE_BOOLEAN
:
11147 case MONO_NATIVE_I1
:
11148 case MONO_NATIVE_U1
:
11151 case MONO_NATIVE_I2
:
11152 case MONO_NATIVE_U2
:
11153 case MONO_NATIVE_VARIANTBOOL
:
11156 case MONO_NATIVE_I4
:
11157 case MONO_NATIVE_U4
:
11158 case MONO_NATIVE_ERROR
:
11161 case MONO_NATIVE_I8
:
11162 case MONO_NATIVE_U8
:
11163 *align
= ALIGNMENT(guint64
);
11165 case MONO_NATIVE_R4
:
11168 case MONO_NATIVE_R8
:
11169 *align
= ALIGNMENT(double);
11171 case MONO_NATIVE_INT
:
11172 case MONO_NATIVE_UINT
:
11173 case MONO_NATIVE_LPSTR
:
11174 case MONO_NATIVE_LPWSTR
:
11175 case MONO_NATIVE_LPTSTR
:
11176 case MONO_NATIVE_BSTR
:
11177 case MONO_NATIVE_ANSIBSTR
:
11178 case MONO_NATIVE_TBSTR
:
11179 case MONO_NATIVE_LPARRAY
:
11180 case MONO_NATIVE_SAFEARRAY
:
11181 case MONO_NATIVE_IUNKNOWN
:
11182 case MONO_NATIVE_IDISPATCH
:
11183 case MONO_NATIVE_INTERFACE
:
11184 case MONO_NATIVE_ASANY
:
11185 case MONO_NATIVE_FUNC
:
11186 case MONO_NATIVE_LPSTRUCT
:
11187 *align
= ALIGNMENT(gpointer
);
11188 return sizeof (gpointer
);
11189 case MONO_NATIVE_STRUCT
:
11190 klass
= mono_class_from_mono_type (type
);
11191 if (klass
== mono_defaults
.object_class
&&
11192 (mspec
&& mspec
->native
== MONO_NATIVE_STRUCT
)) {
11196 return mono_class_native_size (klass
, align
);
11197 case MONO_NATIVE_BYVALTSTR
: {
11198 int esize
= unicode
? 2: 1;
11201 return mspec
->data
.array_data
.num_elem
* esize
;
11203 case MONO_NATIVE_BYVALARRAY
: {
11204 // FIXME: Have to consider ArraySubType
11206 klass
= mono_class_from_mono_type (type
);
11207 if (klass
->element_class
== mono_defaults
.char_class
) {
11208 esize
= unicode
? 2 : 1;
11211 esize
= mono_class_native_size (klass
->element_class
, align
);
11214 return mspec
->data
.array_data
.num_elem
* esize
;
11216 case MONO_NATIVE_CUSTOM
:
11217 g_assert_not_reached ();
11219 case MONO_NATIVE_CURRENCY
:
11220 case MONO_NATIVE_VBBYREFSTR
:
11222 g_error ("native type %02x not implemented", native_type
);
11225 g_assert_not_reached ();
11230 mono_marshal_asany (MonoObject
*o
, MonoMarshalNative string_encoding
, int param_attrs
)
11238 t
= &o
->vtable
->klass
->byval_arg
;
11242 case MONO_TYPE_PTR
:
11245 case MONO_TYPE_BOOLEAN
:
11248 case MONO_TYPE_CHAR
:
11253 return mono_object_unbox (o
);
11255 case MONO_TYPE_STRING
:
11256 switch (string_encoding
) {
11257 case MONO_NATIVE_LPWSTR
:
11258 return mono_string_to_utf16 ((MonoString
*)o
);
11260 case MONO_NATIVE_LPSTR
:
11261 return mono_string_to_lpstr ((MonoString
*)o
);
11264 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11265 g_assert_not_reached ();
11268 case MONO_TYPE_CLASS
:
11269 case MONO_TYPE_VALUETYPE
: {
11270 MonoMethod
*method
;
11273 MonoBoolean delete_old
= FALSE
;
11275 klass
= t
->data
.klass
;
11277 if ((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_AUTO_LAYOUT
)
11280 if (klass
->valuetype
&& (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
11281 klass
->blittable
|| klass
->enumtype
))
11282 return mono_object_unbox (o
);
11284 res
= mono_marshal_alloc (mono_class_native_size (klass
, NULL
));
11286 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11287 method
= mono_marshal_get_struct_to_ptr (o
->vtable
->klass
);
11291 pa
[2] = &delete_old
;
11293 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
11300 mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
11306 mono_marshal_free_asany (MonoObject
*o
, gpointer ptr
, MonoMarshalNative string_encoding
, int param_attrs
)
11314 t
= &o
->vtable
->klass
->byval_arg
;
11316 case MONO_TYPE_STRING
:
11317 switch (string_encoding
) {
11318 case MONO_NATIVE_LPWSTR
:
11319 case MONO_NATIVE_LPSTR
:
11320 mono_marshal_free (ptr
);
11323 g_warning ("marshaling conversion %d not implemented", string_encoding
);
11324 g_assert_not_reached ();
11327 case MONO_TYPE_CLASS
:
11328 case MONO_TYPE_VALUETYPE
: {
11329 klass
= t
->data
.klass
;
11331 if (klass
->valuetype
&& (((klass
->flags
& TYPE_ATTRIBUTE_LAYOUT_MASK
) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) ||
11332 klass
->blittable
|| klass
->enumtype
))
11335 if (param_attrs
& PARAM_ATTRIBUTE_OUT
) {
11336 MonoMethod
*method
= mono_marshal_get_ptr_to_struct (o
->vtable
->klass
);
11342 mono_runtime_invoke (method
, NULL
, pa
, NULL
);
11345 if (!((param_attrs
& PARAM_ATTRIBUTE_OUT
) && !(param_attrs
& PARAM_ATTRIBUTE_IN
))) {
11346 mono_struct_delete_old (klass
, ptr
);
11349 mono_marshal_free (ptr
);
11358 mono_marshal_get_generic_array_helper (MonoClass
*class, MonoClass
*iface
, gchar
*name
, MonoMethod
*method
)
11360 MonoMethodSignature
*sig
, *csig
;
11361 MonoMethodBuilder
*mb
;
11365 mb
= mono_mb_new (class, name
, MONO_WRAPPER_MANAGED_TO_MANAGED
);
11366 mb
->method
->slot
= -1;
11368 mb
->method
->flags
= METHOD_ATTRIBUTE_PRIVATE
| METHOD_ATTRIBUTE_VIRTUAL
|
11369 METHOD_ATTRIBUTE_NEW_SLOT
| METHOD_ATTRIBUTE_HIDE_BY_SIG
| METHOD_ATTRIBUTE_FINAL
;
11371 sig
= mono_method_signature (method
);
11372 csig
= signature_dup (method
->klass
->image
, sig
);
11373 csig
->generic_param_count
= 0;
11375 mono_mb_emit_ldarg (mb
, 0);
11376 for (i
= 0; i
< csig
->param_count
; i
++)
11377 mono_mb_emit_ldarg (mb
, i
+ 1);
11378 mono_mb_emit_managed_call (mb
, method
, NULL
);
11379 mono_mb_emit_byte (mb
, CEE_RET
);
11381 res
= mono_mb_create_method (mb
, csig
, csig
->param_count
+ 16);
11389 * The mono_win32_compat_* functions are implementations of inline
11390 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
11391 * although not exported by kernel32.
11393 * We map the appropiate kernel32 entries to these functions using
11394 * dllmaps declared in the global etc/mono/config.
11398 mono_win32_compat_CopyMemory (gpointer dest
, gconstpointer source
, gsize length
)
11400 if (!dest
|| !source
)
11403 memcpy (dest
, source
, length
);
11407 mono_win32_compat_FillMemory (gpointer dest
, gsize length
, guchar fill
)
11409 memset (dest
, fill
, length
);
11413 mono_win32_compat_MoveMemory (gpointer dest
, gconstpointer source
, gsize length
)
11415 if (!dest
|| !source
)
11418 memmove (dest
, source
, length
);
11422 mono_win32_compat_ZeroMemory (gpointer dest
, gsize length
)
11424 memset (dest
, 0, length
);
11427 /* Put COM Interop related stuff here */
11430 * cominterop_get_ccw_object:
11431 * @ccw_entry: a pointer to the CCWEntry
11432 * @verify: verify ccw_entry is in fact a ccw
11434 * Returns: the corresponding object for the CCW
11437 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
)
11439 MonoCCW
*ccw
= NULL
;
11441 /* no CCW's exist yet */
11442 if (!ccw_interface_hash
)
11446 ccw
= g_hash_table_lookup (ccw_interface_hash
, ccw_entry
);
11449 ccw
= ccw_entry
->ccw
;
11453 return mono_gchandle_get_target (ccw
->gc_handle
);
11459 cominterop_setup_marshal_context (EmitMarshalContext
*m
, MonoMethod
*method
)
11461 MonoMethodSignature
*sig
, *csig
;
11462 sig
= mono_method_signature (method
);
11463 /* we copy the signature, so that we can modify it */
11464 /* FIXME: which to use? */
11465 csig
= signature_dup (method
->klass
->image
, sig
);
11466 /* csig = mono_metadata_signature_dup (sig); */
11468 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
11469 #ifdef PLATFORM_WIN32
11470 csig
->call_convention
= MONO_CALL_STDCALL
;
11472 csig
->call_convention
= MONO_CALL_C
;
11477 m
->image
= method
->klass
->image
;
11485 * cominterop_get_ccw:
11486 * @object: a pointer to the object
11487 * @itf: interface type needed
11489 * Returns: a value indicating if the object is a
11490 * Runtime Callable Wrapper (RCW) for a COM object
11493 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
)
11496 MonoCCW
*ccw
= NULL
;
11497 MonoCCWInterface
* ccw_entry
= NULL
;
11498 gpointer
*vtable
= NULL
;
11499 static gpointer iunknown
[3] = {NULL
, NULL
, NULL
};
11500 static gpointer idispatch
[4] = {NULL
, NULL
, NULL
, NULL
};
11501 MonoClass
* iface
= NULL
;
11502 MonoClass
* klass
= NULL
;
11503 EmitMarshalContext m
;
11504 int start_slot
= 3;
11505 int method_count
= 0;
11506 GList
*ccw_list
, *ccw_list_item
;
11511 klass
= mono_object_get_class (object
);
11514 ccw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
11515 if (!ccw_interface_hash
)
11516 ccw_interface_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
11518 ccw_list
= g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)));
11520 ccw_list_item
= ccw_list
;
11521 while (ccw_list_item
) {
11522 MonoCCW
* ccw_iter
= ccw_list_item
->data
;
11523 if (mono_gchandle_get_target (ccw_iter
->gc_handle
) == object
) {
11527 ccw_list_item
= g_list_next(ccw_list_item
);
11530 if (!iunknown
[0]) {
11531 iunknown
[0] = cominterop_ccw_queryinterface
;
11532 iunknown
[1] = cominterop_ccw_addref
;
11533 iunknown
[2] = cominterop_ccw_release
;
11536 if (!idispatch
[0]) {
11537 idispatch
[0] = cominterop_ccw_get_type_info_count
;
11538 idispatch
[1] = cominterop_ccw_get_type_info
;
11539 idispatch
[2] = cominterop_ccw_get_ids_of_names
;
11540 idispatch
[3] = cominterop_ccw_invoke
;
11544 ccw
= g_new0 (MonoCCW
, 1);
11545 ccw
->vtable_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
11546 ccw
->ref_count
= 0;
11547 /* just alloc a weak handle until we are addref'd*/
11548 ccw
->gc_handle
= mono_gchandle_new_weakref (object
, FALSE
);
11551 ccw_list
= g_list_alloc ();
11552 ccw_list
->data
= ccw
;
11555 ccw_list
= g_list_append (ccw_list
, ccw
);
11556 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)), ccw_list
);
11557 /* register for finalization to clean up ccw */
11558 mono_object_register_finalizer (object
);
11562 if (iface
== mono_defaults
.iunknown_class
) {
11565 else if (iface
== mono_defaults
.idispatch_class
) {
11570 method_count
+= iface
->method
.count
;
11571 if (iface
->interface_count
) {
11572 iface
= iface
->interfaces
[0];
11575 start_slot
= cominterop_get_com_slot_begin (iface
);
11581 ccw_entry
= g_hash_table_lookup (ccw
->vtable_hash
, itf
);
11584 int vtable_index
= method_count
-1+start_slot
;
11585 mono_loader_lock ();
11586 vtable
= mono_mempool_alloc0 (klass
->image
->mempool
, sizeof (gpointer
)*(method_count
+start_slot
));
11587 mono_loader_unlock ();
11588 memcpy (vtable
, iunknown
, sizeof (iunknown
));
11589 if (start_slot
== 7)
11590 memcpy (vtable
+3, idispatch
, sizeof (idispatch
));
11594 for (i
= iface
->method
.count
-1; i
>= 0;i
--) {
11595 int param_index
= 0;
11596 MonoMethodBuilder
*mb
;
11597 MonoMarshalSpec
** mspecs
;
11598 MonoMethod
*wrapper_method
, *adjust_method
;
11599 MonoMethod
*method
= iface
->methods
[i
];
11600 MonoMethodSignature
* sig_adjusted
;
11601 MonoMethodSignature
* sig
= mono_method_signature (method
);
11602 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
11605 mb
= mono_mb_new (iface
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
11606 adjust_method
= cominterop_get_managed_wrapper_adjusted (method
);
11607 sig_adjusted
= mono_method_signature (adjust_method
);
11609 mspecs
= g_new (MonoMarshalSpec
*, sig_adjusted
->param_count
+ 1);
11610 mono_method_get_marshal_info (method
, mspecs
);
11613 /* move managed args up one */
11614 for (param_index
= sig
->param_count
; param_index
>= 1; param_index
--)
11615 mspecs
[param_index
+1] = mspecs
[param_index
];
11617 /* first arg is IntPtr for interface */
11620 /* move return spec to last param */
11621 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
11622 mspecs
[sig_adjusted
->param_count
] = mspecs
[0];
11626 cominterop_setup_marshal_context (&m
, adjust_method
);
11628 mono_marshal_emit_managed_wrapper (mb
, sig_adjusted
, mspecs
, &m
, adjust_method
, NULL
);
11629 mono_loader_lock ();
11630 mono_marshal_lock ();
11631 wrapper_method
= mono_mb_create_method (mb
, sig_adjusted
, sig_adjusted
->param_count
+ 16);
11632 mono_marshal_unlock ();
11633 mono_loader_unlock ();
11635 /* skip visiblity since we call internal methods */
11636 wrapper_method
->skip_visibility
= TRUE
;
11638 vtable
[vtable_index
--] = mono_compile_method (wrapper_method
);
11641 for (param_index
= sig_adjusted
->param_count
; param_index
>= 0; param_index
--)
11642 if (mspecs
[param_index
])
11643 mono_metadata_free_marshal_spec (mspecs
[param_index
]);
11646 if (iface
->interface_count
)
11647 iface
= iface
->interfaces
[0];
11652 ccw_entry
= g_new0 (MonoCCWInterface
, 1);
11653 ccw_entry
->ccw
= ccw
;
11654 ccw_entry
->vtable
= vtable
;
11655 g_hash_table_insert (ccw
->vtable_hash
, itf
, ccw_entry
);
11656 g_hash_table_insert (ccw_interface_hash
, ccw_entry
, ccw
);
11663 mono_marshal_free_ccw_entry (gpointer key
, gpointer value
, gpointer user_data
)
11671 * mono_marshal_free_ccw:
11672 * @object: the mono object
11674 * Returns: whether the object had a CCW
11677 mono_marshal_free_ccw (MonoObject
* object
)
11679 GList
*ccw_list
, *ccw_list_orig
, *ccw_list_item
;
11680 /* no ccw's were created */
11681 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
11684 /* need to cache orig list address to remove from hash_table if empty */
11685 mono_cominterop_lock ();
11686 ccw_list
= ccw_list_orig
= g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)));
11687 mono_cominterop_unlock ();
11692 ccw_list_item
= ccw_list
;
11693 while (ccw_list_item
) {
11694 MonoCCW
* ccw_iter
= ccw_list_item
->data
;
11695 MonoObject
* handle_target
= mono_gchandle_get_target (ccw_iter
->gc_handle
);
11697 /* Looks like the GC NULLs the weakref handle target before running the
11698 * finalizer. So if we get a NULL target, destroy the CCW as well. */
11699 if (!handle_target
|| handle_target
== object
) {
11700 /* remove all interfaces */
11701 g_hash_table_foreach_remove (ccw_iter
->vtable_hash
, mono_marshal_free_ccw_entry
, NULL
);
11702 g_hash_table_destroy (ccw_iter
->vtable_hash
);
11704 /* get next before we delete */
11705 ccw_list_item
= g_list_next(ccw_list_item
);
11707 /* remove ccw from list */
11708 ccw_list
= g_list_remove (ccw_list
, ccw_iter
);
11712 ccw_list_item
= g_list_next(ccw_list_item
);
11715 /* if list is empty remove original address from hash */
11716 if (g_list_length (ccw_list
) == 0)
11717 g_hash_table_remove (ccw_hash
, ccw_list_orig
);
11724 * cominterop_get_native_wrapper_adjusted:
11725 * @method: managed COM Interop method
11727 * Returns: the generated method to call with signature matching
11728 * the unmanaged COM Method signature
11730 static MonoMethod
*
11731 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
)
11733 static MonoMethod
*get_hr_for_exception
= NULL
;
11734 MonoMethod
*res
= NULL
;
11735 MonoMethodBuilder
*mb
;
11736 MonoMarshalSpec
**mspecs
;
11737 MonoMethodSignature
*sig
, *sig_native
;
11738 MonoExceptionClause
*main_clause
= NULL
;
11739 MonoMethodHeader
*header
;
11743 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
11745 if (!get_hr_for_exception
)
11746 get_hr_for_exception
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetHRForException", -1);
11748 sig
= mono_method_signature (method
);
11750 /* create unmanaged wrapper */
11751 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
11753 sig_native
= cominterop_method_signature (method
);
11755 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+1);
11757 mono_method_get_marshal_info (method
, mspecs
);
11759 /* move managed args up one */
11760 for (i
= sig
->param_count
; i
>= 1; i
--)
11761 mspecs
[i
+1] = mspecs
[i
];
11763 /* first arg is IntPtr for interface */
11766 /* move return spec to last param */
11767 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
11768 mspecs
[sig_native
->param_count
] = mspecs
[0];
11772 if (!preserve_sig
) {
11773 hr
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
11776 main_clause
= g_new0 (MonoExceptionClause
, 1);
11777 main_clause
->try_offset
= mb
->pos
;
11780 /* load last param to store result if not preserve_sig and not void */
11781 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
11782 mono_mb_emit_ldarg (mb
, sig_native
->param_count
-1);
11784 /* the CCW -> object conversion */
11785 mono_mb_emit_ldarg (mb
, 0);
11786 mono_mb_emit_icon (mb
, FALSE
);
11787 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
11789 for (i
= 0; i
< sig
->param_count
; i
++)
11790 mono_mb_emit_ldarg (mb
, i
+1);
11792 mono_mb_emit_managed_call (mb
, method
, NULL
);
11794 if (!preserve_sig
) {
11795 /* store result if not preserve_sig and we have one */
11796 if (!MONO_TYPE_IS_VOID (sig
->ret
))
11797 mono_mb_emit_byte (mb
, mono_type_to_stind (sig
->ret
));
11799 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
11801 /* Main exception catch */
11802 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
11803 main_clause
->try_len
= mb
->pos
- main_clause
->try_offset
;
11804 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
11807 main_clause
->handler_offset
= mb
->pos
;
11808 mono_mb_emit_managed_call (mb
, get_hr_for_exception
, NULL
);
11809 mono_mb_emit_stloc (mb
, hr
);
11810 mono_mb_emit_branch (mb
, CEE_LEAVE
);
11811 main_clause
->handler_len
= mb
->pos
- main_clause
->handler_offset
;
11814 mono_mb_patch_addr (mb
, pos_leave
, mb
->pos
- (pos_leave
+ 4));
11816 mono_mb_emit_ldloc (mb
, hr
);
11819 mono_mb_emit_byte (mb
, CEE_RET
);
11821 mono_loader_lock ();
11822 mono_marshal_lock ();
11823 res
= mono_mb_create_method (mb
, sig_native
, sig_native
->param_count
+ 16);
11824 mono_marshal_unlock ();
11825 mono_loader_unlock ();
11829 for (i
= sig_native
->param_count
; i
>= 0; i
--)
11831 mono_metadata_free_marshal_spec (mspecs
[i
]);
11834 if (!preserve_sig
) {
11835 header
= ((MonoMethodNormal
*)res
)->header
;
11836 header
->num_clauses
= 1;
11837 header
->clauses
= main_clause
;
11844 * cominterop_mono_string_to_guid:
11846 * Converts the standard string representation of a GUID
11847 * to a 16 byte Microsoft GUID.
11850 cominterop_mono_string_to_guid (const MonoString
* string
, guint8
*guid
) {
11851 gunichar2
* chars
= mono_string_chars (string
);
11853 static guint8 indexes
[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
11855 for (i
= 0; i
< sizeof(indexes
); i
++)
11856 guid
[i
] = g_unichar_xdigit_value (chars
[indexes
[i
]]) + (g_unichar_xdigit_value (chars
[indexes
[i
] - 1]) << 4);
11860 cominterop_class_guid_equal (guint8
* guid
, MonoClass
* klass
)
11862 guint8 klass_guid
[16];
11863 if (cominterop_class_guid (klass
, klass_guid
))
11864 return !memcmp (guid
, klass_guid
, sizeof (klass_guid
));
11869 cominterop_ccw_addref (MonoCCWInterface
* ccwe
)
11871 gint32 ref_count
= 0;
11872 MonoCCW
* ccw
= ccwe
->ccw
;
11874 g_assert (ccw
->gc_handle
);
11875 g_assert (ccw
->ref_count
>= 0);
11876 ref_count
= InterlockedIncrement ((gint32
*)&ccw
->ref_count
);
11877 if (ref_count
== 1) {
11878 guint32 oldhandle
= ccw
->gc_handle
;
11879 g_assert (oldhandle
);
11880 /* since we now have a ref count, alloc a strong handle*/
11881 ccw
->gc_handle
= mono_gchandle_new (mono_gchandle_get_target (oldhandle
), FALSE
);
11882 mono_gchandle_free (oldhandle
);
11888 cominterop_ccw_release (MonoCCWInterface
* ccwe
)
11890 gint32 ref_count
= 0;
11891 MonoCCW
* ccw
= ccwe
->ccw
;
11893 g_assert (ccw
->ref_count
> 0);
11894 ref_count
= InterlockedDecrement ((gint32
*)&ccw
->ref_count
);
11895 if (ref_count
== 0) {
11896 /* allow gc of object */
11897 guint32 oldhandle
= ccw
->gc_handle
;
11898 g_assert (oldhandle
);
11899 ccw
->gc_handle
= mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle
), FALSE
);
11900 mono_gchandle_free (oldhandle
);
11905 #define MONO_S_OK 0x00000000L
11906 #define MONO_E_NOINTERFACE 0x80004002L
11907 #define MONO_E_NOTIMPL 0x80004001L
11910 cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, guint8
* riid
, gpointer
* ppv
)
11913 MonoClass
*itf
= NULL
;
11915 MonoCCW
* ccw
= ccwe
->ccw
;
11916 MonoClass
* klass
= NULL
;
11917 MonoObject
* object
= mono_gchandle_get_target (ccw
->gc_handle
);
11920 klass
= mono_object_class (object
);
11925 /* handle IUnknown special */
11926 if (cominterop_class_guid_equal (riid
, mono_defaults
.iunknown_class
)) {
11927 *ppv
= cominterop_get_ccw (object
, mono_defaults
.iunknown_class
);
11928 /* remember to addref on QI */
11929 cominterop_ccw_addref (*ppv
);
11933 /* handle IDispatch special */
11934 if (cominterop_class_guid_equal (riid
, mono_defaults
.idispatch_class
)) {
11935 *ppv
= cominterop_get_ccw (object
, mono_defaults
.idispatch_class
);
11936 /* remember to addref on QI */
11937 cominterop_ccw_addref (*ppv
);
11941 ifaces
= mono_class_get_implemented_interfaces (klass
);
11943 for (i
= 0; i
< ifaces
->len
; ++i
) {
11944 MonoClass
*ic
= NULL
;
11945 ic
= g_ptr_array_index (ifaces
, i
);
11946 if (cominterop_class_guid_equal (riid
, ic
)) {
11951 g_ptr_array_free (ifaces
, TRUE
);
11954 *ppv
= cominterop_get_ccw (object
, itf
);
11955 /* remember to addref on QI */
11956 cominterop_ccw_addref (*ppv
);
11960 return MONO_E_NOINTERFACE
;
11964 cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
)
11966 return MONO_E_NOTIMPL
;
11970 cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
)
11972 return MONO_E_NOTIMPL
;
11976 cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
11977 gunichar2
** rgszNames
, guint32 cNames
,
11978 guint32 lcid
, gint32
*rgDispId
)
11980 return MONO_E_NOTIMPL
;
11984 cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
11985 gpointer riid
, guint32 lcid
,
11986 guint16 wFlags
, gpointer pDispParams
,
11987 gpointer pVarResult
, gpointer pExcepInfo
,
11990 return MONO_E_NOTIMPL
;