3 * Copyright 2018 Microsoft
4 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include "metadata/method-builder-ilgen.h"
12 #include "metadata/method-builder-ilgen-internals.h"
16 #include "metadata/marshal.h"
17 #include "metadata/marshal-internals.h"
18 #include "metadata/marshal-ilgen.h"
19 #include "metadata/tabledefs.h"
20 #include "metadata/exception.h"
21 #include "metadata/appdomain.h"
22 #include "mono/metadata/abi-details.h"
23 #include "mono/metadata/class-abi-details.h"
24 #include "mono/metadata/class-init.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/class-internals.h"
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/domain-internals.h"
31 #include "mono/metadata/gc-internals.h"
32 #include "mono/metadata/threads-types.h"
33 #include "mono/metadata/string-icalls.h"
34 #include "mono/metadata/attrdefs.h"
35 #include "mono/metadata/cominterop.h"
36 #include "mono/metadata/remoting.h"
37 #include "mono/metadata/reflection-internals.h"
38 #include "mono/metadata/threadpool.h"
39 #include "mono/metadata/handle.h"
40 #include "mono/metadata/custom-attrs-internals.h"
41 #include "mono/metadata/icall-internals.h"
42 #include "mono/utils/mono-counters.h"
43 #include "mono/utils/mono-tls.h"
44 #include "mono/utils/mono-memory-model.h"
45 #include "mono/utils/atomic.h"
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/mono-threads-coop.h>
48 #include <mono/utils/mono-error-internals.h>
51 #include "icall-decl.h"
53 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
57 #include "mono/cil/opcode.def"
63 is_in (const MonoType
*t
)
65 const guint32 attrs
= t
->attrs
;
66 return (attrs
& PARAM_ATTRIBUTE_IN
) || !(attrs
& PARAM_ATTRIBUTE_OUT
);
70 is_out (const MonoType
*t
)
72 const guint32 attrs
= t
->attrs
;
73 return (attrs
& PARAM_ATTRIBUTE_OUT
) || !(attrs
& PARAM_ATTRIBUTE_IN
);
76 static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute
, "System.Runtime.CompilerServices", "FixedBufferAttribute");
77 static GENERATE_GET_CLASS_WITH_CACHE (date_time
, "System", "DateTime");
78 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler
, "System.Runtime.InteropServices", "ICustomMarshaler");
79 static GENERATE_TRY_GET_CLASS_WITH_CACHE (marshal
, "System.Runtime.InteropServices", "Marshal");
81 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
82 static MonoMethod
*sh_dangerous_add_ref
;
83 static MonoMethod
*sh_dangerous_release
;
85 // FIXME Consolidate the multiple functions named get_method_nofail.
87 get_method_nofail (MonoClass
*klass
, const char *method_name
, int num_params
, int flags
)
91 method
= mono_class_get_method_from_name_checked (klass
, method_name
, num_params
, flags
, error
);
92 mono_error_assert_ok (error
);
93 g_assertf (method
, "Could not lookup method %s in %s", method_name
, m_class_get_name (klass
));
98 init_safe_handle (void)
100 mono_atomic_store_seq (&sh_dangerous_add_ref
, get_method_nofail (mono_class_try_get_safehandle_class (), "DangerousAddRef", 1, 0));
101 mono_atomic_store_seq (&sh_dangerous_release
, get_method_nofail (mono_class_try_get_safehandle_class (), "DangerousRelease", 0, 0));
105 get_method_image (MonoMethod
*method
)
107 return m_class_get_image (method
->klass
);
111 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
114 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
, int offset_of_first_child_field
, MonoMarshalNative string_encoding
);
116 static MonoJitICallId
117 conv_to_icall (MonoMarshalConv conv
, int *ind_store_type
);
119 static MonoMarshalConv
120 conv_str_inverse (MonoMarshalConv conv
);
124 * \param mb the MethodBuilder
127 * Creates a copy of the string \p s that can be referenced from the IL of \c mb.
129 * \returns a pointer to the new string which is owned by the method builder
132 mono_mb_strdup (MonoMethodBuilder
*mb
, const char *s
)
136 res
= mono_image_strdup (get_method_image (mb
->method
), s
);
145 * mono_mb_emit_exception_marshal_directive:
147 * This function assumes ownership of MSG, which should be malloc-ed.
150 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, char *msg
)
152 char *s
= mono_mb_strdup (mb
, msg
);
154 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", s
);
158 offset_of_first_nonstatic_field (MonoClass
*klass
)
161 int fcount
= mono_class_get_field_count (klass
);
162 mono_class_setup_fields (klass
);
163 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
164 for (i
= 0; i
< fcount
; i
++) {
165 if (!(klass_fields
[i
].type
->attrs
& FIELD_ATTRIBUTE_STATIC
) && !mono_field_is_deleted (&klass_fields
[i
]))
166 return klass_fields
[i
].offset
- MONO_ABI_SIZEOF (MonoObject
);
173 get_fixed_buffer_attr (MonoClassField
*field
, MonoType
**out_etype
, int *out_len
)
176 MonoCustomAttrInfo
*cinfo
;
177 MonoCustomAttrEntry
*attr
;
180 cinfo
= mono_custom_attrs_from_field_checked (field
->parent
, field
, error
);
185 for (aindex
= 0; aindex
< cinfo
->num_attrs
; ++aindex
) {
186 MonoClass
*ctor_class
= cinfo
->attrs
[aindex
].ctor
->klass
;
187 if (mono_class_has_parent (ctor_class
, mono_class_get_fixed_buffer_attribute_class ())) {
188 attr
= &cinfo
->attrs
[aindex
];
194 gpointer
*typed_args
, *named_args
;
195 CattrNamedArg
*arginfo
;
198 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
199 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
202 *out_etype
= (MonoType
*)typed_args
[0];
203 *out_len
= *(gint32
*)typed_args
[1];
204 g_free (typed_args
[1]);
209 if (cinfo
&& !cinfo
->cached
)
210 mono_custom_attrs_free (cinfo
);
215 emit_fixed_buf_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoType
*etype
, int len
, gboolean to_object
, int *out_usize
)
217 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
218 MonoClass
*eklass
= mono_class_from_mono_type_internal (etype
);
221 esize
= mono_class_native_size (eklass
, NULL
);
223 MonoMarshalNative string_encoding
= m_class_is_unicode (klass
) ? MONO_NATIVE_LPWSTR
: MONO_NATIVE_LPSTR
;
224 int usize
= mono_class_value_size (eklass
, NULL
);
225 int msize
= mono_class_value_size (eklass
, NULL
);
227 //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), em_class_is_blittable (klass), string_encoding);
229 if (m_class_is_blittable (eklass
)) {
230 /* copy the elements */
231 mono_mb_emit_ldloc (mb
, 1);
232 mono_mb_emit_ldloc (mb
, 0);
233 mono_mb_emit_icon (mb
, len
* esize
);
234 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
235 mono_mb_emit_byte (mb
, CEE_CPBLK
);
238 guint32 label2
, label3
;
240 /* Emit marshalling loop */
241 MonoType
*int_type
= mono_get_int_type ();
242 index_var
= mono_mb_add_local (mb
, int_type
);
243 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
244 mono_mb_emit_stloc (mb
, index_var
);
247 label2
= mono_mb_get_label (mb
);
248 mono_mb_emit_ldloc (mb
, index_var
);
249 mono_mb_emit_icon (mb
, len
);
250 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
252 /* src/dst is already set */
254 /* Do the conversion */
255 MonoTypeEnum t
= etype
->type
;
261 case MONO_TYPE_BOOLEAN
:
270 mono_mb_emit_ldloc (mb
, 1);
271 mono_mb_emit_ldloc (mb
, 0);
272 if (t
== MONO_TYPE_CHAR
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
274 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
275 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
277 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
278 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
282 mono_mb_emit_byte (mb
, mono_type_to_ldind (etype
));
283 mono_mb_emit_byte (mb
, mono_type_to_stind (etype
));
287 g_assert_not_reached ();
292 mono_mb_emit_add_to_local (mb
, 0, usize
);
293 mono_mb_emit_add_to_local (mb
, 1, msize
);
295 mono_mb_emit_add_to_local (mb
, 0, msize
);
296 mono_mb_emit_add_to_local (mb
, 1, usize
);
300 mono_mb_emit_add_to_local (mb
, index_var
, 1);
302 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
304 mono_mb_patch_branch (mb
, label3
);
307 *out_usize
= usize
* len
;
311 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
314 case MONO_MARSHAL_CONV_BOOL_I4
:
315 mono_mb_emit_ldloc (mb
, 1);
316 mono_mb_emit_ldloc (mb
, 0);
317 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
318 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
319 mono_mb_emit_byte (mb
, 3);
320 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
321 mono_mb_emit_byte (mb
, CEE_BR_S
);
322 mono_mb_emit_byte (mb
, 1);
323 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
324 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
326 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
327 mono_mb_emit_ldloc (mb
, 1);
328 mono_mb_emit_ldloc (mb
, 0);
329 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
330 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
331 mono_mb_emit_byte (mb
, 3);
332 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
333 mono_mb_emit_byte (mb
, CEE_BR_S
);
334 mono_mb_emit_byte (mb
, 1);
335 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
336 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
338 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
339 MonoClass
*eklass
= NULL
;
342 if (type
->type
== MONO_TYPE_SZARRAY
) {
343 eklass
= type
->data
.klass
;
345 g_assert_not_reached ();
348 esize
= mono_class_native_size (eklass
, NULL
);
350 /* create a new array */
351 mono_mb_emit_ldloc (mb
, 1);
352 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
353 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
354 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
356 if (m_class_is_blittable (eklass
)) {
357 /* copy the elements */
358 mono_mb_emit_ldloc (mb
, 1);
359 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
360 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
361 mono_mb_emit_byte (mb
, CEE_ADD
);
362 mono_mb_emit_ldloc (mb
, 0);
363 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
364 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
365 mono_mb_emit_byte (mb
, CEE_CPBLK
);
368 int array_var
, src_var
, dst_var
, index_var
;
369 guint32 label2
, label3
;
371 MonoType
*int_type
= mono_get_int_type ();
372 array_var
= mono_mb_add_local (mb
, mono_get_object_type ());
373 src_var
= mono_mb_add_local (mb
, int_type
);
374 dst_var
= mono_mb_add_local (mb
, int_type
);
377 mono_mb_emit_ldloc (mb
, 1);
378 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
379 mono_mb_emit_stloc (mb
, array_var
);
381 /* save the old src pointer */
382 mono_mb_emit_ldloc (mb
, 0);
383 mono_mb_emit_stloc (mb
, src_var
);
384 /* save the old dst pointer */
385 mono_mb_emit_ldloc (mb
, 1);
386 mono_mb_emit_stloc (mb
, dst_var
);
388 /* Emit marshalling loop */
389 index_var
= mono_mb_add_local (mb
, int_type
);
390 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
391 mono_mb_emit_stloc (mb
, index_var
);
394 label2
= mono_mb_get_label (mb
);
395 mono_mb_emit_ldloc (mb
, index_var
);
396 mono_mb_emit_ldloc (mb
, array_var
);
397 mono_mb_emit_byte (mb
, CEE_LDLEN
);
398 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
400 /* src is already set */
403 mono_mb_emit_ldloc (mb
, array_var
);
404 mono_mb_emit_ldloc (mb
, index_var
);
405 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
406 mono_mb_emit_stloc (mb
, 1);
408 /* Do the conversion */
409 emit_struct_conv (mb
, eklass
, TRUE
);
412 mono_mb_emit_add_to_local (mb
, index_var
, 1);
414 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
416 mono_mb_patch_branch (mb
, label3
);
418 /* restore the old src pointer */
419 mono_mb_emit_ldloc (mb
, src_var
);
420 mono_mb_emit_stloc (mb
, 0);
421 /* restore the old dst pointer */
422 mono_mb_emit_ldloc (mb
, dst_var
);
423 mono_mb_emit_stloc (mb
, 1);
427 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
428 MonoClass
*eclass
= mono_defaults
.char_class
;
430 /* create a new array */
431 mono_mb_emit_ldloc (mb
, 1);
432 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
433 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
434 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
436 mono_mb_emit_ldloc (mb
, 1);
437 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
438 mono_mb_emit_ldloc (mb
, 0);
439 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
440 mono_mb_emit_icall (mb
, mono_byvalarray_to_byte_array
);
443 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
444 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
445 mono_mb_emit_ldloc (mb
, 1);
446 mono_mb_emit_ldloc (mb
, 0);
447 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
448 mono_mb_emit_icall (mb
, mono_string_from_byvalstr
);
450 mono_mb_emit_ldloc (mb
, 1);
451 mono_mb_emit_ldloc (mb
, 0);
452 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
454 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
456 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
457 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
458 mono_mb_emit_ldloc (mb
, 1);
459 mono_mb_emit_ldloc (mb
, 0);
460 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
461 mono_mb_emit_icall (mb
, mono_string_from_byvalwstr
);
463 mono_mb_emit_ldloc (mb
, 1);
464 mono_mb_emit_ldloc (mb
, 0);
465 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
467 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
470 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
471 case MONO_MARSHAL_CONV_STR_TBSTR
:
472 case MONO_MARSHAL_CONV_STR_UTF8STR
:
473 case MONO_MARSHAL_CONV_STR_LPWSTR
:
474 case MONO_MARSHAL_CONV_STR_LPSTR
:
475 case MONO_MARSHAL_CONV_STR_LPTSTR
:
476 case MONO_MARSHAL_CONV_STR_BSTR
: {
477 mono_mb_emit_ldloc (mb
, 1);
478 mono_mb_emit_ldloc (mb
, 0);
479 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
480 mono_mb_emit_icall_id (mb
, conv_to_icall (conv_str_inverse (conv
), NULL
));
481 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
485 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
486 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
487 int src_var
, dst_var
;
489 MonoType
*int_type
= mono_get_int_type ();
490 src_var
= mono_mb_add_local (mb
, int_type
);
491 dst_var
= mono_mb_add_local (mb
, int_type
);
493 /* *dst = new object */
494 mono_mb_emit_ldloc (mb
, 1);
495 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
496 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
497 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
499 /* save the old src pointer */
500 mono_mb_emit_ldloc (mb
, 0);
501 mono_mb_emit_stloc (mb
, src_var
);
502 /* save the old dst pointer */
503 mono_mb_emit_ldloc (mb
, 1);
504 mono_mb_emit_stloc (mb
, dst_var
);
506 /* dst = pointer to newly created object data */
507 mono_mb_emit_ldloc (mb
, 1);
508 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
509 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
510 mono_mb_emit_byte (mb
, CEE_ADD
);
511 mono_mb_emit_stloc (mb
, 1);
513 emit_struct_conv (mb
, klass
, TRUE
);
515 /* restore the old src pointer */
516 mono_mb_emit_ldloc (mb
, src_var
);
517 mono_mb_emit_stloc (mb
, 0);
518 /* restore the old dst pointer */
519 mono_mb_emit_ldloc (mb
, dst_var
);
520 mono_mb_emit_stloc (mb
, 1);
523 case MONO_MARSHAL_CONV_DEL_FTN
: {
524 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
526 mono_mb_emit_ldloc (mb
, 1);
527 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
528 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
529 mono_mb_emit_ldloc (mb
, 0);
530 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
531 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
532 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
535 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
: {
536 char *msg
= g_strdup_printf ("Structure field of type %s can't be marshalled as LPArray", m_class_get_name (mono_class_from_mono_type_internal (type
)));
537 mono_mb_emit_exception_marshal_directive (mb
, msg
);
542 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
543 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
544 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
545 mono_cominterop_emit_ptr_to_object_conv (mb
, type
, conv
, mspec
);
547 #endif /* DISABLE_COM */
549 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
551 * Passing SafeHandles as ref does not allow the unmanaged code
552 * to change the SafeHandle value. If the value is changed,
553 * we should issue a diagnostic exception (NotSupportedException)
554 * that informs the user that changes to handles in unmanaged code
557 * Since we currently have no access to the original
558 * SafeHandle that was used during the marshalling,
559 * for now we just ignore this, and ignore/discard any
560 * changes that might have happened to the handle.
565 case MONO_MARSHAL_CONV_HANDLEREF
: {
567 * Passing HandleRefs in a struct that is ref()ed does not
568 * copy the values back to the HandleRef
573 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
575 char *msg
= g_strdup_printf ("marshaling conversion %d not implemented", conv
);
577 mono_mb_emit_exception_marshal_directive (mb
, msg
);
583 // On legacy Mono, LPTSTR was either UTF16 or UTF8 depending on platform
584 static inline MonoJitICallId
585 mono_string_to_platform_unicode (void)
588 return MONO_JIT_ICALL_mono_marshal_string_to_utf16
;
590 return MONO_JIT_ICALL_mono_string_to_utf8str
;
594 static inline MonoJitICallId
595 mono_string_from_platform_unicode (void)
598 return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16
;
600 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
604 static inline MonoJitICallId
605 mono_string_builder_to_platform_unicode (void)
608 return MONO_JIT_ICALL_mono_string_builder_to_utf16
;
610 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
614 static inline MonoJitICallId
615 mono_string_builder_from_platform_unicode (void)
618 return MONO_JIT_ICALL_mono_string_utf16_to_builder
;
620 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
624 static MonoMarshalConv
625 conv_str_inverse (MonoMarshalConv conv
)
629 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
630 return MONO_MARSHAL_CONV_ANSIBSTR_STR
;
631 case MONO_MARSHAL_CONV_ANSIBSTR_STR
:
632 return MONO_MARSHAL_CONV_STR_ANSIBSTR
;
635 case MONO_MARSHAL_CONV_STR_BSTR
:
636 return MONO_MARSHAL_CONV_BSTR_STR
;
637 case MONO_MARSHAL_CONV_BSTR_STR
:
638 return MONO_MARSHAL_CONV_STR_BSTR
;
641 case MONO_MARSHAL_CONV_STR_LPSTR
:
642 return MONO_MARSHAL_CONV_LPSTR_STR
;
643 case MONO_MARSHAL_CONV_LPSTR_STR
:
644 return MONO_MARSHAL_CONV_STR_LPSTR
;
647 case MONO_MARSHAL_CONV_STR_LPTSTR
:
648 return MONO_MARSHAL_CONV_LPTSTR_STR
;
649 case MONO_MARSHAL_CONV_LPTSTR_STR
:
650 return MONO_MARSHAL_CONV_STR_LPTSTR
;
653 case MONO_MARSHAL_CONV_STR_UTF8STR
:
654 return MONO_MARSHAL_CONV_UTF8STR_STR
;
655 case MONO_MARSHAL_CONV_UTF8STR_STR
:
656 return MONO_MARSHAL_CONV_STR_UTF8STR
;
659 case MONO_MARSHAL_CONV_STR_LPWSTR
:
660 return MONO_MARSHAL_CONV_LPWSTR_STR
;
661 case MONO_MARSHAL_CONV_LPWSTR_STR
:
662 return MONO_MARSHAL_CONV_STR_LPWSTR
;
665 case MONO_MARSHAL_CONV_STR_TBSTR
:
666 return MONO_MARSHAL_CONV_TBSTR_STR
;
667 case MONO_MARSHAL_CONV_TBSTR_STR
:
668 return MONO_MARSHAL_CONV_STR_TBSTR
;
671 g_assert_not_reached ();
675 static MonoJitICallId
676 conv_to_icall (MonoMarshalConv conv
, int *ind_store_type
)
678 // FIXME This or its caller might be a good place to inline some
679 // of the wrapper logic. In particular, to produce
680 // volatile stack-based handles. Being data-driven,
685 ind_store_type
= &dummy
;
686 *ind_store_type
= CEE_STIND_I
;
689 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
690 return MONO_JIT_ICALL_mono_string_to_ansibstr
;
691 case MONO_MARSHAL_CONV_ANSIBSTR_STR
:
692 *ind_store_type
= CEE_STIND_REF
;
693 return MONO_JIT_ICALL_mono_string_from_ansibstr
;
696 case MONO_MARSHAL_CONV_STR_BSTR
:
697 return MONO_JIT_ICALL_mono_string_to_bstr
;
698 case MONO_MARSHAL_CONV_BSTR_STR
:
699 *ind_store_type
= CEE_STIND_REF
;
700 return MONO_JIT_ICALL_mono_string_from_bstr_icall
;
703 // In Mono, LPSTR was historically treated as UTF8STR
704 case MONO_MARSHAL_CONV_STR_LPSTR
:
705 return MONO_JIT_ICALL_mono_string_to_utf8str
;
706 case MONO_MARSHAL_CONV_LPSTR_STR
:
707 *ind_store_type
= CEE_STIND_REF
;
708 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
709 case MONO_MARSHAL_CONV_SB_LPSTR
:
710 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
711 case MONO_MARSHAL_CONV_LPSTR_SB
:
712 *ind_store_type
= CEE_STIND_REF
;
713 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
716 // FIXME: This is how LPTStr was handled on legacy, but it's not correct and for netcore we should implement this more properly.
717 // This type is supposed to detect ANSI or UTF16 (as LPTStr can be either depending on _UNICODE) and handle it accordingly.
718 // The CoreCLR test for this type only tests as LPWSTR regardless of platform.
719 case MONO_MARSHAL_CONV_STR_LPTSTR
:
720 return mono_string_to_platform_unicode ();
721 case MONO_MARSHAL_CONV_LPTSTR_STR
:
722 *ind_store_type
= CEE_STIND_REF
;
723 return mono_string_from_platform_unicode ();
724 case MONO_MARSHAL_CONV_SB_LPTSTR
:
725 return mono_string_builder_to_platform_unicode ();
726 case MONO_MARSHAL_CONV_LPTSTR_SB
:
727 *ind_store_type
= CEE_STIND_REF
;
728 return mono_string_builder_from_platform_unicode ();
731 case MONO_MARSHAL_CONV_STR_UTF8STR
:
732 return MONO_JIT_ICALL_mono_string_to_utf8str
;
733 case MONO_MARSHAL_CONV_UTF8STR_STR
:
734 *ind_store_type
= CEE_STIND_REF
;
735 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
736 case MONO_MARSHAL_CONV_SB_UTF8STR
:
737 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
738 case MONO_MARSHAL_CONV_UTF8STR_SB
:
739 *ind_store_type
= CEE_STIND_REF
;
740 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
743 case MONO_MARSHAL_CONV_STR_LPWSTR
:
744 return MONO_JIT_ICALL_mono_marshal_string_to_utf16
;
745 case MONO_MARSHAL_CONV_LPWSTR_STR
:
746 *ind_store_type
= CEE_STIND_REF
;
747 return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16
;
748 case MONO_MARSHAL_CONV_SB_LPWSTR
:
749 return MONO_JIT_ICALL_mono_string_builder_to_utf16
;
750 case MONO_MARSHAL_CONV_LPWSTR_SB
:
751 *ind_store_type
= CEE_STIND_REF
;
752 return MONO_JIT_ICALL_mono_string_utf16_to_builder
;
755 case MONO_MARSHAL_CONV_STR_TBSTR
:
756 return MONO_JIT_ICALL_mono_string_to_tbstr
;
757 case MONO_MARSHAL_CONV_TBSTR_STR
:
758 *ind_store_type
= CEE_STIND_REF
;
759 return MONO_JIT_ICALL_mono_string_from_tbstr
;
761 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
762 return MONO_JIT_ICALL_mono_string_to_byvalstr
;
763 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
764 return MONO_JIT_ICALL_mono_string_to_byvalwstr
;
766 case MONO_MARSHAL_CONV_DEL_FTN
:
767 return MONO_JIT_ICALL_mono_delegate_to_ftnptr
;
768 case MONO_MARSHAL_CONV_FTN_DEL
:
769 *ind_store_type
= CEE_STIND_REF
;
770 return MONO_JIT_ICALL_mono_ftnptr_to_delegate
;
772 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
773 return MONO_JIT_ICALL_mono_array_to_savearray
;
774 case MONO_MARSHAL_FREE_ARRAY
:
775 return MONO_JIT_ICALL_mono_marshal_free_array
;
777 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
778 return MONO_JIT_ICALL_mono_array_to_lparray
;
779 case MONO_MARSHAL_FREE_LPARRAY
:
780 return MONO_JIT_ICALL_mono_free_lparray
;
783 g_assert_not_reached ();
786 return MONO_JIT_ICALL_ZeroIsReserved
;
790 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
796 case MONO_MARSHAL_CONV_BOOL_I4
:
797 mono_mb_emit_ldloc (mb
, 1);
798 mono_mb_emit_ldloc (mb
, 0);
799 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
800 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
802 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
803 mono_mb_emit_ldloc (mb
, 1);
804 mono_mb_emit_ldloc (mb
, 0);
805 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
806 mono_mb_emit_byte (mb
, CEE_NEG
);
807 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
809 case MONO_MARSHAL_CONV_STR_UTF8STR
:
810 case MONO_MARSHAL_CONV_STR_LPWSTR
:
811 case MONO_MARSHAL_CONV_STR_LPSTR
:
812 case MONO_MARSHAL_CONV_STR_LPTSTR
:
813 case MONO_MARSHAL_CONV_STR_BSTR
:
814 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
815 case MONO_MARSHAL_CONV_STR_TBSTR
: {
818 /* free space if free == true */
819 mono_mb_emit_ldloc (mb
, 2);
820 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
821 mono_mb_emit_ldloc (mb
, 1);
822 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
823 mono_mb_emit_icall (mb
, g_free
); // aka monoeg_g_free
824 mono_mb_patch_short_branch (mb
, pos
);
826 mono_mb_emit_ldloc (mb
, 1);
827 mono_mb_emit_ldloc (mb
, 0);
828 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
829 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
830 mono_mb_emit_byte (mb
, stind_op
);
833 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
834 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
835 case MONO_MARSHAL_CONV_DEL_FTN
:
836 mono_mb_emit_ldloc (mb
, 1);
837 mono_mb_emit_ldloc (mb
, 0);
838 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
839 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
840 mono_mb_emit_byte (mb
, stind_op
);
842 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
843 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
846 mono_mb_emit_ldloc (mb
, 1); /* dst */
847 mono_mb_emit_ldloc (mb
, 0);
848 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
849 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
850 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
853 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
854 MonoClass
*eklass
= NULL
;
857 if (type
->type
== MONO_TYPE_SZARRAY
) {
858 eklass
= type
->data
.klass
;
859 } else if (type
->type
== MONO_TYPE_ARRAY
) {
860 eklass
= type
->data
.array
->eklass
;
861 g_assert(m_class_is_blittable (eklass
));
863 g_assert_not_reached ();
866 if (m_class_is_valuetype (eklass
))
867 esize
= mono_class_native_size (eklass
, NULL
);
869 esize
= TARGET_SIZEOF_VOID_P
;
871 mono_mb_emit_ldloc (mb
, 0);
872 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
873 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
875 if (m_class_is_blittable (eklass
)) {
876 mono_mb_emit_ldloc (mb
, 1);
877 mono_mb_emit_ldloc (mb
, 0);
878 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
879 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
880 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
881 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
882 mono_mb_emit_byte (mb
, CEE_CPBLK
);
884 int array_var
, src_var
, dst_var
, index_var
;
885 guint32 label2
, label3
;
887 MonoType
*int_type
= mono_get_int_type ();
888 MonoType
*object_type
= mono_get_object_type ();
889 array_var
= mono_mb_add_local (mb
, object_type
);
890 src_var
= mono_mb_add_local (mb
, int_type
);
891 dst_var
= mono_mb_add_local (mb
, int_type
);
894 mono_mb_emit_ldloc (mb
, 0);
895 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
896 mono_mb_emit_stloc (mb
, array_var
);
898 /* save the old src pointer */
899 mono_mb_emit_ldloc (mb
, 0);
900 mono_mb_emit_stloc (mb
, src_var
);
901 /* save the old dst pointer */
902 mono_mb_emit_ldloc (mb
, 1);
903 mono_mb_emit_stloc (mb
, dst_var
);
905 /* Emit marshalling loop */
906 index_var
= mono_mb_add_local (mb
, int_type
);
907 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
908 mono_mb_emit_stloc (mb
, index_var
);
911 label2
= mono_mb_get_label (mb
);
912 mono_mb_emit_ldloc (mb
, index_var
);
913 mono_mb_emit_ldloc (mb
, array_var
);
914 mono_mb_emit_byte (mb
, CEE_LDLEN
);
915 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
918 mono_mb_emit_ldloc (mb
, array_var
);
919 mono_mb_emit_ldloc (mb
, index_var
);
920 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
921 mono_mb_emit_stloc (mb
, 0);
923 /* dst is already set */
925 /* Do the conversion */
926 emit_struct_conv (mb
, eklass
, FALSE
);
929 mono_mb_emit_add_to_local (mb
, index_var
, 1);
931 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
933 mono_mb_patch_branch (mb
, label3
);
935 /* restore the old src pointer */
936 mono_mb_emit_ldloc (mb
, src_var
);
937 mono_mb_emit_stloc (mb
, 0);
938 /* restore the old dst pointer */
939 mono_mb_emit_ldloc (mb
, dst_var
);
940 mono_mb_emit_stloc (mb
, 1);
943 mono_mb_patch_branch (mb
, pos
);
946 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
947 mono_mb_emit_ldloc (mb
, 0);
948 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
949 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
951 mono_mb_emit_ldloc (mb
, 1);
952 mono_mb_emit_ldloc (mb
, 0);
953 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
954 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
955 mono_mb_emit_icall (mb
, mono_array_to_byte_byvalarray
);
956 mono_mb_patch_short_branch (mb
, pos
);
959 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
960 int src_var
, dst_var
;
962 MonoType
*int_type
= mono_get_int_type ();
963 src_var
= mono_mb_add_local (mb
, int_type
);
964 dst_var
= mono_mb_add_local (mb
, int_type
);
966 mono_mb_emit_ldloc (mb
, 0);
967 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
968 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
970 /* save the old src pointer */
971 mono_mb_emit_ldloc (mb
, 0);
972 mono_mb_emit_stloc (mb
, src_var
);
973 /* save the old dst pointer */
974 mono_mb_emit_ldloc (mb
, 1);
975 mono_mb_emit_stloc (mb
, dst_var
);
977 /* src = pointer to object data */
978 mono_mb_emit_ldloc (mb
, 0);
979 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
980 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
981 mono_mb_emit_byte (mb
, CEE_ADD
);
982 mono_mb_emit_stloc (mb
, 0);
984 emit_struct_conv (mb
, mono_class_from_mono_type_internal (type
), FALSE
);
986 /* restore the old src pointer */
987 mono_mb_emit_ldloc (mb
, src_var
);
988 mono_mb_emit_stloc (mb
, 0);
989 /* restore the old dst pointer */
990 mono_mb_emit_ldloc (mb
, dst_var
);
991 mono_mb_emit_stloc (mb
, 1);
993 mono_mb_patch_branch (mb
, pos
);
998 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
999 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
1000 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
1001 mono_cominterop_emit_object_to_ptr_conv (mb
, type
, conv
, mspec
);
1003 #endif /* DISABLE_COM */
1005 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
1008 mono_mb_emit_ldloc (mb
, 0);
1009 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1010 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1011 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
1012 mono_mb_patch_branch (mb
, pos
);
1014 /* Pull the handle field from SafeHandle */
1015 mono_mb_emit_ldloc (mb
, 1);
1016 mono_mb_emit_ldloc (mb
, 0);
1017 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1018 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
1019 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1020 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1024 case MONO_MARSHAL_CONV_HANDLEREF
: {
1025 mono_mb_emit_ldloc (mb
, 1);
1026 mono_mb_emit_ldloc (mb
, 0);
1027 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
1028 mono_mb_emit_byte (mb
, CEE_ADD
);
1029 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1030 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1035 g_error ("marshalling conversion %d not implemented", conv
);
1042 // FIXME There are multiple caches of "Clear".
1045 mono_get_Variant_Clear (void)
1047 MONO_STATIC_POINTER_INIT (MonoMethod
, variant_clear
)
1048 variant_clear
= get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
1049 MONO_STATIC_POINTER_INIT_END (MonoMethod
, variant_clear
)
1051 g_assert (variant_clear
);
1052 return variant_clear
;
1057 // FIXME There are multiple caches of "GetObjectForNativeVariant".
1060 mono_get_Marshal_GetObjectForNativeVariant (void)
1062 MONO_STATIC_POINTER_INIT (MonoMethod
, get_object_for_native_variant
)
1063 get_object_for_native_variant
= get_method_nofail (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0);
1064 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_object_for_native_variant
)
1066 g_assert (get_object_for_native_variant
);
1067 return get_object_for_native_variant
;
1070 // FIXME There are multiple caches of "GetNativeVariantForObject".
1073 mono_get_Marshal_GetNativeVariantForObject (void)
1075 MONO_STATIC_POINTER_INIT (MonoMethod
, get_native_variant_for_object
)
1076 get_native_variant_for_object
= get_method_nofail (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0);
1077 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_native_variant_for_object
)
1079 g_assert (get_native_variant_for_object
);
1080 return get_native_variant_for_object
;
1084 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
,
1085 int offset_of_first_child_field
, MonoMarshalNative string_encoding
)
1087 MonoMarshalType
*info
;
1090 if (m_class_get_parent (klass
))
1091 emit_struct_conv_full (mb
, m_class_get_parent (klass
), to_object
, offset_of_first_nonstatic_field (klass
), string_encoding
);
1093 info
= mono_marshal_load_type_info (klass
);
1095 if (info
->native_size
== 0)
1098 if (m_class_is_blittable (klass
)) {
1099 int usize
= mono_class_value_size (klass
, NULL
);
1100 g_assert (usize
== info
->native_size
);
1101 mono_mb_emit_ldloc (mb
, 1);
1102 mono_mb_emit_ldloc (mb
, 0);
1103 mono_mb_emit_icon (mb
, usize
);
1104 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1105 mono_mb_emit_byte (mb
, CEE_CPBLK
);
1108 mono_mb_emit_add_to_local (mb
, 0, usize
);
1109 mono_mb_emit_add_to_local (mb
, 1, offset_of_first_child_field
);
1111 mono_mb_emit_add_to_local (mb
, 0, offset_of_first_child_field
);
1112 mono_mb_emit_add_to_local (mb
, 1, usize
);
1117 if (klass
!= mono_class_try_get_safehandle_class ()) {
1118 if (mono_class_is_auto_layout (klass
)) {
1119 char *msg
= g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
1120 mono_type_full_name (m_class_get_byval_arg (klass
)));
1121 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1126 for (i
= 0; i
< info
->num_fields
; i
++) {
1127 MonoMarshalNative ntype
;
1128 MonoMarshalConv conv
;
1129 MonoType
*ftype
= info
->fields
[i
].field
->type
;
1132 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
1134 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
1137 ntype
= (MonoMarshalNative
)mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, m_class_is_unicode (klass
), &conv
);
1140 msize
= m_class_get_instance_size (klass
) - info
->fields
[i
].field
->offset
;
1141 usize
= info
->native_size
- info
->fields
[i
].offset
;
1143 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
1144 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
1147 if (klass
!= mono_class_try_get_safehandle_class ()){
1149 * FIXME: Should really check for usize==0 and msize>0, but we apply
1150 * the layout to the managed structure as well.
1153 if (mono_class_is_explicit_layout (klass
) && (usize
== 0)) {
1154 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
1155 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
1156 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
1157 "reference field at the same offset as another field.",
1158 mono_type_full_name (m_class_get_byval_arg (klass
)));
1163 case MONO_MARSHAL_CONV_NONE
: {
1166 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
1167 g_assert (!ftype
->byref
);
1168 if (ftype
->type
== MONO_TYPE_I
|| ftype
->type
== MONO_TYPE_U
) {
1169 mono_mb_emit_ldloc (mb
, 1);
1170 mono_mb_emit_ldloc (mb
, 0);
1171 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1172 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1183 case MONO_TYPE_BOOLEAN
:
1186 case MONO_TYPE_CHAR
:
1192 mono_mb_emit_ldloc (mb
, 1);
1193 mono_mb_emit_ldloc (mb
, 0);
1194 if (t
== MONO_TYPE_CHAR
&& ntype
== MONO_NATIVE_U1
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
1196 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1197 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
1199 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
1200 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1203 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
1204 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
1207 case MONO_TYPE_GENERICINST
:
1208 if (!mono_type_generic_inst_is_valuetype (ftype
)) {
1209 char *msg
= g_strdup_printf ("Generic type %s cannot be marshaled as field in a struct.",
1210 mono_type_full_name (ftype
));
1211 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1215 case MONO_TYPE_VALUETYPE
: {
1216 int src_var
, dst_var
;
1220 if (t
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (ftype
->data
.klass
)) {
1221 ftype
= mono_class_enum_basetype_internal (ftype
->data
.klass
);
1225 MonoType
*int_type
= mono_get_int_type ();
1226 src_var
= mono_mb_add_local (mb
, int_type
);
1227 dst_var
= mono_mb_add_local (mb
, int_type
);
1229 /* save the old src pointer */
1230 mono_mb_emit_ldloc (mb
, 0);
1231 mono_mb_emit_stloc (mb
, src_var
);
1232 /* save the old dst pointer */
1233 mono_mb_emit_ldloc (mb
, 1);
1234 mono_mb_emit_stloc (mb
, dst_var
);
1236 if (get_fixed_buffer_attr (info
->fields
[i
].field
, &etype
, &len
)) {
1237 emit_fixed_buf_conv (mb
, ftype
, etype
, len
, to_object
, &usize
);
1239 emit_struct_conv (mb
, mono_class_from_mono_type_internal (ftype
), to_object
);
1242 /* restore the old src pointer */
1243 mono_mb_emit_ldloc (mb
, src_var
);
1244 mono_mb_emit_stloc (mb
, 0);
1245 /* restore the old dst pointer */
1246 mono_mb_emit_ldloc (mb
, dst_var
);
1247 mono_mb_emit_stloc (mb
, 1);
1250 case MONO_TYPE_OBJECT
: {
1253 mono_mb_emit_ldloc (mb
, 1);
1254 mono_mb_emit_ldloc (mb
, 0);
1255 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetObjectForNativeVariant (), NULL
);
1256 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1258 mono_mb_emit_ldloc (mb
, 0);
1259 mono_mb_emit_managed_call (mb
, mono_get_Variant_Clear (), NULL
);
1262 mono_mb_emit_ldloc (mb
, 0);
1263 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
1264 mono_mb_emit_ldloc (mb
, 1);
1265 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetNativeVariantForObject (), NULL
);
1268 char *msg
= g_strdup_printf ("COM support was disabled at compilation time.");
1269 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1275 g_warning ("marshaling type %02x not implemented", ftype
->type
);
1276 g_assert_not_reached ();
1281 int src_var
, dst_var
;
1283 MonoType
*int_type
= mono_get_int_type ();
1284 src_var
= mono_mb_add_local (mb
, int_type
);
1285 dst_var
= mono_mb_add_local (mb
, int_type
);
1287 /* save the old src pointer */
1288 mono_mb_emit_ldloc (mb
, 0);
1289 mono_mb_emit_stloc (mb
, src_var
);
1290 /* save the old dst pointer */
1291 mono_mb_emit_ldloc (mb
, 1);
1292 mono_mb_emit_stloc (mb
, dst_var
);
1295 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1297 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1299 /* restore the old src pointer */
1300 mono_mb_emit_ldloc (mb
, src_var
);
1301 mono_mb_emit_stloc (mb
, 0);
1302 /* restore the old dst pointer */
1303 mono_mb_emit_ldloc (mb
, dst_var
);
1304 mono_mb_emit_stloc (mb
, 1);
1309 mono_mb_emit_add_to_local (mb
, 0, usize
);
1310 mono_mb_emit_add_to_local (mb
, 1, msize
);
1312 mono_mb_emit_add_to_local (mb
, 0, msize
);
1313 mono_mb_emit_add_to_local (mb
, 1, usize
);
1319 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
1321 emit_struct_conv_full (mb
, klass
, to_object
, 0, (MonoMarshalNative
)-1);
1325 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
1327 /* Call DestroyStructure */
1328 /* FIXME: Only do this if needed */
1329 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1330 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1331 mono_mb_emit_ldloc (mb
, struct_var
);
1332 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
1336 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, MonoJitICallId checkpoint_icall_id
)
1338 int pos_noabort
, pos_noex
;
1340 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1341 mono_mb_emit_byte (mb
, CEE_MONO_LDPTR_INT_REQ_FLAG
);
1342 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
1343 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1345 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1346 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
1348 mono_mb_emit_icall_id (mb
, checkpoint_icall_id
);
1349 /* Throw the exception returned by the checkpoint function, if any */
1350 mono_mb_emit_byte (mb
, CEE_DUP
);
1351 pos_noex
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1353 mono_mb_emit_byte (mb
, CEE_DUP
);
1354 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoException
, caught_in_unmanaged
));
1355 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1356 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
1358 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1359 mono_mb_emit_byte (mb
, CEE_MONO_RETHROW
);
1361 mono_mb_patch_branch (mb
, pos_noex
);
1362 mono_mb_emit_byte (mb
, CEE_POP
);
1364 mono_mb_patch_branch (mb
, pos_noabort
);
1368 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1370 // FIXME Put a boolean in MonoMethodBuilder instead.
1371 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
1374 emit_thread_interrupt_checkpoint_call (mb
, MONO_JIT_ICALL_mono_thread_interruption_checkpoint
);
1378 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1380 emit_thread_interrupt_checkpoint_call (mb
, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise
);
1384 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1386 emit_thread_interrupt_checkpoint (mb
);
1390 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1392 emit_thread_force_interrupt_checkpoint (mb
);
1396 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
1398 int i
, params_var
, tmp_var
;
1400 MonoType
*int_type
= mono_get_int_type ();
1401 /* allocate local (pointer) *params[] */
1402 params_var
= mono_mb_add_local (mb
, int_type
);
1403 /* allocate local (pointer) tmp */
1404 tmp_var
= mono_mb_add_local (mb
, int_type
);
1406 /* alloate space on stack to store an array of pointers to the arguments */
1407 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* (sig
->param_count
+ 1));
1408 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1409 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1410 mono_mb_emit_stloc (mb
, params_var
);
1413 mono_mb_emit_ldloc (mb
, params_var
);
1414 mono_mb_emit_stloc (mb
, tmp_var
);
1416 if (save_this
&& sig
->hasthis
) {
1417 mono_mb_emit_ldloc (mb
, tmp_var
);
1418 mono_mb_emit_ldarg_addr (mb
, 0);
1419 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1420 /* tmp = tmp + sizeof (gpointer) */
1421 if (sig
->param_count
)
1422 mono_mb_emit_add_to_local (mb
, tmp_var
, TARGET_SIZEOF_VOID_P
);
1426 for (i
= 0; i
< sig
->param_count
; i
++) {
1427 mono_mb_emit_ldloc (mb
, tmp_var
);
1428 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
1429 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1430 /* tmp = tmp + sizeof (gpointer) */
1431 if (i
< (sig
->param_count
- 1))
1432 mono_mb_emit_add_to_local (mb
, tmp_var
, TARGET_SIZEOF_VOID_P
);
1440 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
1442 MonoType
*t
= mono_type_get_underlying_type (return_type
);
1443 MonoType
*int_type
= mono_get_int_type ();
1445 if (return_type
->byref
)
1446 return_type
= int_type
;
1449 case MONO_TYPE_VOID
:
1450 g_assert_not_reached ();
1453 case MONO_TYPE_STRING
:
1454 case MONO_TYPE_CLASS
:
1455 case MONO_TYPE_OBJECT
:
1456 case MONO_TYPE_ARRAY
:
1457 case MONO_TYPE_SZARRAY
:
1461 case MONO_TYPE_BOOLEAN
:
1464 case MONO_TYPE_CHAR
:
1474 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type_internal (return_type
));
1475 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
1477 case MONO_TYPE_GENERICINST
:
1478 if (!mono_type_generic_inst_is_valuetype (t
))
1481 case MONO_TYPE_VALUETYPE
: {
1482 MonoClass
*klass
= mono_class_from_mono_type_internal (return_type
);
1483 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
1484 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
1488 case MONO_TYPE_MVAR
: {
1489 MonoClass
*klass
= mono_class_from_mono_type_internal (return_type
);
1490 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, klass
);
1494 g_warning ("type 0x%x not handled", return_type
->type
);
1495 g_assert_not_reached ();
1498 mono_mb_emit_byte (mb
, CEE_RET
);
1504 * Emit the call to the wrapper method from a runtime invoke wrapper.
1507 emit_invoke_call (MonoMethodBuilder
*mb
, MonoMethod
*method
,
1508 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
1510 gboolean virtual_
, gboolean need_direct_wrapper
)
1512 static MonoString
*string_dummy
= NULL
;
1514 int *tmp_nullable_locals
;
1515 gboolean void_ret
= FALSE
;
1516 gboolean string_ctor
= method
&& method
->string_ctor
;
1518 /* to make it work with our special string constructors */
1519 if (!string_dummy
) {
1522 // FIXME Allow for static construction of MonoString.
1524 SETUP_ICALL_FUNCTION
;
1527 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy
, MONO_ROOT_SOURCE_MARSHAL
, NULL
, "Marshal Dummy String");
1529 MonoStringHandle string_dummy_handle
= mono_string_new_utf8_len (mono_get_root_domain (), "dummy", 5, error
);
1530 string_dummy
= MONO_HANDLE_RAW (string_dummy_handle
);
1531 mono_error_assert_ok (error
);
1537 g_assert (sig
->hasthis
);
1538 g_assert (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
);
1543 if (mono_gc_is_moving ()) {
1544 mono_mb_emit_ptr (mb
, &string_dummy
);
1545 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1547 mono_mb_emit_ptr (mb
, string_dummy
);
1550 mono_mb_emit_ldarg (mb
, 0);
1554 tmp_nullable_locals
= g_new0 (int, sig
->param_count
);
1556 for (i
= 0; i
< sig
->param_count
; i
++) {
1557 MonoType
*t
= sig
->params
[i
];
1560 mono_mb_emit_ldarg (mb
, 1);
1562 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1563 mono_mb_emit_byte (mb
, CEE_ADD
);
1567 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1568 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
1569 * So to make this work we unbox it to a local variablee and push a reference to that.
1571 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
1572 tmp_nullable_locals
[i
] = mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_from_mono_type_internal (t
)));
1574 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type_internal (t
));
1575 mono_mb_emit_stloc (mb
, tmp_nullable_locals
[i
]);
1576 mono_mb_emit_ldloc_addr (mb
, tmp_nullable_locals
[i
]);
1581 type
= sig
->params
[i
]->type
;
1585 case MONO_TYPE_BOOLEAN
:
1589 case MONO_TYPE_CHAR
:
1598 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1599 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1601 case MONO_TYPE_STRING
:
1602 case MONO_TYPE_CLASS
:
1603 case MONO_TYPE_ARRAY
:
1605 case MONO_TYPE_SZARRAY
:
1606 case MONO_TYPE_OBJECT
:
1607 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1609 case MONO_TYPE_GENERICINST
:
1610 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
1611 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1615 t
= m_class_get_byval_arg (t
->data
.generic_class
->container_class
);
1618 case MONO_TYPE_VALUETYPE
:
1619 if (type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (t
->data
.klass
)) {
1620 type
= mono_class_enum_basetype_internal (t
->data
.klass
)->type
;
1623 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1624 if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig
->params
[i
]))) {
1625 /* Need to convert a boxed vtype to an mp to a Nullable struct */
1626 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1627 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1629 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1633 g_assert_not_reached ();
1638 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
1639 } else if (need_direct_wrapper
) {
1640 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1642 mono_mb_emit_ldarg (mb
, 3);
1643 mono_mb_emit_calli (mb
, callsig
);
1646 if (sig
->ret
->byref
) {
1647 /* perform indirect load and return by value */
1648 #ifdef ENABLE_NETCORE
1650 mono_mb_emit_byte (mb
, CEE_DUP
);
1651 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1652 mono_mb_emit_exception_full (mb
, "Mono", "NullByRefReturnException", NULL
);
1653 mono_mb_patch_branch (mb
, pos
);
1657 MonoType
* ret_byval
= m_class_get_byval_arg (mono_class_from_mono_type_internal (sig
->ret
));
1658 g_assert (!ret_byval
->byref
);
1659 // TODO: Handle null references
1660 ldind_op
= mono_type_to_ldind (ret_byval
);
1661 /* taken from similar code in mini-generic-sharing.c
1662 * we need to use mono_mb_emit_op to add method data when loading
1663 * a structure since method-to-ir needs this data for wrapper methods */
1664 if (ldind_op
== CEE_LDOBJ
)
1665 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (ret_byval
));
1667 mono_mb_emit_byte (mb
, ldind_op
);
1670 switch (sig
->ret
->type
) {
1671 case MONO_TYPE_VOID
:
1675 case MONO_TYPE_BOOLEAN
:
1676 case MONO_TYPE_CHAR
:
1689 case MONO_TYPE_VALUETYPE
:
1690 case MONO_TYPE_TYPEDBYREF
:
1691 case MONO_TYPE_GENERICINST
:
1692 /* box value types */
1693 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (sig
->ret
));
1695 case MONO_TYPE_STRING
:
1696 case MONO_TYPE_CLASS
:
1697 case MONO_TYPE_ARRAY
:
1698 case MONO_TYPE_SZARRAY
:
1699 case MONO_TYPE_OBJECT
:
1703 /* The result is an IntPtr */
1704 mono_mb_emit_op (mb
, CEE_BOX
, mono_defaults
.int_class
);
1707 g_assert_not_reached ();
1711 mono_mb_emit_stloc (mb
, loc_res
);
1713 /* Convert back nullable-byref arguments */
1714 for (i
= 0; i
< sig
->param_count
; i
++) {
1715 MonoType
*t
= sig
->params
[i
];
1718 * Box the result and put it back into the array, the caller will have
1719 * to obtain it from there.
1721 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
1722 mono_mb_emit_ldarg (mb
, 1);
1723 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1724 mono_mb_emit_byte (mb
, CEE_ADD
);
1726 mono_mb_emit_ldloc (mb
, tmp_nullable_locals
[i
]);
1727 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (t
));
1729 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1733 g_free (tmp_nullable_locals
);
1737 emit_runtime_invoke_body_ilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
1738 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
1739 gboolean virtual_
, gboolean need_direct_wrapper
)
1742 MonoExceptionClause
*clause
;
1743 int loc_res
, loc_exc
;
1745 mono_mb_set_param_names (mb
, param_names
);
1747 /* The wrapper looks like this:
1753 * } catch (Exception e) {
1761 MonoType
*object_type
= mono_get_object_type ();
1762 /* allocate local 0 (object) tmp */
1763 loc_res
= mono_mb_add_local (mb
, object_type
);
1764 /* allocate local 1 (object) exc */
1765 loc_exc
= mono_mb_add_local (mb
, object_type
);
1767 /* *exc is assumed to be initialized to NULL by the caller */
1769 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1770 labels
[0] = mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1775 labels
[1] = mono_mb_get_label (mb
);
1776 emit_thread_force_interrupt_checkpoint (mb
);
1777 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
1779 labels
[2] = mono_mb_emit_branch (mb
, CEE_LEAVE
);
1781 /* Add a try clause around the call */
1782 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
1783 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
1784 clause
->data
.catch_class
= mono_defaults
.exception_class
;
1785 clause
->try_offset
= labels
[1];
1786 clause
->try_len
= mono_mb_get_label (mb
) - labels
[1];
1788 clause
->handler_offset
= mono_mb_get_label (mb
);
1791 mono_mb_emit_stloc (mb
, loc_exc
);
1792 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1793 mono_mb_emit_ldloc (mb
, loc_exc
);
1794 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1796 mono_mb_emit_branch (mb
, CEE_LEAVE
);
1798 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
1800 mono_mb_set_clauses (mb
, 1, clause
);
1802 mono_mb_patch_branch (mb
, labels
[2]);
1803 mono_mb_emit_ldloc (mb
, loc_res
);
1804 mono_mb_emit_byte (mb
, CEE_RET
);
1809 mono_mb_patch_branch (mb
, labels
[0]);
1810 emit_thread_force_interrupt_checkpoint (mb
);
1811 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
1813 mono_mb_emit_ldloc (mb
, 0);
1814 mono_mb_emit_byte (mb
, CEE_RET
);
1818 emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder
*mb
)
1821 MonoExceptionClause
*clause
;
1823 MonoType
*object_type
= mono_get_object_type ();
1824 /* allocate local 0 (object) tmp */
1825 mono_mb_add_local (mb
, object_type
);
1826 /* allocate local 1 (object) exc */
1827 mono_mb_add_local (mb
, object_type
);
1829 /* cond set *exc to null */
1830 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1831 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1832 mono_mb_emit_byte (mb
, 3);
1833 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1834 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1835 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1837 emit_thread_force_interrupt_checkpoint (mb
);
1839 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1840 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1841 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1842 mono_mb_emit_byte (mb
, CEE_MONO_DYN_CALL
);
1844 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
1846 clause
= (MonoExceptionClause
*)mono_image_alloc0 (mono_defaults
.corlib
, sizeof (MonoExceptionClause
));
1847 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
1848 clause
->try_len
= mono_mb_get_label (mb
);
1851 clause
->data
.filter_offset
= mono_mb_get_label (mb
);
1853 mono_mb_emit_byte (mb
, CEE_POP
);
1854 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1855 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1856 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1857 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
1858 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1859 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
1861 clause
->handler_offset
= mono_mb_get_label (mb
);
1864 /* store exception */
1865 mono_mb_emit_stloc (mb
, 1);
1867 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1868 mono_mb_emit_ldloc (mb
, 1);
1869 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1871 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1872 mono_mb_emit_stloc (mb
, 0);
1874 mono_mb_emit_branch (mb
, CEE_LEAVE
);
1876 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
1878 mono_mb_set_clauses (mb
, 1, clause
);
1881 mono_mb_patch_branch (mb
, pos
);
1882 //mono_mb_emit_ldloc (mb, 0);
1883 mono_mb_emit_byte (mb
, CEE_RET
);
1887 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
1889 char *msg
= g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit", m_class_get_name_space (klass
), m_class_get_name (klass
));
1890 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1893 typedef struct EmitGCSafeTransitionBuilder
{
1894 MonoMethodBuilder
*mb
;
1895 gboolean func_param
;
1898 int coop_cominterop_fnptr
;
1900 } GCSafeTransitionBuilder
;
1903 gc_safe_transition_builder_init (GCSafeTransitionBuilder
*builder
, MonoMethodBuilder
*mb
, gboolean func_param
)
1906 builder
->func_param
= func_param
;
1907 builder
->coop_gc_var
= -1;
1909 builder
->coop_cominterop_fnptr
= -1;
1911 #if defined (TARGET_WASM)
1919 * adds locals for the gc safe transition to the method builder.
1922 gc_safe_transition_builder_add_locals (GCSafeTransitionBuilder
*builder
)
1924 MonoType
*int_type
= mono_get_int_type();
1925 /* local 4, the local to be used when calling the suspend funcs */
1926 builder
->coop_gc_var
= mono_mb_add_local (builder
->mb
, int_type
);
1928 if (!builder
->func_param
&& MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
)) {
1929 builder
->coop_cominterop_fnptr
= mono_mb_add_local (builder
->mb
, int_type
);
1936 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1940 gc_safe_transition_builder_emit_enter (GCSafeTransitionBuilder
*builder
, MonoMethod
*method
, gboolean aot
)
1943 // Perform an extra, early lookup of the function address, so any exceptions
1944 // potentially resulting from the lookup occur before entering blocking mode.
1945 if (!builder
->func_param
&& !MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
) && aot
) {
1946 mono_mb_emit_byte (builder
->mb
, MONO_CUSTOM_PREFIX
);
1947 mono_mb_emit_op (builder
->mb
, CEE_MONO_ICALL_ADDR
, method
);
1948 mono_mb_emit_byte (builder
->mb
, CEE_POP
); // Result not needed yet
1952 if (!builder
->func_param
&& MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
)) {
1953 mono_mb_emit_cominterop_get_function_pointer (builder
->mb
, method
);
1954 mono_mb_emit_stloc (builder
->mb
, builder
->coop_cominterop_fnptr
);
1958 mono_mb_emit_byte (builder
->mb
, MONO_CUSTOM_PREFIX
);
1959 mono_mb_emit_byte (builder
->mb
, CEE_MONO_GET_SP
);
1960 mono_mb_emit_icall (builder
->mb
, mono_threads_enter_gc_safe_region_unbalanced
);
1961 mono_mb_emit_stloc (builder
->mb
, builder
->coop_gc_var
);
1966 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1970 gc_safe_transition_builder_emit_exit (GCSafeTransitionBuilder
*builder
)
1972 mono_mb_emit_ldloc (builder
->mb
, builder
->coop_gc_var
);
1973 mono_mb_emit_byte (builder
->mb
, MONO_CUSTOM_PREFIX
);
1974 mono_mb_emit_byte (builder
->mb
, CEE_MONO_GET_SP
);
1975 mono_mb_emit_icall (builder
->mb
, mono_threads_exit_gc_safe_region_unbalanced
);
1979 gc_safe_transition_builder_cleanup (GCSafeTransitionBuilder
*builder
)
1982 builder
->coop_gc_var
= -1;
1984 builder
->coop_cominterop_fnptr
= -1;
1989 * emit_native_wrapper_ilgen:
1990 * \param image the image to use for looking up custom marshallers
1991 * \param sig The signature of the native function
1992 * \param piinfo Marshalling information
1993 * \param mspecs Marshalling information
1994 * \param aot whenever the created method will be compiled by the AOT compiler
1995 * \param method if non-NULL, the pinvoke method to call
1996 * \param check_exceptions Whenever to check for pending exceptions after the native call
1997 * \param func_param the function to call is passed as a boxed IntPtr as the first parameter
1998 * \param skip_gc_trans Whenever to skip GC transitions
2000 * generates IL code for the pinvoke wrapper, the generated code calls \p func .
2003 emit_native_wrapper_ilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
, gboolean skip_gc_trans
)
2005 EmitMarshalContext m
;
2006 MonoMethodSignature
*csig
;
2008 int i
, argnum
, *tmp_locals
;
2009 int type
, param_shift
= 0;
2010 int func_addr_local
= -1;
2011 gboolean need_gc_safe
= FALSE
;
2012 GCSafeTransitionBuilder gc_safe_transition_builder
;
2014 memset (&m
, 0, sizeof (m
));
2020 need_gc_safe
= gc_safe_transition_builder_init (&gc_safe_transition_builder
, mb
, func_param
);
2022 /* we copy the signature, so that we can set pinvoke to 0 */
2024 /* The function address is passed as the first argument */
2025 g_assert (!sig
->hasthis
);
2028 csig
= mono_metadata_signature_dup_full (get_method_image (mb
->method
), sig
);
2036 MonoType
*int_type
= mono_get_int_type ();
2037 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
2038 /* we allocate local for use with emit_struct_conv() */
2039 /* allocate local 0 (pointer) src_ptr */
2040 mono_mb_add_local (mb
, int_type
);
2041 /* allocate local 1 (pointer) dst_ptr */
2042 mono_mb_add_local (mb
, int_type
);
2043 /* allocate local 2 (boolean) delete_old */
2044 mono_mb_add_local (mb
, boolean_type
);
2046 /* delete_old = FALSE */
2047 mono_mb_emit_icon (mb
, 0);
2048 mono_mb_emit_stloc (mb
, 2);
2050 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
2051 /* allocate local 3 to store the return value */
2052 mono_mb_add_local (mb
, sig
->ret
);
2056 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder
);
2058 #ifdef ENABLE_NETCORE
2059 if (!func
&& !aot
&& !func_param
&& !MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
2061 * On netcore, its possible to register pinvoke resolvers at runtime, so
2062 * a pinvoke lookup can fail, and then succeed later. So if the
2063 * original lookup failed, do a lookup every time until it
2065 * This adds some overhead, but only when the pinvoke lookup
2066 * was not initially successful.
2069 func_addr_local
= mono_mb_add_local (mb
, int_type
);
2071 int cache_local
= mono_mb_add_local (mb
, int_type
);
2072 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2073 mono_mb_emit_op (mb
, CEE_MONO_PINVOKE_ADDR_CACHE
, &piinfo
->method
);
2074 mono_mb_emit_stloc (mb
, cache_local
);
2076 mono_mb_emit_ldloc (mb
, cache_local
);
2077 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2078 int pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
2080 mono_mb_emit_ldloc (mb
, cache_local
);
2081 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2082 mono_mb_emit_op (mb
, CEE_MONO_METHODCONST
, &piinfo
->method
);
2083 mono_mb_emit_icall (mb
, mono_marshal_lookup_pinvoke
);
2084 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2086 mono_mb_patch_branch (mb
, pos
);
2087 mono_mb_emit_ldloc (mb
, cache_local
);
2088 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2089 mono_mb_emit_stloc (mb
, func_addr_local
);
2094 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
2096 * ret = method (...);
2098 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
2105 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
2106 m
.vtaddr_var
= mono_mb_add_local (mb
, int_type
);
2108 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
2109 /* Return type custom marshaling */
2111 * Since we can't determine the return type of the unmanaged function,
2112 * we assume it returns a pointer, and pass that pointer to
2113 * MarshalNativeToManaged.
2115 csig
->ret
= int_type
;
2118 /* we first do all conversions */
2119 tmp_locals
= g_newa (int, sig
->param_count
);
2120 m
.orig_conv_args
= g_newa (int, sig
->param_count
+ 1);
2122 for (i
= 0; i
< sig
->param_count
; i
++) {
2123 tmp_locals
[i
] = mono_emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
2126 // In coop mode need to register blocking state during native call
2128 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder
, &piinfo
->method
, aot
);
2130 /* push all arguments */
2133 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
2135 for (i
= 0; i
< sig
->param_count
; i
++) {
2136 mono_emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
2139 /* call the native method */
2141 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
2142 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_defaults
.int_class
);
2143 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2144 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
2145 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2146 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
2148 mono_mb_emit_calli (mb
, csig
);
2149 } else if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
2151 mono_mb_emit_ldloc (mb
, gc_safe_transition_builder
.coop_cominterop_fnptr
);
2152 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
2153 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2154 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
2156 mono_mb_emit_cominterop_call_function_pointer (mb
, csig
);
2158 g_assert_not_reached ();
2161 if (func_addr_local
!= -1) {
2162 mono_mb_emit_ldloc (mb
, func_addr_local
);
2165 /* Reuse the ICALL_ADDR opcode for pinvokes too */
2166 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2167 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
2170 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
2171 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2172 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
2174 if (func_addr_local
!= -1 || aot
)
2175 mono_mb_emit_calli (mb
, csig
);
2177 mono_mb_emit_native_call (mb
, csig
, func
);
2180 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
2181 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
2182 mono_class_init_internal (klass
);
2183 if (!(mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
))) {
2184 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
2185 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2186 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
2187 mono_mb_emit_stloc (mb
, m
.vtaddr_var
);
2191 /* Unblock before converting the result, since that can involve calls into the runtime */
2193 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder
);
2195 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder
);
2197 /* convert the result */
2198 if (!sig
->ret
->byref
) {
2199 MonoMarshalSpec
*spec
= mspecs
[0];
2200 type
= sig
->ret
->type
;
2202 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
2203 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2207 case MONO_TYPE_VOID
:
2209 case MONO_TYPE_VALUETYPE
:
2210 klass
= sig
->ret
->data
.klass
;
2211 if (m_class_is_enumtype (klass
)) {
2212 type
= mono_class_enum_basetype_internal (sig
->ret
->data
.klass
)->type
;
2215 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2229 case MONO_TYPE_FNPTR
:
2230 case MONO_TYPE_STRING
:
2231 case MONO_TYPE_CLASS
:
2232 case MONO_TYPE_OBJECT
:
2233 case MONO_TYPE_BOOLEAN
:
2234 case MONO_TYPE_ARRAY
:
2235 case MONO_TYPE_SZARRAY
:
2236 case MONO_TYPE_CHAR
:
2238 case MONO_TYPE_GENERICINST
:
2239 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2241 case MONO_TYPE_TYPEDBYREF
:
2243 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
2244 g_assert_not_reached ();
2248 mono_mb_emit_stloc (mb
, 3);
2252 * Need to call this after converting the result since MONO_VTADDR needs
2253 * to be adjacent to the call instruction.
2255 if (check_exceptions
)
2256 emit_thread_interrupt_checkpoint (mb
);
2258 /* we need to convert byref arguments back and free string arrays */
2259 for (i
= 0; i
< sig
->param_count
; i
++) {
2260 MonoType
*t
= sig
->params
[i
];
2261 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
2263 argnum
= i
+ param_shift
;
2265 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
2266 mono_emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
2271 case MONO_TYPE_STRING
:
2272 case MONO_TYPE_VALUETYPE
:
2273 case MONO_TYPE_CLASS
:
2274 case MONO_TYPE_OBJECT
:
2275 case MONO_TYPE_SZARRAY
:
2276 case MONO_TYPE_BOOLEAN
:
2277 mono_emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
2284 if (!MONO_TYPE_IS_VOID(sig
->ret
))
2285 mono_mb_emit_ldloc (mb
, 3);
2287 mono_mb_emit_byte (mb
, CEE_RET
);
2291 * The code directly following this is the cache hit, value positive branch
2293 * This function takes a new method builder with 0 locals and adds two locals
2294 * to create multiple out-branches and the fall through state of having the object
2295 * on the stack after a cache miss
2298 generate_check_cache (int obj_arg_position
, int class_arg_position
, int cache_arg_position
, // In-parameters
2299 int *null_obj
, int *cache_hit_neg
, int *cache_hit_pos
, // Out-parameters
2300 MonoMethodBuilder
*mb
)
2304 MonoType
*int_type
= mono_get_int_type ();
2305 /* allocate local 0 (pointer) obj_vtable */
2306 mono_mb_add_local (mb
, int_type
);
2307 /* allocate local 1 (pointer) cached_vtable */
2308 mono_mb_add_local (mb
, int_type
);
2311 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2312 *null_obj
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2314 /*obj_vtable = obj->vtable;*/
2315 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2316 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2317 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2318 mono_mb_emit_stloc (mb
, 0);
2320 /* cached_vtable = *cache*/
2321 mono_mb_emit_ldarg (mb
, cache_arg_position
);
2322 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2323 mono_mb_emit_stloc (mb
, 1);
2325 mono_mb_emit_ldloc (mb
, 1);
2326 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
2327 mono_mb_emit_i4 (mb
, ~0x1);
2328 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2329 mono_mb_emit_byte (mb
, CEE_AND
);
2330 mono_mb_emit_ldloc (mb
, 0);
2331 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
2332 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
2334 /*return (cached_vtable & 0x1) ? NULL : obj;*/
2335 mono_mb_emit_ldloc (mb
, 1);
2336 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
2337 mono_mb_emit_byte (mb
, CEE_CONV_U
);
2338 mono_mb_emit_byte (mb
, CEE_AND
);
2339 *cache_hit_neg
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
2340 *cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BR
);
2343 mono_mb_patch_branch (mb
, cache_miss_pos
);
2346 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2347 mono_mb_emit_ldarg (mb
, class_arg_position
);
2348 mono_mb_emit_ldarg (mb
, cache_arg_position
);
2349 mono_mb_emit_icall (mb
, mono_marshal_isinst_with_cache
);
2353 emit_castclass_ilgen (MonoMethodBuilder
*mb
)
2355 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
, invalid_cast_pos
;
2356 const int obj_arg_position
= TYPECHECK_OBJECT_ARG_POS
;
2357 const int class_arg_position
= TYPECHECK_CLASS_ARG_POS
;
2358 const int cache_arg_position
= TYPECHECK_CACHE_ARG_POS
;
2360 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
2361 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
2362 invalid_cast_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2365 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
2366 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2367 mono_mb_emit_byte (mb
, CEE_RET
);
2370 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
2371 mono_mb_patch_branch (mb
, invalid_cast_pos
);
2372 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
2375 mono_mb_patch_branch (mb
, return_null_pos
);
2376 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2377 mono_mb_emit_byte (mb
, CEE_RET
);
2381 emit_isinst_ilgen (MonoMethodBuilder
*mb
)
2383 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
;
2384 const int obj_arg_position
= TYPECHECK_OBJECT_ARG_POS
;
2385 const int class_arg_position
= TYPECHECK_CLASS_ARG_POS
;
2386 const int cache_arg_position
= TYPECHECK_CACHE_ARG_POS
;
2388 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
2389 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
2390 // Return the object gotten via the slow path.
2391 mono_mb_emit_byte (mb
, CEE_RET
);
2394 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
2395 mono_mb_patch_branch (mb
, return_null_pos
);
2396 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2397 mono_mb_emit_byte (mb
, CEE_RET
);
2400 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
2401 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2402 mono_mb_emit_byte (mb
, CEE_RET
);
2406 load_array_element_address (MonoMethodBuilder
*mb
)
2408 mono_mb_emit_ldarg (mb
, 0);
2409 mono_mb_emit_ldarg (mb
, 1);
2410 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
2414 load_array_class (MonoMethodBuilder
*mb
, int aklass
)
2416 mono_mb_emit_ldarg (mb
, 0);
2417 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2418 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2419 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
2420 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2421 mono_mb_emit_ldflda (mb
, m_class_offsetof_element_class ());
2422 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2423 mono_mb_emit_stloc (mb
, aklass
);
2427 load_value_class (MonoMethodBuilder
*mb
, int vklass
)
2429 mono_mb_emit_ldarg (mb
, 2);
2430 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2431 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2432 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
2433 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2434 mono_mb_emit_stloc (mb
, vklass
);
2438 emit_marshal_array_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2439 MonoMarshalSpec
*spec
,
2440 int conv_arg
, MonoType
**conv_arg_type
,
2441 MarshalAction action
)
2443 MonoMethodBuilder
*mb
= m
->mb
;
2444 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
2445 gboolean need_convert
, need_free
;
2446 MonoMarshalNative encoding
;
2448 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
2449 MonoType
*int_type
= mono_get_int_type ();
2450 MonoType
*object_type
= mono_get_object_type ();
2452 MonoClass
*eklass
= m_class_get_element_class (klass
);
2455 case MARSHAL_ACTION_CONV_IN
:
2456 *conv_arg_type
= object_type
;
2457 conv_arg
= mono_mb_add_local (mb
, object_type
);
2459 if (m_class_is_blittable (eklass
)) {
2460 mono_mb_emit_ldarg (mb
, argnum
);
2462 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2463 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
, NULL
));
2464 mono_mb_emit_stloc (mb
, conv_arg
);
2466 guint32 label1
, label2
, label3
;
2467 int index_var
, src_var
, dest_ptr
, esize
;
2468 MonoMarshalConv conv
;
2469 gboolean is_string
= FALSE
;
2471 dest_ptr
= mono_mb_add_local (mb
, int_type
);
2473 if (eklass
== mono_defaults
.string_class
) {
2475 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2477 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2479 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
2482 conv
= MONO_MARSHAL_CONV_INVALID
;
2484 if (is_string
&& conv
== MONO_MARSHAL_CONV_INVALID
) {
2485 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
2486 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2490 src_var
= mono_mb_add_local (mb
, object_type
);
2491 mono_mb_emit_ldarg (mb
, argnum
);
2493 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2494 mono_mb_emit_stloc (mb
, src_var
);
2497 mono_mb_emit_ldloc (mb
, src_var
);
2498 mono_mb_emit_stloc (mb
, conv_arg
);
2499 mono_mb_emit_ldloc (mb
, src_var
);
2500 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2503 esize
= TARGET_SIZEOF_VOID_P
;
2504 else if (eklass
== mono_defaults
.char_class
) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
2505 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2507 esize
= mono_class_native_size (eklass
, NULL
);
2509 /* allocate space for the native struct and store the address */
2510 mono_mb_emit_icon (mb
, esize
);
2511 mono_mb_emit_ldloc (mb
, src_var
);
2512 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2514 if (eklass
== mono_defaults
.string_class
) {
2515 /* Make the array bigger for the terminating null */
2516 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
2517 mono_mb_emit_byte (mb
, CEE_ADD
);
2519 mono_mb_emit_byte (mb
, CEE_MUL
);
2520 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2521 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2522 mono_mb_emit_stloc (mb
, conv_arg
);
2524 mono_mb_emit_ldloc (mb
, conv_arg
);
2525 mono_mb_emit_stloc (mb
, dest_ptr
);
2527 /* Emit marshalling loop */
2528 index_var
= mono_mb_add_local (mb
, int_type
);
2529 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2530 mono_mb_emit_stloc (mb
, index_var
);
2531 label2
= mono_mb_get_label (mb
);
2532 mono_mb_emit_ldloc (mb
, index_var
);
2533 mono_mb_emit_ldloc (mb
, src_var
);
2534 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2535 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2537 /* Emit marshalling code */
2541 mono_mb_emit_ldloc (mb
, dest_ptr
);
2542 mono_mb_emit_ldloc (mb
, src_var
);
2543 mono_mb_emit_ldloc (mb
, index_var
);
2544 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2545 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2546 mono_mb_emit_byte (mb
, stind_op
);
2548 /* set the src_ptr */
2549 mono_mb_emit_ldloc (mb
, src_var
);
2550 mono_mb_emit_ldloc (mb
, index_var
);
2551 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2552 mono_mb_emit_stloc (mb
, 0);
2555 mono_mb_emit_ldloc (mb
, dest_ptr
);
2556 mono_mb_emit_stloc (mb
, 1);
2558 /* emit valuetype conversion code */
2559 emit_struct_conv_full (mb
, eklass
, FALSE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
2562 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2563 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
2565 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2567 mono_mb_patch_branch (mb
, label3
);
2569 if (eklass
== mono_defaults
.string_class
) {
2570 /* Null terminate */
2571 mono_mb_emit_ldloc (mb
, dest_ptr
);
2572 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2573 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2576 mono_mb_patch_branch (mb
, label1
);
2581 case MARSHAL_ACTION_CONV_OUT
:
2582 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
2583 need_convert
= ((eklass
== mono_defaults
.char_class
) && (encoding
== MONO_NATIVE_LPWSTR
)) || (eklass
== mono_class_try_get_stringbuilder_class ()) || (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
2584 need_free
= mono_marshal_need_free (m_class_get_byval_arg (eklass
), m
->piinfo
, spec
);
2586 if ((t
->attrs
& PARAM_ATTRIBUTE_OUT
) && spec
&& spec
->native
== MONO_NATIVE_LPARRAY
&& spec
->data
.array_data
.param_num
!= -1) {
2587 int param_num
= spec
->data
.array_data
.param_num
;
2588 MonoType
*param_type
;
2590 param_type
= m
->sig
->params
[param_num
];
2592 if (param_type
->byref
&& param_type
->type
!= MONO_TYPE_I4
) {
2593 char *msg
= g_strdup ("Not implemented.");
2594 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2599 mono_mb_emit_ldarg (mb
, argnum
);
2601 /* Create the managed array */
2602 mono_mb_emit_ldarg (mb
, param_num
);
2603 if (m
->sig
->params
[param_num
]->byref
)
2604 // FIXME: Support other types
2605 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
2606 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
2607 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
2608 /* Store into argument */
2609 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2613 if (need_convert
|| need_free
) {
2614 /* FIXME: Optimize blittable case */
2615 guint32 label1
, label2
, label3
;
2616 int index_var
, src_ptr
, loc
, esize
;
2618 if ((eklass
== mono_class_try_get_stringbuilder_class ()) || (eklass
== mono_defaults
.string_class
))
2619 esize
= TARGET_SIZEOF_VOID_P
;
2620 else if (eklass
== mono_defaults
.char_class
)
2621 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2623 esize
= mono_class_native_size (eklass
, NULL
);
2624 src_ptr
= mono_mb_add_local (mb
, int_type
);
2625 loc
= mono_mb_add_local (mb
, int_type
);
2628 mono_mb_emit_ldarg (mb
, argnum
);
2630 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2631 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2633 mono_mb_emit_ldloc (mb
, conv_arg
);
2634 mono_mb_emit_stloc (mb
, src_ptr
);
2636 /* Emit marshalling loop */
2637 index_var
= mono_mb_add_local (mb
, int_type
);
2638 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2639 mono_mb_emit_stloc (mb
, index_var
);
2640 label2
= mono_mb_get_label (mb
);
2641 mono_mb_emit_ldloc (mb
, index_var
);
2642 mono_mb_emit_ldarg (mb
, argnum
);
2644 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2645 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2646 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2648 /* Emit marshalling code */
2650 if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2651 gboolean need_free2
;
2652 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
2654 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2657 mono_mb_emit_ldarg (mb
, argnum
);
2659 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2660 mono_mb_emit_ldloc (mb
, index_var
);
2661 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2664 mono_mb_emit_ldloc (mb
, src_ptr
);
2665 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2667 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
2671 mono_mb_emit_ldloc (mb
, src_ptr
);
2672 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2674 mono_mb_emit_icall (mb
, mono_marshal_free
);
2677 else if (eklass
== mono_defaults
.string_class
) {
2680 mono_mb_emit_ldloc (mb
, src_ptr
);
2681 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2683 mono_mb_emit_icall (mb
, mono_marshal_free
);
2688 /* set the src_ptr */
2689 mono_mb_emit_ldloc (mb
, src_ptr
);
2690 mono_mb_emit_stloc (mb
, 0);
2693 mono_mb_emit_ldarg (mb
, argnum
);
2695 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2696 mono_mb_emit_ldloc (mb
, index_var
);
2697 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2698 mono_mb_emit_stloc (mb
, 1);
2700 /* emit valuetype conversion code */
2701 emit_struct_conv_full (mb
, eklass
, TRUE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
2705 mono_mb_emit_ldloc (mb
, src_ptr
);
2706 mono_mb_emit_stloc (mb
, loc
);
2708 emit_struct_free (mb
, eklass
, loc
);
2712 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2713 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
2715 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2717 mono_mb_patch_branch (mb
, label1
);
2718 mono_mb_patch_branch (mb
, label3
);
2721 if (m_class_is_blittable (eklass
)) {
2722 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
2724 mono_mb_emit_ldarg (mb
, argnum
);
2726 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2727 mono_mb_emit_ldloc (mb
, conv_arg
);
2728 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY
, NULL
));
2733 case MARSHAL_ACTION_PUSH
:
2735 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
2737 mono_mb_emit_ldloc (mb
, conv_arg
);
2740 case MARSHAL_ACTION_CONV_RESULT
: {
2741 mono_mb_emit_byte (mb
, CEE_POP
);
2742 char *msg
= g_strdup_printf ("Cannot marshal 'return value': Invalid managed/unmanaged type combination.");
2743 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2747 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
2748 guint32 label1
, label2
, label3
;
2749 int index_var
, src_ptr
, esize
, param_num
, num_elem
;
2750 MonoMarshalConv conv
;
2751 gboolean is_string
= FALSE
;
2753 conv_arg
= mono_mb_add_local (mb
, object_type
);
2754 *conv_arg_type
= int_type
;
2757 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
2758 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2762 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
2763 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2767 switch (spec
->native
) {
2768 case MONO_NATIVE_LPARRAY
:
2770 case MONO_NATIVE_SAFEARRAY
:
2772 if (spec
->data
.safearray_data
.elem_type
!= MONO_VARIANT_VARIANT
) {
2773 char *msg
= g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented.");
2774 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2777 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
2780 char *msg
= g_strdup ("Unsupported array type marshalling to managed code.");
2781 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2786 /* FIXME: t is from the method which is wrapped, not the delegate type */
2787 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
2789 param_num
= spec
->data
.array_data
.param_num
;
2790 num_elem
= spec
->data
.array_data
.num_elem
;
2791 if (spec
->data
.array_data
.elem_mult
== 0)
2792 /* param_num is not specified */
2795 if (param_num
== -1) {
2796 if (num_elem
<= 0) {
2797 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
2798 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2803 /* FIXME: Optimize blittable case */
2805 if (eklass
== mono_defaults
.string_class
) {
2807 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
2809 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2811 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
2814 conv
= MONO_MARSHAL_CONV_INVALID
;
2816 mono_marshal_load_type_info (eklass
);
2819 esize
= TARGET_SIZEOF_VOID_P
;
2821 esize
= mono_class_native_size (eklass
, NULL
);
2822 src_ptr
= mono_mb_add_local (mb
, int_type
);
2824 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2825 mono_mb_emit_stloc (mb
, conv_arg
);
2827 /* Check param index */
2828 if (param_num
!= -1) {
2829 if (param_num
>= m
->sig
->param_count
) {
2830 char *msg
= g_strdup ("Array size control parameter index is out of range.");
2831 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2834 switch (m
->sig
->params
[param_num
]->type
) {
2847 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
2848 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2855 mono_mb_emit_ldarg (mb
, argnum
);
2856 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2858 mono_mb_emit_ldarg (mb
, argnum
);
2859 mono_mb_emit_stloc (mb
, src_ptr
);
2861 /* Create managed array */
2863 * The LPArray marshalling spec says that sometimes param_num starts
2864 * from 1, sometimes it starts from 0. But MS seems to allways start
2868 if (param_num
== -1) {
2869 mono_mb_emit_icon (mb
, num_elem
);
2871 mono_mb_emit_ldarg (mb
, param_num
);
2873 mono_mb_emit_icon (mb
, num_elem
);
2874 mono_mb_emit_byte (mb
, CEE_ADD
);
2876 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
2879 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
2880 mono_mb_emit_stloc (mb
, conv_arg
);
2882 if (m_class_is_blittable (eklass
)) {
2883 mono_mb_emit_ldloc (mb
, conv_arg
);
2884 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2885 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
2886 mono_mb_emit_byte (mb
, CEE_ADD
);
2887 mono_mb_emit_ldarg (mb
, argnum
);
2888 mono_mb_emit_ldloc (mb
, conv_arg
);
2889 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2890 mono_mb_emit_icon (mb
, esize
);
2891 mono_mb_emit_byte (mb
, CEE_MUL
);
2892 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2893 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2894 mono_mb_patch_branch (mb
, label1
);
2898 /* Emit marshalling loop */
2899 index_var
= mono_mb_add_local (mb
, int_type
);
2900 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2901 mono_mb_emit_stloc (mb
, index_var
);
2902 label2
= mono_mb_get_label (mb
);
2903 mono_mb_emit_ldloc (mb
, index_var
);
2904 mono_mb_emit_ldloc (mb
, conv_arg
);
2905 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2906 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2908 /* Emit marshalling code */
2910 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2912 mono_mb_emit_ldloc (mb
, conv_arg
);
2913 mono_mb_emit_ldloc (mb
, index_var
);
2915 mono_mb_emit_ldloc (mb
, src_ptr
);
2916 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2918 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
2919 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
2922 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2923 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2927 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2928 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
2930 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2932 mono_mb_patch_branch (mb
, label1
);
2933 mono_mb_patch_branch (mb
, label3
);
2937 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
2938 guint32 label1
, label2
, label3
;
2939 int index_var
, dest_ptr
, esize
, param_num
, num_elem
;
2940 MonoMarshalConv conv
;
2941 gboolean is_string
= FALSE
;
2944 /* Already handled in CONV_IN */
2947 /* These are already checked in CONV_IN */
2948 g_assert (!t
->byref
);
2949 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
2950 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
2952 param_num
= spec
->data
.array_data
.param_num
;
2953 num_elem
= spec
->data
.array_data
.num_elem
;
2955 if (spec
->data
.array_data
.elem_mult
== 0)
2956 /* param_num is not specified */
2959 if (param_num
== -1) {
2960 if (num_elem
<= 0) {
2961 g_assert_not_reached ();
2965 /* FIXME: Optimize blittable case */
2967 if (eklass
== mono_defaults
.string_class
) {
2969 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2971 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2973 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
2976 conv
= MONO_MARSHAL_CONV_INVALID
;
2978 mono_marshal_load_type_info (eklass
);
2981 esize
= TARGET_SIZEOF_VOID_P
;
2983 esize
= mono_class_native_size (eklass
, NULL
);
2985 dest_ptr
= mono_mb_add_local (mb
, int_type
);
2988 mono_mb_emit_ldloc (mb
, conv_arg
);
2989 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2991 mono_mb_emit_ldarg (mb
, argnum
);
2992 mono_mb_emit_stloc (mb
, dest_ptr
);
2994 if (m_class_is_blittable (eklass
)) {
2996 mono_mb_emit_ldarg (mb
, argnum
);
2998 mono_mb_emit_ldloc (mb
, conv_arg
);
2999 mono_mb_emit_byte (mb
, CEE_CONV_I
);
3000 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
3001 mono_mb_emit_byte (mb
, CEE_ADD
);
3003 mono_mb_emit_ldloc (mb
, conv_arg
);
3004 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3005 mono_mb_emit_icon (mb
, esize
);
3006 mono_mb_emit_byte (mb
, CEE_MUL
);
3007 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
3008 mono_mb_emit_byte (mb
, CEE_CPBLK
);
3012 /* Emit marshalling loop */
3013 index_var
= mono_mb_add_local (mb
, int_type
);
3014 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3015 mono_mb_emit_stloc (mb
, index_var
);
3016 label2
= mono_mb_get_label (mb
);
3017 mono_mb_emit_ldloc (mb
, index_var
);
3018 mono_mb_emit_ldloc (mb
, conv_arg
);
3019 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3020 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
3022 /* Emit marshalling code */
3025 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
3028 mono_mb_emit_ldloc (mb
, dest_ptr
);
3031 mono_mb_emit_ldloc (mb
, conv_arg
);
3032 mono_mb_emit_ldloc (mb
, index_var
);
3034 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3036 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
3037 mono_mb_emit_byte (mb
, stind_op
);
3040 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
3041 mono_mb_emit_exception_marshal_directive (mb
, msg
);
3045 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3046 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
3048 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
3050 mono_mb_patch_branch (mb
, label1
);
3051 mono_mb_patch_branch (mb
, label3
);
3055 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
3056 guint32 label1
, label2
, label3
;
3057 int index_var
, src
, dest
, esize
;
3058 MonoMarshalConv conv
= MONO_MARSHAL_CONV_INVALID
;
3059 gboolean is_string
= FALSE
;
3061 g_assert (!t
->byref
);
3063 mono_marshal_load_type_info (eklass
);
3065 if (eklass
== mono_defaults
.string_class
) {
3067 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
3070 g_assert_not_reached ();
3074 esize
= TARGET_SIZEOF_VOID_P
;
3075 else if (eklass
== mono_defaults
.char_class
)
3076 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
3078 esize
= mono_class_native_size (eklass
, NULL
);
3080 src
= mono_mb_add_local (mb
, object_type
);
3081 dest
= mono_mb_add_local (mb
, int_type
);
3083 mono_mb_emit_stloc (mb
, src
);
3084 mono_mb_emit_ldloc (mb
, src
);
3085 mono_mb_emit_stloc (mb
, 3);
3087 /* Check for null */
3088 mono_mb_emit_ldloc (mb
, src
);
3089 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3091 /* Allocate native array */
3092 mono_mb_emit_icon (mb
, esize
);
3093 mono_mb_emit_ldloc (mb
, src
);
3094 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3096 if (eklass
== mono_defaults
.string_class
) {
3097 /* Make the array bigger for the terminating null */
3098 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3099 mono_mb_emit_byte (mb
, CEE_ADD
);
3101 mono_mb_emit_byte (mb
, CEE_MUL
);
3102 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
3103 mono_mb_emit_stloc (mb
, dest
);
3104 mono_mb_emit_ldloc (mb
, dest
);
3105 mono_mb_emit_stloc (mb
, 3);
3107 /* Emit marshalling loop */
3108 index_var
= mono_mb_add_local (mb
, int_type
);
3109 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3110 mono_mb_emit_stloc (mb
, index_var
);
3111 label2
= mono_mb_get_label (mb
);
3112 mono_mb_emit_ldloc (mb
, index_var
);
3113 mono_mb_emit_ldloc (mb
, src
);
3114 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3115 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
3117 /* Emit marshalling code */
3120 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
3123 mono_mb_emit_ldloc (mb
, dest
);
3126 mono_mb_emit_ldloc (mb
, src
);
3127 mono_mb_emit_ldloc (mb
, index_var
);
3129 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
3131 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
3132 mono_mb_emit_byte (mb
, stind_op
);
3135 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
3136 mono_mb_emit_exception_marshal_directive (mb
, msg
);
3140 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3141 mono_mb_emit_add_to_local (mb
, dest
, esize
);
3143 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
3145 mono_mb_patch_branch (mb
, label3
);
3146 mono_mb_patch_branch (mb
, label1
);
3150 g_assert_not_reached ();
3156 emit_marshal_boolean_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3157 MonoMarshalSpec
*spec
,
3158 int conv_arg
, MonoType
**conv_arg_type
,
3159 MarshalAction action
)
3161 MonoMethodBuilder
*mb
= m
->mb
;
3162 MonoType
*int_type
= mono_get_int_type ();
3163 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
3166 case MARSHAL_ACTION_CONV_IN
: {
3167 MonoType
*local_type
;
3169 guint8 ldc_op
= CEE_LDC_I4_1
;
3171 local_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, &ldc_op
);
3173 *conv_arg_type
= int_type
;
3175 *conv_arg_type
= local_type
;
3176 conv_arg
= mono_mb_add_local (mb
, local_type
);
3178 mono_mb_emit_ldarg (mb
, argnum
);
3180 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
3181 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3182 mono_mb_emit_byte (mb
, ldc_op
);
3183 mono_mb_emit_stloc (mb
, conv_arg
);
3184 mono_mb_patch_branch (mb
, label_false
);
3189 case MARSHAL_ACTION_CONV_OUT
:
3191 int label_false
, label_end
;
3195 mono_mb_emit_ldarg (mb
, argnum
);
3196 mono_mb_emit_ldloc (mb
, conv_arg
);
3198 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3199 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3201 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
3202 mono_mb_patch_branch (mb
, label_false
);
3203 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3204 mono_mb_patch_branch (mb
, label_end
);
3206 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
3210 case MARSHAL_ACTION_PUSH
:
3212 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
3214 mono_mb_emit_ldloc (mb
, conv_arg
);
3216 mono_mb_emit_ldarg (mb
, argnum
);
3219 case MARSHAL_ACTION_CONV_RESULT
:
3220 /* maybe we need to make sure that it fits within 8 bits */
3221 mono_mb_emit_stloc (mb
, 3);
3224 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3225 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3226 guint8 ldop
= CEE_LDIND_I4
;
3227 int label_null
, label_false
;
3229 conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, &ldop
);
3230 conv_arg
= mono_mb_add_local (mb
, boolean_type
);
3233 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3235 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3238 mono_mb_emit_ldarg (mb
, argnum
);
3242 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3243 mono_mb_emit_ldarg (mb
, argnum
);
3244 mono_mb_emit_byte (mb
, ldop
);
3248 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3249 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3250 mono_mb_emit_stloc (mb
, conv_arg
);
3251 mono_mb_patch_branch (mb
, label_false
);
3254 mono_mb_patch_branch (mb
, label_null
);
3258 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
3259 guint8 stop
= CEE_STIND_I4
;
3260 guint8 ldc_op
= CEE_LDC_I4_1
;
3261 int label_null
,label_false
, label_end
;
3266 switch (spec
->native
) {
3267 case MONO_NATIVE_I1
:
3268 case MONO_NATIVE_U1
:
3269 stop
= CEE_STIND_I1
;
3271 case MONO_NATIVE_VARIANTBOOL
:
3272 stop
= CEE_STIND_I2
;
3273 ldc_op
= CEE_LDC_I4_M1
;
3281 mono_mb_emit_ldarg (mb
, argnum
);
3282 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3284 mono_mb_emit_ldarg (mb
, argnum
);
3285 mono_mb_emit_ldloc (mb
, conv_arg
);
3287 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3288 mono_mb_emit_byte (mb
, ldc_op
);
3289 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
3291 mono_mb_patch_branch (mb
, label_false
);
3292 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3293 mono_mb_patch_branch (mb
, label_end
);
3295 mono_mb_emit_byte (mb
, stop
);
3296 mono_mb_patch_branch (mb
, label_null
);
3301 g_assert_not_reached ();
3307 emit_marshal_ptr_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3308 MonoMarshalSpec
*spec
, int conv_arg
,
3309 MonoType
**conv_arg_type
, MarshalAction action
)
3311 MonoMethodBuilder
*mb
= m
->mb
;
3314 case MARSHAL_ACTION_CONV_IN
:
3315 /* MS seems to allow this in some cases, ie. bxc #158 */
3317 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) {
3318 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
3319 mono_mb_emit_exception_marshal_directive (m->mb, msg);
3324 case MARSHAL_ACTION_PUSH
:
3325 mono_mb_emit_ldarg (mb
, argnum
);
3328 case MARSHAL_ACTION_CONV_RESULT
:
3329 /* no conversions necessary */
3330 mono_mb_emit_stloc (mb
, 3);
3340 emit_marshal_char_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3341 MonoMarshalSpec
*spec
, int conv_arg
,
3342 MonoType
**conv_arg_type
, MarshalAction action
)
3344 MonoMethodBuilder
*mb
= m
->mb
;
3347 case MARSHAL_ACTION_PUSH
:
3348 /* fixme: dont know how to marshal that. We cant simply
3349 * convert it to a one byte UTF8 character, because an
3350 * unicode character may need more that one byte in UTF8 */
3351 mono_mb_emit_ldarg (mb
, argnum
);
3354 case MARSHAL_ACTION_CONV_RESULT
:
3355 /* fixme: we need conversions here */
3356 mono_mb_emit_stloc (mb
, 3);
3366 emit_marshal_scalar_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3367 MonoMarshalSpec
*spec
, int conv_arg
,
3368 MonoType
**conv_arg_type
, MarshalAction action
)
3370 MonoMethodBuilder
*mb
= m
->mb
;
3373 case MARSHAL_ACTION_PUSH
:
3374 mono_mb_emit_ldarg (mb
, argnum
);
3377 case MARSHAL_ACTION_CONV_RESULT
:
3378 /* no conversions necessary */
3379 mono_mb_emit_stloc (mb
, 3);
3389 emit_virtual_stelemref_ilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
3391 guint32 b1
, b2
, b3
, b4
;
3392 int aklass
, vklass
, vtable
, uiid
;
3393 int array_slot_addr
;
3395 mono_mb_set_param_names (mb
, param_names
);
3396 MonoType
*int_type
= mono_get_int_type ();
3397 MonoType
*int32_type
= m_class_get_byval_arg (mono_defaults
.int32_class
);
3398 MonoType
*object_type_byref
= m_class_get_this_arg (mono_defaults
.object_class
);
3400 /*For now simply call plain old stelemref*/
3402 case STELEMREF_OBJECT
:
3403 /* ldelema (implicit bound check) */
3404 load_array_element_address (mb
);
3406 mono_mb_emit_ldarg (mb
, 2);
3407 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3408 mono_mb_emit_byte (mb
, CEE_RET
);
3411 case STELEMREF_COMPLEX
: {
3414 <ldelema (bound check)>
3417 if (!mono_object_isinst (value, aklass))
3421 *array_slot_addr = value;
3424 throw new ArrayTypeMismatchException ();
3427 aklass
= mono_mb_add_local (mb
, int_type
);
3428 vklass
= mono_mb_add_local (mb
, int_type
);
3429 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3433 /*Use this to debug/record stores that are going thru the slow path*/
3434 MonoMethodSignature
*csig
;
3435 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3436 csig
->ret
= mono_get_void_type ();
3437 csig
->params
[0] = object_type
;
3438 csig
->params
[1] = int_type
; /* this is a natural sized int */
3439 csig
->params
[2] = object_type
;
3440 mono_mb_emit_ldarg (mb
, 0);
3441 mono_mb_emit_ldarg (mb
, 1);
3442 mono_mb_emit_ldarg (mb
, 2);
3443 mono_mb_emit_native_call (mb
, csig
, record_slot_vstore
);
3447 /* ldelema (implicit bound check) */
3448 load_array_element_address (mb
);
3449 mono_mb_emit_stloc (mb
, array_slot_addr
);
3451 /* if (!value) goto do_store */
3452 mono_mb_emit_ldarg (mb
, 2);
3453 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3455 /* aklass = array->vtable->klass->element_class */
3456 load_array_class (mb
, aklass
);
3457 /* vklass = value->vtable->klass */
3458 load_value_class (mb
, vklass
);
3461 mono_mb_emit_ldloc (mb
, vklass
);
3462 mono_mb_emit_ldloc (mb
, aklass
);
3463 b_fast
= mono_mb_emit_branch (mb
, CEE_BEQ
);
3465 /*if (mono_object_isinst (value, aklass)) */
3466 mono_mb_emit_ldarg (mb
, 2);
3467 mono_mb_emit_ldloc (mb
, aklass
);
3468 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
3469 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3472 mono_mb_patch_branch (mb
, b1
);
3473 mono_mb_patch_branch (mb
, b_fast
);
3474 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3475 mono_mb_emit_ldarg (mb
, 2);
3476 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3477 mono_mb_emit_byte (mb
, CEE_RET
);
3480 mono_mb_patch_branch (mb
, b2
);
3482 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3485 case STELEMREF_SEALED_CLASS
:
3487 <ldelema (bound check)>
3491 aklass = array->vtable->m_class_get_element_class (klass);
3492 vklass = value->vtable->klass;
3494 if (vklass != aklass)
3498 *array_slot_addr = value;
3501 throw new ArrayTypeMismatchException ();
3503 aklass
= mono_mb_add_local (mb
, int_type
);
3504 vklass
= mono_mb_add_local (mb
, int_type
);
3505 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3507 /* ldelema (implicit bound check) */
3508 load_array_element_address (mb
);
3509 mono_mb_emit_stloc (mb
, array_slot_addr
);
3511 /* if (!value) goto do_store */
3512 mono_mb_emit_ldarg (mb
, 2);
3513 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3515 /* aklass = array->vtable->klass->element_class */
3516 load_array_class (mb
, aklass
);
3518 /* vklass = value->vtable->klass */
3519 load_value_class (mb
, vklass
);
3521 /*if (vklass != aklass) goto do_exception; */
3522 mono_mb_emit_ldloc (mb
, aklass
);
3523 mono_mb_emit_ldloc (mb
, vklass
);
3524 b2
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3527 mono_mb_patch_branch (mb
, b1
);
3528 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3529 mono_mb_emit_ldarg (mb
, 2);
3530 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3531 mono_mb_emit_byte (mb
, CEE_RET
);
3534 mono_mb_patch_branch (mb
, b2
);
3535 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3538 case STELEMREF_CLASS
: {
3541 <ldelema (bound check)>
3545 aklass = array->vtable->m_class_get_element_class (klass);
3546 vklass = value->vtable->klass;
3548 if (vklass->idepth < aklass->idepth)
3551 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3555 *array_slot_addr = value;
3559 throw new ArrayTypeMismatchException ();
3561 aklass
= mono_mb_add_local (mb
, int_type
);
3562 vklass
= mono_mb_add_local (mb
, int_type
);
3563 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3565 /* ldelema (implicit bound check) */
3566 load_array_element_address (mb
);
3567 mono_mb_emit_stloc (mb
, array_slot_addr
);
3569 /* if (!value) goto do_store */
3570 mono_mb_emit_ldarg (mb
, 2);
3571 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3573 /* aklass = array->vtable->klass->element_class */
3574 load_array_class (mb
, aklass
);
3576 /* vklass = value->vtable->klass */
3577 load_value_class (mb
, vklass
);
3579 /* if (vklass->idepth < aklass->idepth) goto failue */
3580 mono_mb_emit_ldloc (mb
, vklass
);
3581 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3582 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3584 mono_mb_emit_ldloc (mb
, aklass
);
3585 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3586 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3588 b3
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
3590 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3591 mono_mb_emit_ldloc (mb
, vklass
);
3592 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3593 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3595 mono_mb_emit_ldloc (mb
, aklass
);
3596 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3597 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3598 mono_mb_emit_icon (mb
, 1);
3599 mono_mb_emit_byte (mb
, CEE_SUB
);
3600 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3601 mono_mb_emit_byte (mb
, CEE_MUL
);
3602 mono_mb_emit_byte (mb
, CEE_ADD
);
3603 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3605 mono_mb_emit_ldloc (mb
, aklass
);
3606 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3609 mono_mb_patch_branch (mb
, b1
);
3610 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3611 mono_mb_emit_ldarg (mb
, 2);
3612 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3613 mono_mb_emit_byte (mb
, CEE_RET
);
3616 mono_mb_patch_branch (mb
, b3
);
3617 mono_mb_patch_branch (mb
, b4
);
3619 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3623 case STELEMREF_CLASS_SMALL_IDEPTH
:
3626 <ldelema (bound check)>
3630 aklass = array->vtable->m_class_get_element_class (klass);
3631 vklass = value->vtable->klass;
3633 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3637 *array_slot_addr = value;
3641 throw new ArrayTypeMismatchException ();
3643 aklass
= mono_mb_add_local (mb
, int_type
);
3644 vklass
= mono_mb_add_local (mb
, int_type
);
3645 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3647 /* ldelema (implicit bound check) */
3648 load_array_element_address (mb
);
3649 mono_mb_emit_stloc (mb
, array_slot_addr
);
3651 /* if (!value) goto do_store */
3652 mono_mb_emit_ldarg (mb
, 2);
3653 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3655 /* aklass = array->vtable->klass->element_class */
3656 load_array_class (mb
, aklass
);
3658 /* vklass = value->vtable->klass */
3659 load_value_class (mb
, vklass
);
3661 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3662 mono_mb_emit_ldloc (mb
, vklass
);
3663 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3664 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3666 mono_mb_emit_ldloc (mb
, aklass
);
3667 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3668 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3669 mono_mb_emit_icon (mb
, 1);
3670 mono_mb_emit_byte (mb
, CEE_SUB
);
3671 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3672 mono_mb_emit_byte (mb
, CEE_MUL
);
3673 mono_mb_emit_byte (mb
, CEE_ADD
);
3674 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3676 mono_mb_emit_ldloc (mb
, aklass
);
3677 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3680 mono_mb_patch_branch (mb
, b1
);
3681 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3682 mono_mb_emit_ldarg (mb
, 2);
3683 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3684 mono_mb_emit_byte (mb
, CEE_RET
);
3687 mono_mb_patch_branch (mb
, b4
);
3689 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3692 case STELEMREF_INTERFACE
:
3699 klass = array->obj.vtable->klass->element_class;
3701 uiid = klass->interface_id;
3702 if (uiid > vt->max_interface_id)
3704 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
3707 mono_array_setref_internal (array, index, value);
3710 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
3712 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3713 aklass
= mono_mb_add_local (mb
, int_type
);
3714 vtable
= mono_mb_add_local (mb
, int_type
);
3715 uiid
= mono_mb_add_local (mb
, int32_type
);
3717 /* ldelema (implicit bound check) */
3718 load_array_element_address (mb
);
3719 mono_mb_emit_stloc (mb
, array_slot_addr
);
3721 /* if (!value) goto do_store */
3722 mono_mb_emit_ldarg (mb
, 2);
3723 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3725 /* klass = array->vtable->m_class_get_element_class (klass) */
3726 load_array_class (mb
, aklass
);
3728 /* vt = value->vtable */
3729 mono_mb_emit_ldarg (mb
, 2);
3730 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3731 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3732 mono_mb_emit_stloc (mb
, vtable
);
3734 /* uiid = klass->interface_id; */
3735 mono_mb_emit_ldloc (mb
, aklass
);
3736 mono_mb_emit_ldflda (mb
, m_class_offsetof_interface_id ());
3737 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
3738 mono_mb_emit_stloc (mb
, uiid
);
3740 /*if (uiid > vt->max_interface_id)*/
3741 mono_mb_emit_ldloc (mb
, uiid
);
3742 mono_mb_emit_ldloc (mb
, vtable
);
3743 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
3744 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
3745 b2
= mono_mb_emit_branch (mb
, CEE_BGT_UN
);
3747 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
3749 /*vt->interface_bitmap*/
3750 mono_mb_emit_ldloc (mb
, vtable
);
3751 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, interface_bitmap
));
3752 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3755 mono_mb_emit_ldloc (mb
, uiid
);
3756 mono_mb_emit_icon (mb
, 3);
3757 mono_mb_emit_byte (mb
, CEE_SHR_UN
);
3759 /*vt->interface_bitmap [(uiid) >> 3]*/
3760 mono_mb_emit_byte (mb
, CEE_ADD
); /*interface_bitmap is a guint8 array*/
3761 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
3763 /*(1 << ((uiid)&7)))*/
3764 mono_mb_emit_icon (mb
, 1);
3765 mono_mb_emit_ldloc (mb
, uiid
);
3766 mono_mb_emit_icon (mb
, 7);
3767 mono_mb_emit_byte (mb
, CEE_AND
);
3768 mono_mb_emit_byte (mb
, CEE_SHL
);
3770 /*bitwise and the whole thing*/
3771 mono_mb_emit_byte (mb
, CEE_AND
);
3772 b3
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3775 mono_mb_patch_branch (mb
, b1
);
3776 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3777 mono_mb_emit_ldarg (mb
, 2);
3778 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3779 mono_mb_emit_byte (mb
, CEE_RET
);
3782 mono_mb_patch_branch (mb
, b2
);
3783 mono_mb_patch_branch (mb
, b3
);
3784 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3788 mono_mb_emit_ldarg (mb
, 0);
3789 mono_mb_emit_ldarg (mb
, 1);
3790 mono_mb_emit_ldarg (mb
, 2);
3791 mono_mb_emit_managed_call (mb
, mono_marshal_get_stelemref (), NULL
);
3792 mono_mb_emit_byte (mb
, CEE_RET
);
3798 emit_stelemref_ilgen (MonoMethodBuilder
*mb
)
3800 guint32 b1
, b2
, b3
, b4
;
3803 int array_slot_addr
;
3805 MonoType
*int_type
= mono_get_int_type ();
3806 MonoType
*object_type_byref
= m_class_get_this_arg (mono_defaults
.object_class
);
3808 aklass
= mono_mb_add_local (mb
, int_type
);
3809 vklass
= mono_mb_add_local (mb
, int_type
);
3810 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3814 <ldelema (bound check)>
3818 aklass = array->vtable->m_class_get_element_class (klass);
3819 vklass = value->vtable->klass;
3821 if (vklass->idepth < aklass->idepth)
3824 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3828 *array_slot_addr = value;
3832 if (mono_object_isinst (value, aklass))
3835 throw new ArrayTypeMismatchException ();
3838 /* ldelema (implicit bound check) */
3839 mono_mb_emit_ldarg (mb
, 0);
3840 mono_mb_emit_ldarg (mb
, 1);
3841 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
3842 mono_mb_emit_stloc (mb
, array_slot_addr
);
3844 /* if (!value) goto do_store */
3845 mono_mb_emit_ldarg (mb
, 2);
3846 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3848 /* aklass = array->vtable->klass->element_class */
3849 mono_mb_emit_ldarg (mb
, 0);
3850 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3851 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3852 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3853 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3854 mono_mb_emit_ldflda (mb
, m_class_offsetof_element_class ());
3855 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3856 mono_mb_emit_stloc (mb
, aklass
);
3858 /* vklass = value->vtable->klass */
3859 mono_mb_emit_ldarg (mb
, 2);
3860 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3861 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3862 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3863 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3864 mono_mb_emit_stloc (mb
, vklass
);
3866 /* if (vklass->idepth < aklass->idepth) goto failue */
3867 mono_mb_emit_ldloc (mb
, vklass
);
3868 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3869 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3871 mono_mb_emit_ldloc (mb
, aklass
);
3872 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3873 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3875 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
3877 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3878 mono_mb_emit_ldloc (mb
, vklass
);
3879 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3880 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3882 mono_mb_emit_ldloc (mb
, aklass
);
3883 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3884 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3885 mono_mb_emit_icon (mb
, 1);
3886 mono_mb_emit_byte (mb
, CEE_SUB
);
3887 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3888 mono_mb_emit_byte (mb
, CEE_MUL
);
3889 mono_mb_emit_byte (mb
, CEE_ADD
);
3890 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3892 mono_mb_emit_ldloc (mb
, aklass
);
3894 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3896 copy_pos
= mono_mb_get_label (mb
);
3898 mono_mb_patch_branch (mb
, b1
);
3899 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3900 mono_mb_emit_ldarg (mb
, 2);
3901 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3903 mono_mb_emit_byte (mb
, CEE_RET
);
3906 mono_mb_patch_branch (mb
, b2
);
3907 mono_mb_patch_branch (mb
, b3
);
3909 mono_mb_emit_ldarg (mb
, 2);
3910 mono_mb_emit_ldloc (mb
, aklass
);
3911 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
3913 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3914 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
3915 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3917 mono_mb_emit_byte (mb
, CEE_RET
);
3921 mb_emit_byte_ilgen (MonoMethodBuilder
*mb
, guint8 op
)
3923 mono_mb_emit_byte (mb
, op
);
3927 emit_array_address_ilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
3929 int i
, bounds
, ind
, realidx
;
3930 int branch_pos
, *branch_positions
;
3932 MonoType
*int_type
= mono_get_int_type ();
3933 MonoType
*int32_type
= mono_get_int32_type ();
3935 branch_positions
= g_new0 (int, rank
);
3937 bounds
= mono_mb_add_local (mb
, int_type
);
3938 ind
= mono_mb_add_local (mb
, int32_type
);
3939 realidx
= mono_mb_add_local (mb
, int32_type
);
3941 /* bounds = array->bounds; */
3942 mono_mb_emit_ldarg (mb
, 0);
3943 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
3944 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3945 mono_mb_emit_stloc (mb
, bounds
);
3947 /* ind is the overall element index, realidx is the partial index in a single dimension */
3948 /* ind = idx0 - bounds [0].lower_bound */
3949 mono_mb_emit_ldarg (mb
, 1);
3950 mono_mb_emit_ldloc (mb
, bounds
);
3951 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
3952 mono_mb_emit_byte (mb
, CEE_ADD
);
3953 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3954 mono_mb_emit_byte (mb
, CEE_SUB
);
3955 mono_mb_emit_stloc (mb
, ind
);
3956 /* if (ind >= bounds [0].length) goto exeception; */
3957 mono_mb_emit_ldloc (mb
, ind
);
3958 mono_mb_emit_ldloc (mb
, bounds
);
3959 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3960 mono_mb_emit_byte (mb
, CEE_ADD
);
3961 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3962 /* note that we use unsigned comparison */
3963 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
3965 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
3966 * We could also decide to ignore the passed elem_size and get it
3967 * from the array object, to reduce the number of methods we generate:
3968 * the additional cost is 3 memory loads and a non-immediate mul.
3970 for (i
= 1; i
< rank
; ++i
) {
3971 /* realidx = idxi - bounds [i].lower_bound */
3972 mono_mb_emit_ldarg (mb
, 1 + i
);
3973 mono_mb_emit_ldloc (mb
, bounds
);
3974 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
3975 mono_mb_emit_byte (mb
, CEE_ADD
);
3976 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3977 mono_mb_emit_byte (mb
, CEE_SUB
);
3978 mono_mb_emit_stloc (mb
, realidx
);
3979 /* if (realidx >= bounds [i].length) goto exeception; */
3980 mono_mb_emit_ldloc (mb
, realidx
);
3981 mono_mb_emit_ldloc (mb
, bounds
);
3982 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3983 mono_mb_emit_byte (mb
, CEE_ADD
);
3984 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3985 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
3986 /* ind = ind * bounds [i].length + realidx */
3987 mono_mb_emit_ldloc (mb
, ind
);
3988 mono_mb_emit_ldloc (mb
, bounds
);
3989 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3990 mono_mb_emit_byte (mb
, CEE_ADD
);
3991 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3992 mono_mb_emit_byte (mb
, CEE_MUL
);
3993 mono_mb_emit_ldloc (mb
, realidx
);
3994 mono_mb_emit_byte (mb
, CEE_ADD
);
3995 mono_mb_emit_stloc (mb
, ind
);
3998 /* return array->vector + ind * element_size */
3999 mono_mb_emit_ldarg (mb
, 0);
4000 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
4001 mono_mb_emit_ldloc (mb
, ind
);
4003 mono_mb_emit_icon (mb
, elem_size
);
4005 /* Load arr->vtable->klass->sizes.element_class */
4006 mono_mb_emit_ldarg (mb
, 0);
4007 mono_mb_emit_byte (mb
, CEE_CONV_I
);
4008 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
4009 mono_mb_emit_byte (mb
, CEE_ADD
);
4010 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4011 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
4012 mono_mb_emit_byte (mb
, CEE_ADD
);
4013 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4014 /* sizes is an union, so this reads sizes.element_size */
4015 mono_mb_emit_icon (mb
, m_class_offsetof_sizes ());
4016 mono_mb_emit_byte (mb
, CEE_ADD
);
4017 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
4019 mono_mb_emit_byte (mb
, CEE_MUL
);
4020 mono_mb_emit_byte (mb
, CEE_ADD
);
4021 mono_mb_emit_byte (mb
, CEE_RET
);
4023 /* patch the branches to get here and throw */
4024 for (i
= 1; i
< rank
; ++i
) {
4025 mono_mb_patch_branch (mb
, branch_positions
[i
]);
4027 mono_mb_patch_branch (mb
, branch_pos
);
4028 /* throw exception */
4029 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
4031 g_free (branch_positions
);
4035 emit_delegate_begin_invoke_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
4038 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
4040 mono_mb_emit_ldarg (mb
, 0);
4041 mono_mb_emit_ldloc (mb
, params_var
);
4042 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
4043 mono_mb_emit_byte (mb
, CEE_RET
);
4047 emit_delegate_end_invoke_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
4050 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
4052 mono_mb_emit_ldarg (mb
, 0);
4053 mono_mb_emit_ldloc (mb
, params_var
);
4054 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
4056 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
4057 mono_mb_emit_byte (mb
, CEE_POP
);
4058 mono_mb_emit_byte (mb
, CEE_RET
);
4060 mono_mb_emit_restore_result (mb
, sig
->ret
);
4064 emit_delegate_invoke_internal_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodSignature
*invoke_sig
, gboolean static_method_with_first_arg_bound
, gboolean callvirt
, gboolean closed_over_null
, MonoMethod
*method
, MonoMethod
*target_method
, MonoClass
*target_class
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
)
4066 int local_i
, local_len
, local_delegates
, local_d
, local_target
, local_res
;
4067 int pos0
, pos1
, pos2
;
4071 MonoType
*int32_type
= mono_get_int32_type ();
4072 MonoType
*object_type
= mono_get_object_type ();
4074 void_ret
= sig
->ret
->type
== MONO_TYPE_VOID
&& !method
->string_ctor
;
4076 /* allocate local 0 (object) */
4077 local_i
= mono_mb_add_local (mb
, int32_type
);
4078 local_len
= mono_mb_add_local (mb
, int32_type
);
4079 local_delegates
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_defaults
.array_class
));
4080 local_d
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_defaults
.multicastdelegate_class
));
4081 local_target
= mono_mb_add_local (mb
, object_type
);
4084 local_res
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_from_mono_type_internal (sig
->ret
)));
4086 g_assert (sig
->hasthis
);
4089 * {type: sig->ret} res;
4090 * if (delegates == null) {
4091 * return this.<target> ( args .. );
4093 * int i = 0, len = this.delegates.Length;
4095 * res = this.delegates [i].Invoke ( args .. );
4096 * } while (++i < len);
4101 /* this wrapper can be used in unmanaged-managed transitions */
4102 emit_thread_interrupt_checkpoint (mb
);
4104 /* delegates = this.delegates */
4105 mono_mb_emit_ldarg (mb
, 0);
4106 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoMulticastDelegate
, delegates
));
4107 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4108 mono_mb_emit_stloc (mb
, local_delegates
);
4110 /* if (delegates == null) */
4111 mono_mb_emit_ldloc (mb
, local_delegates
);
4112 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
4114 /* return target.<target_method|method_ptr> ( args .. ); */
4116 /* target = d.target; */
4117 mono_mb_emit_ldarg (mb
, 0);
4118 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
4119 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4120 mono_mb_emit_stloc (mb
, local_target
);
4122 /*static methods with bound first arg can have null target and still be bound*/
4123 if (!static_method_with_first_arg_bound
) {
4124 /* if target != null */
4125 mono_mb_emit_ldloc (mb
, local_target
);
4126 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4128 /* then call this->method_ptr nonstatic */
4131 mono_mb_emit_exception_full (mb
, "System", "NotImplementedException", "");
4133 mono_mb_emit_ldloc (mb
, local_target
);
4134 for (i
= 0; i
< sig
->param_count
; ++i
)
4135 mono_mb_emit_ldarg (mb
, i
+ 1);
4136 mono_mb_emit_ldarg (mb
, 0);
4137 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
4138 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4139 mono_mb_emit_ldarg (mb
, 0);
4140 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4141 mono_mb_emit_byte (mb
, CEE_MONO_LD_DELEGATE_METHOD_PTR
);
4142 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4143 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, sig
);
4144 mono_mb_emit_byte (mb
, CEE_RET
);
4147 /* else [target == null] call this->method_ptr static */
4148 mono_mb_patch_branch (mb
, pos0
);
4152 if (!closed_over_null
) {
4153 /* if target_method is not really virtual, turn it into a direct call */
4154 if (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || m_class_is_valuetype (target_class
)) {
4155 mono_mb_emit_ldarg (mb
, 1);
4156 for (i
= 1; i
< sig
->param_count
; ++i
)
4157 mono_mb_emit_ldarg (mb
, i
+ 1);
4158 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
4160 mono_mb_emit_ldarg (mb
, 1);
4161 mono_mb_emit_op (mb
, CEE_CASTCLASS
, target_class
);
4162 for (i
= 1; i
< sig
->param_count
; ++i
)
4163 mono_mb_emit_ldarg (mb
, i
+ 1);
4164 mono_mb_emit_op (mb
, CEE_CALLVIRT
, target_method
);
4167 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4168 for (i
= 0; i
< sig
->param_count
; ++i
)
4169 mono_mb_emit_ldarg (mb
, i
+ 1);
4170 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
4173 if (static_method_with_first_arg_bound
) {
4174 mono_mb_emit_ldloc (mb
, local_target
);
4175 if (!MONO_TYPE_IS_REFERENCE (invoke_sig
->params
[0]))
4176 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type_internal (invoke_sig
->params
[0]));
4178 for (i
= 0; i
< sig
->param_count
; ++i
)
4179 mono_mb_emit_ldarg (mb
, i
+ 1);
4180 mono_mb_emit_ldarg (mb
, 0);
4181 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
4182 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4183 mono_mb_emit_ldarg (mb
, 0);
4184 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4185 mono_mb_emit_byte (mb
, CEE_MONO_LD_DELEGATE_METHOD_PTR
);
4186 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4187 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, invoke_sig
);
4190 mono_mb_emit_byte (mb
, CEE_RET
);
4192 /* else [delegates != null] */
4193 mono_mb_patch_branch (mb
, pos2
);
4195 /* len = delegates.Length; */
4196 mono_mb_emit_ldloc (mb
, local_delegates
);
4197 mono_mb_emit_byte (mb
, CEE_LDLEN
);
4198 mono_mb_emit_byte (mb
, CEE_CONV_I4
);
4199 mono_mb_emit_stloc (mb
, local_len
);
4202 mono_mb_emit_icon (mb
, 0);
4203 mono_mb_emit_stloc (mb
, local_i
);
4205 pos1
= mono_mb_get_label (mb
);
4207 /* d = delegates [i]; */
4208 mono_mb_emit_ldloc (mb
, local_delegates
);
4209 mono_mb_emit_ldloc (mb
, local_i
);
4210 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4211 mono_mb_emit_stloc (mb
, local_d
);
4213 /* res = d.Invoke ( args .. ); */
4214 mono_mb_emit_ldloc (mb
, local_d
);
4215 for (i
= 0; i
< sig
->param_count
; i
++)
4216 mono_mb_emit_ldarg (mb
, i
+ 1);
4218 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4221 mono_mb_emit_op (mb
, CEE_CALLVIRT
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
));
4222 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4225 mono_mb_emit_stloc (mb
, local_res
);
4228 mono_mb_emit_add_to_local (mb
, local_i
, 1);
4231 mono_mb_emit_ldloc (mb
, local_i
);
4232 mono_mb_emit_ldloc (mb
, local_len
);
4233 mono_mb_emit_branch_label (mb
, CEE_BLT
, pos1
);
4237 mono_mb_emit_ldloc (mb
, local_res
);
4238 mono_mb_emit_byte (mb
, CEE_RET
);
4242 mb_skip_visibility_ilgen (MonoMethodBuilder
*mb
)
4244 mb
->skip_visibility
= 1;
4248 mb_set_dynamic_ilgen (MonoMethodBuilder
*mb
)
4254 emit_synchronized_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4256 int i
, pos
, pos2
, this_local
, taken_local
, ret_local
= 0;
4257 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4258 MonoExceptionClause
*clause
;
4261 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4262 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
4264 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4265 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4266 mono_class_set_type_load_failure (method
->klass
, "");
4267 /* This will throw the type load exception when the wrapper is compiled */
4268 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4269 mono_mb_emit_op (mb
, CEE_ISINST
, method
->klass
);
4270 mono_mb_emit_byte (mb
, CEE_POP
);
4272 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4273 mono_mb_emit_ldloc (mb
, ret_local
);
4274 mono_mb_emit_byte (mb
, CEE_RET
);
4279 MonoType
*object_type
= mono_get_object_type ();
4280 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
4282 this_local
= mono_mb_add_local (mb
, object_type
);
4283 taken_local
= mono_mb_add_local (mb
, boolean_type
);
4285 clause
= (MonoExceptionClause
*)mono_image_alloc0 (get_method_image (method
), sizeof (MonoExceptionClause
));
4286 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
4288 /* Push this or the type object */
4289 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
4290 /* We have special handling for this in the JIT */
4291 int index
= mono_mb_add_data (mb
, method
->klass
);
4292 mono_mb_add_data (mb
, mono_defaults
.typehandle_class
);
4293 mono_mb_emit_byte (mb
, CEE_LDTOKEN
);
4294 mono_mb_emit_i4 (mb
, index
);
4296 mono_mb_emit_managed_call (mb
, gettypefromhandle_method
, NULL
);
4299 mono_mb_emit_ldarg (mb
, 0);
4300 mono_mb_emit_stloc (mb
, this_local
);
4302 clause
->try_offset
= mono_mb_get_label (mb
);
4303 /* Call Monitor::Enter() */
4304 mono_mb_emit_ldloc (mb
, this_local
);
4305 mono_mb_emit_ldloc_addr (mb
, taken_local
);
4306 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
4308 /* Call the method */
4310 mono_mb_emit_ldarg (mb
, 0);
4311 for (i
= 0; i
< sig
->param_count
; i
++)
4312 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
4316 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
), NULL
);
4317 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4319 mono_mb_emit_managed_call (mb
, method
, NULL
);
4322 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4323 mono_mb_emit_stloc (mb
, ret_local
);
4325 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4327 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
4328 clause
->handler_offset
= mono_mb_get_label (mb
);
4330 /* Call Monitor::Exit() if needed */
4331 mono_mb_emit_ldloc (mb
, taken_local
);
4332 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4333 mono_mb_emit_ldloc (mb
, this_local
);
4334 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
4335 mono_mb_patch_branch (mb
, pos2
);
4336 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
4338 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4340 mono_mb_patch_branch (mb
, pos
);
4341 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4342 mono_mb_emit_ldloc (mb
, ret_local
);
4343 mono_mb_emit_byte (mb
, CEE_RET
);
4345 mono_mb_set_clauses (mb
, 1, clause
);
4349 emit_unbox_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4351 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4353 mono_mb_emit_ldarg (mb
, 0);
4354 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
4355 mono_mb_emit_byte (mb
, CEE_ADD
);
4356 for (int i
= 0; i
< sig
->param_count
; ++i
)
4357 mono_mb_emit_ldarg (mb
, i
+ 1);
4358 mono_mb_emit_managed_call (mb
, method
, NULL
);
4359 mono_mb_emit_byte (mb
, CEE_RET
);
4363 emit_array_accessor_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4365 MonoGenericContainer
*container
= NULL
;
4366 /* Call the method */
4368 mono_mb_emit_ldarg (mb
, 0);
4369 for (int i
= 0; i
< sig
->param_count
; i
++)
4370 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
4374 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
), NULL
);
4375 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4377 mono_mb_emit_managed_call (mb
, method
, NULL
);
4379 mono_mb_emit_byte (mb
, CEE_RET
);
4383 emit_generic_array_helper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
4385 mono_mb_emit_ldarg (mb
, 0);
4386 for (int i
= 0; i
< csig
->param_count
; i
++)
4387 mono_mb_emit_ldarg (mb
, i
+ 1);
4388 mono_mb_emit_managed_call (mb
, method
, NULL
);
4389 mono_mb_emit_byte (mb
, CEE_RET
);
4393 emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
4395 MonoImage
*image
= get_method_image (method
);
4396 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4397 int param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
4398 int pos_leave
, coop_gc_var
= 0;
4399 MonoExceptionClause
*clause
;
4400 MonoType
*object_type
= mono_get_object_type ();
4401 #if defined (TARGET_WASM)
4402 const gboolean do_blocking_transition
= FALSE
;
4404 const gboolean do_blocking_transition
= TRUE
;
4407 /* local 0 (temp for exception object) */
4408 mono_mb_add_local (mb
, object_type
);
4410 /* local 1 (temp for result) */
4411 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4412 mono_mb_add_local (mb
, sig
->ret
);
4414 if (do_blocking_transition
) {
4415 /* local 4, the local to be used when calling the suspend funcs */
4416 coop_gc_var
= mono_mb_add_local (mb
, mono_get_int_type ());
4419 /* clear exception arg */
4420 mono_mb_emit_ldarg (mb
, param_count
- 1);
4421 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4422 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4424 if (do_blocking_transition
) {
4425 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4426 mono_mb_emit_byte (mb
, CEE_MONO_GET_SP
);
4427 mono_mb_emit_icall (mb
, mono_threads_enter_gc_unsafe_region_unbalanced
);
4428 mono_mb_emit_stloc (mb
, coop_gc_var
);
4432 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
4433 clause
->try_offset
= mono_mb_get_label (mb
);
4435 /* push method's args */
4436 for (int i
= 0; i
< param_count
- 1; i
++) {
4440 mono_mb_emit_ldarg (mb
, i
);
4442 /* get the byval type of the param */
4443 klass
= mono_class_from_mono_type_internal (csig
->params
[i
]);
4444 type
= m_class_get_byval_arg (klass
);
4446 /* unbox struct args */
4447 if (MONO_TYPE_ISSTRUCT (type
)) {
4448 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
4450 /* byref args & and the "this" arg must remain a ptr.
4451 Otherwise make a copy of the value type */
4452 if (!(csig
->params
[i
]->byref
|| (i
== 0 && sig
->hasthis
)))
4453 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
4455 csig
->params
[i
] = object_type
;
4460 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
4461 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4463 mono_mb_emit_op (mb
, CEE_CALL
, method
);
4465 /* save result at local 1 */
4466 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4467 mono_mb_emit_stloc (mb
, 1);
4469 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4472 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4473 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
4474 clause
->data
.catch_class
= mono_defaults
.object_class
;
4476 clause
->handler_offset
= mono_mb_get_label (mb
);
4478 /* store exception at local 0 */
4479 mono_mb_emit_stloc (mb
, 0);
4480 mono_mb_emit_ldarg (mb
, param_count
- 1);
4481 mono_mb_emit_ldloc (mb
, 0);
4482 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4483 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4485 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4487 mono_mb_set_clauses (mb
, 1, clause
);
4489 mono_mb_patch_branch (mb
, pos_leave
);
4492 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
4493 mono_mb_emit_ldloc (mb
, 1);
4495 /* box the return value */
4496 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
4497 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (sig
->ret
));
4500 if (do_blocking_transition
) {
4501 mono_mb_emit_ldloc (mb
, coop_gc_var
);
4502 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4503 mono_mb_emit_byte (mb
, CEE_MONO_GET_SP
);
4504 mono_mb_emit_icall (mb
, mono_threads_exit_gc_unsafe_region_unbalanced
);
4507 mono_mb_emit_byte (mb
, CEE_RET
);
4511 emit_marshal_custom_get_instance (MonoMethodBuilder
*mb
, MonoClass
*klass
, MonoMarshalSpec
*spec
)
4513 MONO_STATIC_POINTER_INIT (MonoMethod
, get_instance
)
4515 MonoClass
*Marshal
= mono_class_try_get_marshal_class ();
4517 get_instance
= get_method_nofail (Marshal
, "GetCustomMarshalerInstance", 2, 0);
4518 g_assert (get_instance
);
4520 MONO_STATIC_POINTER_INIT_END (MonoClass
, get_instance
)
4522 // HACK: We cannot use ldtoken in this type of wrapper.
4523 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4524 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
4525 mono_mb_emit_icall (mb
, mono_marshal_get_type_object
);
4526 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4528 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4532 emit_marshal_custom_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4533 MonoMarshalSpec
*spec
,
4534 int conv_arg
, MonoType
**conv_arg_type
,
4535 MarshalAction action
)
4540 static MonoClass
*ICustomMarshaler
= NULL
;
4541 static MonoMethod
*cleanup_native
, *cleanup_managed
;
4542 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
4543 MonoMethodBuilder
*mb
= m
->mb
;
4544 MonoAssemblyLoadContext
*alc
= mono_domain_ambient_alc (mono_domain_get ());
4548 MonoType
*int_type
= mono_get_int_type ();
4549 MonoType
*object_type
= mono_get_object_type ();
4551 if (!ICustomMarshaler
) {
4552 MonoClass
*klass
= mono_class_try_get_icustom_marshaler_class ();
4554 char *exception_msg
= g_strdup ("Current profile doesn't support ICustomMarshaler");
4555 /* Throw exception and emit compensation code if neccesary */
4557 case MARSHAL_ACTION_CONV_IN
:
4558 case MARSHAL_ACTION_CONV_RESULT
:
4559 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4560 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
4561 mono_mb_emit_byte (mb
, CEE_POP
);
4563 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
4566 case MARSHAL_ACTION_PUSH
:
4567 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4575 cleanup_native
= get_method_nofail (klass
, "CleanUpNativeData", 1, 0);
4576 g_assert (cleanup_native
);
4578 cleanup_managed
= get_method_nofail (klass
, "CleanUpManagedData", 1, 0);
4579 g_assert (cleanup_managed
);
4581 marshal_managed_to_native
= get_method_nofail (klass
, "MarshalManagedToNative", 1, 0);
4582 g_assert (marshal_managed_to_native
);
4584 marshal_native_to_managed
= get_method_nofail (klass
, "MarshalNativeToManaged", 1, 0);
4585 g_assert (marshal_native_to_managed
);
4587 mono_memory_barrier ();
4588 ICustomMarshaler
= klass
;
4591 if (spec
->data
.custom_data
.image
)
4592 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, alc
, spec
->data
.custom_data
.image
, error
);
4594 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, alc
, m
->image
, error
);
4596 g_assert (mtype
!= NULL
);
4597 mono_error_assert_ok (error
);
4598 mklass
= mono_class_from_mono_type_internal (mtype
);
4599 g_assert (mklass
!= NULL
);
4602 case MARSHAL_ACTION_CONV_IN
:
4604 case MONO_TYPE_CLASS
:
4605 case MONO_TYPE_OBJECT
:
4606 case MONO_TYPE_STRING
:
4607 case MONO_TYPE_ARRAY
:
4608 case MONO_TYPE_SZARRAY
:
4609 case MONO_TYPE_VALUETYPE
:
4613 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
4614 g_assert_not_reached ();
4618 conv_arg
= mono_mb_add_local (mb
, int_type
);
4620 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4621 mono_mb_emit_stloc (mb
, conv_arg
);
4623 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4626 /* Minic MS.NET behavior */
4627 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
4630 /* Check for null */
4631 mono_mb_emit_ldarg (mb
, argnum
);
4633 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4634 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4636 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4638 mono_mb_emit_ldarg (mb
, argnum
);
4640 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4642 if (t
->type
== MONO_TYPE_VALUETYPE
) {
4644 * Since we can't determine the type of the argument, we
4645 * will assume the unmanaged function takes a pointer.
4647 *conv_arg_type
= int_type
;
4649 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (t
));
4652 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4653 mono_mb_emit_stloc (mb
, conv_arg
);
4655 mono_mb_patch_branch (mb
, pos2
);
4658 case MARSHAL_ACTION_CONV_OUT
:
4659 /* Check for null */
4660 mono_mb_emit_ldloc (mb
, conv_arg
);
4661 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4664 mono_mb_emit_ldarg (mb
, argnum
);
4666 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4668 mono_mb_emit_ldloc (mb
, conv_arg
);
4669 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4670 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4671 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
4672 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4674 mono_mb_emit_ldloc (mb
, conv_arg
);
4675 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4677 /* We have nowhere to store the result */
4678 mono_mb_emit_byte (mb
, CEE_POP
);
4681 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4683 mono_mb_emit_ldloc (mb
, conv_arg
);
4685 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4687 mono_mb_patch_branch (mb
, pos2
);
4690 case MARSHAL_ACTION_PUSH
:
4692 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4694 mono_mb_emit_ldloc (mb
, conv_arg
);
4697 case MARSHAL_ACTION_CONV_RESULT
:
4698 loc1
= mono_mb_add_local (mb
, int_type
);
4700 mono_mb_emit_stloc (mb
, 3);
4702 mono_mb_emit_ldloc (mb
, 3);
4703 mono_mb_emit_stloc (mb
, loc1
);
4705 /* Check for null */
4706 mono_mb_emit_ldloc (mb
, 3);
4707 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4709 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4710 mono_mb_emit_byte (mb
, CEE_DUP
);
4712 mono_mb_emit_ldloc (mb
, 3);
4713 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4714 mono_mb_emit_stloc (mb
, 3);
4716 mono_mb_emit_ldloc (mb
, loc1
);
4717 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4719 mono_mb_patch_branch (mb
, pos2
);
4722 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4723 conv_arg
= mono_mb_add_local (mb
, object_type
);
4725 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4726 mono_mb_emit_stloc (mb
, conv_arg
);
4728 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4731 /* Check for null */
4732 mono_mb_emit_ldarg (mb
, argnum
);
4734 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4735 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4737 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4739 mono_mb_emit_ldarg (mb
, argnum
);
4741 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4743 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4744 mono_mb_emit_stloc (mb
, conv_arg
);
4746 mono_mb_patch_branch (mb
, pos2
);
4749 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4750 g_assert (!t
->byref
);
4752 loc1
= mono_mb_add_local (mb
, object_type
);
4754 mono_mb_emit_stloc (mb
, 3);
4756 mono_mb_emit_ldloc (mb
, 3);
4757 mono_mb_emit_stloc (mb
, loc1
);
4759 /* Check for null */
4760 mono_mb_emit_ldloc (mb
, 3);
4761 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4763 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4764 mono_mb_emit_byte (mb
, CEE_DUP
);
4766 mono_mb_emit_ldloc (mb
, 3);
4767 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4768 mono_mb_emit_stloc (mb
, 3);
4770 mono_mb_emit_ldloc (mb
, loc1
);
4771 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4773 mono_mb_patch_branch (mb
, pos2
);
4776 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4778 /* Check for null */
4779 mono_mb_emit_ldloc (mb
, conv_arg
);
4780 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4783 mono_mb_emit_ldarg (mb
, argnum
);
4785 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4787 mono_mb_emit_ldloc (mb
, conv_arg
);
4788 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4789 mono_mb_emit_byte (mb
, CEE_STIND_I
);
4792 /* Call CleanUpManagedData */
4793 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4795 mono_mb_emit_ldloc (mb
, conv_arg
);
4796 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4798 mono_mb_patch_branch (mb
, pos2
);
4802 g_assert_not_reached ();
4808 emit_marshal_asany_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4809 MonoMarshalSpec
*spec
,
4810 int conv_arg
, MonoType
**conv_arg_type
,
4811 MarshalAction action
)
4813 MonoMethodBuilder
*mb
= m
->mb
;
4815 MonoType
*int_type
= mono_get_int_type ();
4817 case MARSHAL_ACTION_CONV_IN
: {
4818 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4820 g_assert (t
->type
== MONO_TYPE_OBJECT
);
4821 g_assert (!t
->byref
);
4823 conv_arg
= mono_mb_add_local (mb
, int_type
);
4824 mono_mb_emit_ldarg (mb
, argnum
);
4825 mono_mb_emit_icon (mb
, encoding
);
4826 mono_mb_emit_icon (mb
, t
->attrs
);
4827 mono_mb_emit_icall (mb
, mono_marshal_asany
);
4828 mono_mb_emit_stloc (mb
, conv_arg
);
4832 case MARSHAL_ACTION_PUSH
:
4833 mono_mb_emit_ldloc (mb
, conv_arg
);
4836 case MARSHAL_ACTION_CONV_OUT
: {
4837 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4839 mono_mb_emit_ldarg (mb
, argnum
);
4840 mono_mb_emit_ldloc (mb
, conv_arg
);
4841 mono_mb_emit_icon (mb
, encoding
);
4842 mono_mb_emit_icon (mb
, t
->attrs
);
4843 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
4848 g_assert_not_reached ();
4854 emit_marshal_vtype_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4855 MonoMarshalSpec
*spec
,
4856 int conv_arg
, MonoType
**conv_arg_type
,
4857 MarshalAction action
)
4859 MonoMethodBuilder
*mb
= m
->mb
;
4860 MonoClass
*klass
, *date_time_class
;
4863 klass
= mono_class_from_mono_type_internal (t
);
4865 date_time_class
= mono_class_get_date_time_class ();
4867 MonoType
*int_type
= mono_get_int_type ();
4868 MonoType
*double_type
= m_class_get_byval_arg (mono_defaults
.double_class
);
4871 case MARSHAL_ACTION_CONV_IN
:
4872 if (klass
== date_time_class
) {
4873 /* Convert it to an OLE DATE type */
4875 conv_arg
= mono_mb_add_local (mb
, double_type
);
4878 mono_mb_emit_ldarg (mb
, argnum
);
4879 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4882 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4884 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = double_type
;
4886 MONO_STATIC_POINTER_INIT (MonoMethod
, to_oadate
)
4887 to_oadate
= get_method_nofail (date_time_class
, "ToOADate", 0, 0);
4888 g_assert (to_oadate
);
4889 MONO_STATIC_POINTER_INIT_END (MonoMethod
, to_oadate
)
4891 mono_mb_emit_ldarg_addr (mb
, argnum
);
4892 mono_mb_emit_managed_call (mb
, to_oadate
, NULL
);
4893 mono_mb_emit_stloc (mb
, conv_arg
);
4897 mono_mb_patch_branch (mb
, pos
);
4901 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4904 conv_arg
= mono_mb_add_local (mb
, int_type
);
4906 /* store the address of the source into local variable 0 */
4908 mono_mb_emit_ldarg (mb
, argnum
);
4910 mono_mb_emit_ldarg_addr (mb
, argnum
);
4912 mono_mb_emit_stloc (mb
, 0);
4914 /* allocate space for the native struct and
4915 * store the address into local variable 1 (dest) */
4916 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
4917 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4918 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
4919 mono_mb_emit_stloc (mb
, conv_arg
);
4922 mono_mb_emit_ldloc (mb
, 0);
4923 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4926 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4928 mono_mb_emit_ldloc (mb
, conv_arg
);
4929 mono_mb_emit_stloc (mb
, 1);
4931 /* emit valuetype conversion code */
4932 emit_struct_conv (mb
, klass
, FALSE
);
4936 mono_mb_patch_branch (mb
, pos
);
4939 case MARSHAL_ACTION_PUSH
:
4940 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
4942 g_assert (!t
->byref
);
4944 /* Have to change the signature since the vtype is passed byref */
4945 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = int_type
;
4947 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4948 mono_mb_emit_ldarg_addr (mb
, argnum
);
4950 mono_mb_emit_ldloc (mb
, conv_arg
);
4954 if (klass
== date_time_class
) {
4956 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4958 mono_mb_emit_ldloc (mb
, conv_arg
);
4962 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4963 mono_mb_emit_ldarg (mb
, argnum
);
4966 mono_mb_emit_ldloc (mb
, conv_arg
);
4968 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4969 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
4973 case MARSHAL_ACTION_CONV_OUT
:
4974 if (klass
== date_time_class
) {
4975 /* Convert from an OLE DATE type */
4980 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4982 MONO_STATIC_POINTER_INIT (MonoMethod
, from_oadate
)
4983 from_oadate
= get_method_nofail (date_time_class
, "FromOADate", 1, 0);
4984 MONO_STATIC_POINTER_INIT_END (MonoMethod
, from_oadate
)
4986 g_assert (from_oadate
);
4988 mono_mb_emit_ldarg (mb
, argnum
);
4989 mono_mb_emit_ldloc (mb
, conv_arg
);
4990 mono_mb_emit_managed_call (mb
, from_oadate
, NULL
);
4991 mono_mb_emit_op (mb
, CEE_STOBJ
, date_time_class
);
4996 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
5000 /* dst = argument */
5001 mono_mb_emit_ldarg (mb
, argnum
);
5002 mono_mb_emit_stloc (mb
, 1);
5004 mono_mb_emit_ldloc (mb
, 1);
5005 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5007 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
5008 /* src = tmp_locals [i] */
5009 mono_mb_emit_ldloc (mb
, conv_arg
);
5010 mono_mb_emit_stloc (mb
, 0);
5012 /* emit valuetype conversion code */
5013 emit_struct_conv (mb
, klass
, TRUE
);
5017 emit_struct_free (mb
, klass
, conv_arg
);
5020 mono_mb_patch_branch (mb
, pos
);
5023 case MARSHAL_ACTION_CONV_RESULT
:
5024 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
)) {
5025 mono_mb_emit_stloc (mb
, 3);
5029 /* load pointer to returned value type */
5030 g_assert (m
->vtaddr_var
);
5031 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
5032 /* store the address of the source into local variable 0 */
5033 mono_mb_emit_stloc (mb
, 0);
5035 mono_mb_emit_ldloc_addr (mb
, 3);
5036 mono_mb_emit_stloc (mb
, 1);
5038 /* emit valuetype conversion code */
5039 emit_struct_conv (mb
, klass
, TRUE
);
5042 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5043 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
5048 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
5050 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5054 mono_mb_emit_ldarg (mb
, argnum
);
5056 mono_mb_emit_ldarg_addr (mb
, argnum
);
5057 mono_mb_emit_stloc (mb
, 0);
5060 mono_mb_emit_ldloc (mb
, 0);
5061 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5064 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5065 mono_mb_emit_stloc (mb
, 1);
5067 /* emit valuetype conversion code */
5068 emit_struct_conv (mb
, klass
, TRUE
);
5071 mono_mb_patch_branch (mb
, pos
);
5074 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5075 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
5077 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5080 /* Check for null */
5081 mono_mb_emit_ldarg (mb
, argnum
);
5082 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5085 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5086 mono_mb_emit_stloc (mb
, 0);
5089 mono_mb_emit_ldarg (mb
, argnum
);
5090 mono_mb_emit_stloc (mb
, 1);
5092 /* emit valuetype conversion code */
5093 emit_struct_conv (mb
, klass
, FALSE
);
5095 mono_mb_patch_branch (mb
, pos2
);
5098 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5099 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
5100 mono_mb_emit_stloc (mb
, 3);
5105 /* load pointer to returned value type */
5106 g_assert (m
->vtaddr_var
);
5107 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
5109 /* store the address of the source into local variable 0 */
5110 mono_mb_emit_stloc (mb
, 0);
5111 /* allocate space for the native struct and
5112 * store the address into dst_ptr */
5113 m
->retobj_var
= mono_mb_add_local (mb
, int_type
);
5114 m
->retobj_class
= klass
;
5115 g_assert (m
->retobj_var
);
5116 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5117 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5118 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5119 mono_mb_emit_stloc (mb
, 1);
5120 mono_mb_emit_ldloc (mb
, 1);
5121 mono_mb_emit_stloc (mb
, m
->retobj_var
);
5123 /* emit valuetype conversion code */
5124 emit_struct_conv (mb
, klass
, FALSE
);
5128 g_assert_not_reached ();
5134 emit_string_free_icall (MonoMethodBuilder
*mb
, MonoMarshalConv conv
)
5136 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
|| conv
== MONO_MARSHAL_CONV_ANSIBSTR_STR
|| conv
== MONO_MARSHAL_CONV_TBSTR_STR
)
5137 mono_mb_emit_icall (mb
, mono_free_bstr
);
5139 mono_mb_emit_icall (mb
, mono_marshal_free
);
5143 emit_marshal_string_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5144 MonoMarshalSpec
*spec
,
5145 int conv_arg
, MonoType
**conv_arg_type
,
5146 MarshalAction action
)
5148 MonoMethodBuilder
*mb
= m
->mb
;
5149 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5150 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
5153 MonoType
*int_type
= mono_get_int_type ();
5154 MonoType
*object_type
= mono_get_object_type ();
5156 case MARSHAL_ACTION_CONV_IN
:
5157 *conv_arg_type
= int_type
;
5158 conv_arg
= mono_mb_add_local (mb
, int_type
);
5161 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5164 mono_mb_emit_ldarg (mb
, argnum
);
5165 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5167 mono_mb_emit_ldarg (mb
, argnum
);
5170 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5171 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5172 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5174 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5176 mono_mb_emit_stloc (mb
, conv_arg
);
5180 case MARSHAL_ACTION_CONV_OUT
:
5181 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5182 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5183 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5184 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5188 if (encoding
== MONO_NATIVE_VBBYREFSTR
) {
5191 char *msg
= g_strdup ("VBByRefStr marshalling requires a ref parameter.");
5192 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5196 MONO_STATIC_POINTER_INIT (MonoMethod
, m
)
5198 m
= get_method_nofail (mono_defaults
.string_class
, "get_Length", -1, 0);
5200 MONO_STATIC_POINTER_INIT_END (MonoMethod
, m
)
5203 * Have to allocate a new string with the same length as the original, and
5204 * copy the contents of the buffer pointed to by CONV_ARG into it.
5206 g_assert (t
->byref
);
5207 mono_mb_emit_ldarg (mb
, argnum
);
5208 mono_mb_emit_ldloc (mb
, conv_arg
);
5209 mono_mb_emit_ldarg (mb
, argnum
);
5210 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5211 mono_mb_emit_managed_call (mb
, m
, NULL
);
5212 mono_mb_emit_icall (mb
, mono_string_new_len_wrapper
);
5213 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5214 } else if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5216 mono_mb_emit_ldarg (mb
, argnum
);
5217 mono_mb_emit_ldloc (mb
, conv_arg
);
5218 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
5219 mono_mb_emit_byte (mb
, stind_op
);
5224 mono_mb_emit_ldloc (mb
, conv_arg
);
5225 emit_string_free_icall (mb
, conv
);
5229 case MARSHAL_ACTION_PUSH
:
5230 if (t
->byref
&& encoding
!= MONO_NATIVE_VBBYREFSTR
)
5231 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5233 mono_mb_emit_ldloc (mb
, conv_arg
);
5236 case MARSHAL_ACTION_CONV_RESULT
:
5237 mono_mb_emit_stloc (mb
, 0);
5239 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5240 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5241 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5242 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5246 mono_mb_emit_ldloc (mb
, 0);
5247 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5248 mono_mb_emit_stloc (mb
, 3);
5250 /* free the string */
5251 mono_mb_emit_ldloc (mb
, 0);
5252 emit_string_free_icall (mb
, conv
);
5255 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5256 conv_arg
= mono_mb_add_local (mb
, object_type
);
5258 *conv_arg_type
= int_type
;
5261 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5265 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5266 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5267 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5268 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5272 mono_mb_emit_ldarg (mb
, argnum
);
5274 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5275 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5276 mono_mb_emit_stloc (mb
, conv_arg
);
5279 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5283 mono_mb_emit_ldarg (mb
, argnum
);
5284 mono_mb_emit_ldloc (mb
, conv_arg
);
5285 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
5286 mono_mb_emit_byte (mb
, stind_op
);
5291 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5292 if (conv_to_icall (conv
, NULL
) == MONO_JIT_ICALL_mono_marshal_string_to_utf16
)
5293 /* We need to make a copy so the caller is able to free it */
5294 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
5296 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5297 mono_mb_emit_stloc (mb
, 3);
5301 g_assert_not_reached ();
5308 emit_marshal_safehandle_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5309 MonoMarshalSpec
*spec
, int conv_arg
,
5310 MonoType
**conv_arg_type
, MarshalAction action
)
5312 MonoMethodBuilder
*mb
= m
->mb
;
5313 MonoType
*int_type
= mono_get_int_type ();
5314 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
5317 case MARSHAL_ACTION_CONV_IN
: {
5318 int dar_release_slot
, pos
;
5320 conv_arg
= mono_mb_add_local (mb
, int_type
);
5321 *conv_arg_type
= int_type
;
5323 if (!sh_dangerous_add_ref
)
5324 init_safe_handle ();
5326 mono_mb_emit_ldarg (mb
, argnum
);
5327 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5328 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5330 mono_mb_patch_branch (mb
, pos
);
5332 /* Create local to hold the ref parameter to DangerousAddRef */
5333 dar_release_slot
= mono_mb_add_local (mb
, boolean_type
);
5335 /* set release = false; */
5336 mono_mb_emit_icon (mb
, 0);
5337 mono_mb_emit_stloc (mb
, dar_release_slot
);
5340 int old_handle_value_slot
= mono_mb_add_local (mb
, int_type
);
5343 mono_mb_emit_icon (mb
, 0);
5344 mono_mb_emit_stloc (mb
, conv_arg
);
5346 /* safehandle.DangerousAddRef (ref release) */
5347 mono_mb_emit_ldarg (mb
, argnum
);
5348 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5349 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5350 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5352 /* Pull the handle field from SafeHandle */
5353 mono_mb_emit_ldarg (mb
, argnum
);
5354 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5355 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5356 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5357 mono_mb_emit_byte (mb
, CEE_DUP
);
5358 mono_mb_emit_stloc (mb
, conv_arg
);
5359 mono_mb_emit_stloc (mb
, old_handle_value_slot
);
5362 /* safehandle.DangerousAddRef (ref release) */
5363 mono_mb_emit_ldarg (mb
, argnum
);
5364 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5365 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5367 /* Pull the handle field from SafeHandle */
5368 mono_mb_emit_ldarg (mb
, argnum
);
5369 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5370 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5371 mono_mb_emit_stloc (mb
, conv_arg
);
5377 case MARSHAL_ACTION_PUSH
:
5379 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5381 mono_mb_emit_ldloc (mb
, conv_arg
);
5384 case MARSHAL_ACTION_CONV_OUT
: {
5385 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5386 int dar_release_slot
= conv_arg
+ 1;
5389 if (!sh_dangerous_release
)
5390 init_safe_handle ();
5393 /* If there was SafeHandle on input we have to release the reference to it */
5395 mono_mb_emit_ldloc (mb
, dar_release_slot
);
5396 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5397 mono_mb_emit_ldarg (mb
, argnum
);
5398 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5399 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5400 mono_mb_patch_branch (mb
, label_next
);
5404 ERROR_DECL (local_error
);
5408 * If the SafeHandle was marshalled on input we can skip the marshalling on
5409 * output if the handle value is identical.
5412 int old_handle_value_slot
= dar_release_slot
+ 1;
5413 mono_mb_emit_ldloc (mb
, old_handle_value_slot
);
5414 mono_mb_emit_ldloc (mb
, conv_arg
);
5415 label_next
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5419 * Create an empty SafeHandle (of correct derived type).
5421 * FIXME: If an out-of-memory situation or exception happens here we will
5422 * leak the handle. We should move the allocation of the SafeHandle to the
5423 * input marshalling code to prevent that.
5425 ctor
= mono_class_get_method_from_name_checked (t
->data
.klass
, ".ctor", 0, 0, local_error
);
5426 if (ctor
== NULL
|| !is_ok (local_error
)){
5427 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5428 mono_error_cleanup (local_error
);
5432 /* refval = new SafeHandleDerived ()*/
5433 mono_mb_emit_ldarg (mb
, argnum
);
5434 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5435 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5437 /* refval.handle = returned_handle */
5438 mono_mb_emit_ldarg (mb
, argnum
);
5439 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5440 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5441 mono_mb_emit_ldloc (mb
, conv_arg
);
5442 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5445 mono_mb_patch_branch (mb
, label_next
);
5449 mono_mb_emit_ldloc (mb
, dar_release_slot
);
5450 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5451 mono_mb_emit_ldarg (mb
, argnum
);
5452 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5453 mono_mb_patch_branch (mb
, label_next
);
5458 case MARSHAL_ACTION_CONV_RESULT
: {
5460 MonoMethod
*ctor
= NULL
;
5461 int intptr_handle_slot
;
5463 if (mono_class_is_abstract (t
->data
.klass
)) {
5464 mono_mb_emit_byte (mb
, CEE_POP
);
5465 mono_mb_emit_exception_marshal_directive (mb
, g_strdup ("Returned SafeHandles should not be abstract"));
5469 ctor
= mono_class_get_method_from_name_checked (t
->data
.klass
, ".ctor", 0, 0, error
);
5470 if (ctor
== NULL
|| !is_ok (error
)){
5471 mono_error_cleanup (error
);
5472 mono_mb_emit_byte (mb
, CEE_POP
);
5473 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5476 /* Store the IntPtr results into a local */
5477 intptr_handle_slot
= mono_mb_add_local (mb
, int_type
);
5478 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
5480 /* Create return value */
5481 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5482 mono_mb_emit_stloc (mb
, 3);
5484 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5485 mono_mb_emit_ldloc (mb
, 3);
5486 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5487 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
5488 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5492 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5493 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5496 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5497 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5500 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5501 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5504 printf ("Unhandled case for MarshalAction: %d\n", action
);
5511 emit_marshal_handleref_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5512 MonoMarshalSpec
*spec
, int conv_arg
,
5513 MonoType
**conv_arg_type
, MarshalAction action
)
5515 MonoMethodBuilder
*mb
= m
->mb
;
5517 MonoType
*int_type
= mono_get_int_type ();
5519 case MARSHAL_ACTION_CONV_IN
: {
5520 conv_arg
= mono_mb_add_local (mb
, int_type
);
5521 *conv_arg_type
= int_type
;
5524 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5525 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5528 mono_mb_emit_ldarg_addr (mb
, argnum
);
5529 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
5530 mono_mb_emit_byte (mb
, CEE_ADD
);
5531 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5532 mono_mb_emit_stloc (mb
, conv_arg
);
5536 case MARSHAL_ACTION_PUSH
:
5537 mono_mb_emit_ldloc (mb
, conv_arg
);
5540 case MARSHAL_ACTION_CONV_OUT
: {
5541 /* no resource release required */
5545 case MARSHAL_ACTION_CONV_RESULT
: {
5546 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5547 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5551 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5552 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5555 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5556 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5559 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5560 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5563 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
5570 emit_marshal_object_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5571 MonoMarshalSpec
*spec
,
5572 int conv_arg
, MonoType
**conv_arg_type
,
5573 MarshalAction action
)
5575 MonoMethodBuilder
*mb
= m
->mb
;
5576 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
5579 MonoType
*int_type
= mono_get_int_type ();
5581 case MARSHAL_ACTION_CONV_IN
:
5582 *conv_arg_type
= int_type
;
5583 conv_arg
= mono_mb_add_local (mb
, int_type
);
5585 m
->orig_conv_args
[argnum
] = 0;
5587 if (mono_class_from_mono_type_internal (t
) == mono_defaults
.object_class
) {
5588 char *msg
= g_strdup_printf ("Marshalling of type object is not implemented");
5589 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5593 if (m_class_is_delegate (klass
)) {
5595 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5596 char *msg
= g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5597 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5599 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5600 mono_mb_emit_stloc (mb
, conv_arg
);
5602 mono_mb_emit_ldarg (mb
, argnum
);
5603 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5604 mono_mb_emit_stloc (mb
, conv_arg
);
5606 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5607 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5608 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
5612 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5613 char *msg
= g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5614 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5620 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5623 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5624 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
5625 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5629 mono_mb_emit_ldarg (mb
, argnum
);
5631 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5633 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5634 mono_mb_emit_stloc (mb
, conv_arg
);
5635 } else if (m_class_is_blittable (klass
)) {
5636 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5637 mono_mb_emit_stloc (mb
, conv_arg
);
5639 mono_mb_emit_ldarg (mb
, argnum
);
5640 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5642 mono_mb_emit_ldarg (mb
, argnum
);
5643 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5644 mono_mb_emit_stloc (mb
, conv_arg
);
5646 mono_mb_patch_branch (mb
, pos
);
5649 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5650 mono_mb_emit_stloc (mb
, conv_arg
);
5653 /* we dont need any conversions for out parameters */
5654 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5657 mono_mb_emit_ldarg (mb
, argnum
);
5658 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5661 mono_mb_emit_ldarg (mb
, argnum
);
5662 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5663 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5666 /* store the address of the source into local variable 0 */
5667 mono_mb_emit_stloc (mb
, 0);
5668 mono_mb_emit_ldloc (mb
, 0);
5669 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5671 /* allocate space for the native struct and store the address */
5672 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5673 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5674 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5675 mono_mb_emit_stloc (mb
, conv_arg
);
5678 /* Need to store the original buffer so we can free it later */
5679 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, int_type
);
5680 mono_mb_emit_ldloc (mb
, conv_arg
);
5681 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
5684 /* set the src_ptr */
5685 mono_mb_emit_ldloc (mb
, 0);
5686 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5687 mono_mb_emit_stloc (mb
, 0);
5690 mono_mb_emit_ldloc (mb
, conv_arg
);
5691 mono_mb_emit_stloc (mb
, 1);
5693 /* emit valuetype conversion code */
5694 emit_struct_conv (mb
, klass
, FALSE
);
5696 mono_mb_patch_branch (mb
, pos
);
5700 case MARSHAL_ACTION_CONV_OUT
:
5701 if (klass
== mono_class_try_get_stringbuilder_class ()) {
5703 MonoMarshalNative encoding
;
5704 MonoMarshalConv conv
;
5706 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5707 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
5709 g_assert (encoding
!= -1);
5712 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5716 mono_mb_emit_ldarg (mb
, argnum
);
5717 mono_mb_emit_ldloc (mb
, conv_arg
);
5720 case MONO_NATIVE_LPWSTR
:
5721 mono_mb_emit_icall (mb
, mono_string_utf16_to_builder2
);
5723 case MONO_NATIVE_LPSTR
:
5724 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5726 case MONO_NATIVE_UTF8STR
:
5727 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5730 g_assert_not_reached ();
5733 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5734 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
)) {
5735 mono_mb_emit_ldarg (mb
, argnum
);
5736 mono_mb_emit_ldloc (mb
, conv_arg
);
5738 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5742 mono_mb_emit_ldloc (mb
, conv_arg
);
5743 mono_mb_emit_icall (mb
, mono_marshal_free
);
5748 if (m_class_is_delegate (klass
)) {
5750 mono_mb_emit_ldarg (mb
, argnum
);
5751 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5752 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5753 mono_mb_emit_ldloc (mb
, conv_arg
);
5754 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5755 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5760 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5761 /* allocate a new object */
5762 mono_mb_emit_ldarg (mb
, argnum
);
5763 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5764 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5765 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5768 /* dst = *argument */
5769 mono_mb_emit_ldarg (mb
, argnum
);
5772 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5774 mono_mb_emit_stloc (mb
, 1);
5776 mono_mb_emit_ldloc (mb
, 1);
5777 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5779 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5780 mono_mb_emit_ldloc (mb
, 1);
5781 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
5782 mono_mb_emit_byte (mb
, CEE_ADD
);
5783 mono_mb_emit_stloc (mb
, 1);
5785 /* src = tmp_locals [i] */
5786 mono_mb_emit_ldloc (mb
, conv_arg
);
5787 mono_mb_emit_stloc (mb
, 0);
5789 /* emit valuetype conversion code */
5790 emit_struct_conv (mb
, klass
, TRUE
);
5792 /* Free the structure returned by the native code */
5793 emit_struct_free (mb
, klass
, conv_arg
);
5795 if (m
->orig_conv_args
[argnum
]) {
5797 * If the native function changed the pointer, then free
5798 * the original structure plus the new pointer.
5800 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
5801 mono_mb_emit_ldloc (mb
, conv_arg
);
5802 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5804 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5805 g_assert (m
->orig_conv_args
[argnum
]);
5807 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
5810 mono_mb_emit_ldloc (mb
, conv_arg
);
5811 mono_mb_emit_icall (mb
, mono_marshal_free
);
5813 mono_mb_patch_branch (mb
, pos2
);
5817 /* Free the original structure passed to native code */
5818 emit_struct_free (mb
, klass
, conv_arg
);
5820 mono_mb_patch_branch (mb
, pos
);
5823 case MARSHAL_ACTION_PUSH
:
5825 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5827 mono_mb_emit_ldloc (mb
, conv_arg
);
5830 case MARSHAL_ACTION_CONV_RESULT
:
5831 if (m_class_is_delegate (klass
)) {
5832 g_assert (!t
->byref
);
5833 mono_mb_emit_stloc (mb
, 0);
5834 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5835 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5836 mono_mb_emit_ldloc (mb
, 0);
5837 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5838 mono_mb_emit_stloc (mb
, 3);
5839 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5841 char *msg
= g_strdup_printf ("Return marshalling of stringbuilders is not implemented.");
5842 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5845 mono_mb_emit_stloc (mb
, 0);
5847 /* Make a copy since emit_conv modifies local 0 */
5848 loc
= mono_mb_add_local (mb
, int_type
);
5849 mono_mb_emit_ldloc (mb
, 0);
5850 mono_mb_emit_stloc (mb
, loc
);
5852 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5853 mono_mb_emit_stloc (mb
, 3);
5855 mono_mb_emit_ldloc (mb
, 0);
5856 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5858 /* allocate result object */
5860 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5861 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5862 mono_mb_emit_stloc (mb
, 3);
5866 mono_mb_emit_ldloc (mb
, 3);
5867 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5868 mono_mb_emit_stloc (mb
, 1);
5870 /* emit conversion code */
5871 emit_struct_conv (mb
, klass
, TRUE
);
5873 emit_struct_free (mb
, klass
, loc
);
5875 /* Free the pointer allocated by unmanaged code */
5876 mono_mb_emit_ldloc (mb
, loc
);
5877 mono_mb_emit_icall (mb
, mono_marshal_free
);
5878 mono_mb_patch_branch (mb
, pos
);
5882 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5883 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
5885 if (m_class_is_delegate (klass
)) {
5886 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5887 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5888 mono_mb_emit_ldarg (mb
, argnum
);
5890 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5891 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5892 mono_mb_emit_stloc (mb
, conv_arg
);
5896 if (klass
== mono_class_try_get_stringbuilder_class ()) {
5897 MonoMarshalNative encoding
;
5899 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5902 g_assert (encoding
== MONO_NATIVE_LPSTR
|| encoding
== MONO_NATIVE_UTF8STR
);
5904 g_assert (!t
->byref
);
5905 g_assert (encoding
!= -1);
5907 mono_mb_emit_ldarg (mb
, argnum
);
5908 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5909 mono_mb_emit_stloc (mb
, conv_arg
);
5913 /* The class can not have an automatic layout */
5914 if (mono_class_is_auto_layout (klass
)) {
5915 mono_mb_emit_auto_layout_exception (mb
, klass
);
5919 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
5920 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5921 mono_mb_emit_stloc (mb
, conv_arg
);
5926 mono_mb_emit_ldarg (mb
, argnum
);
5930 /* Check for NULL and raise an exception */
5931 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5933 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5935 mono_mb_patch_branch (mb
, pos2
);
5936 mono_mb_emit_ldarg (mb
, argnum
);
5937 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5940 mono_mb_emit_stloc (mb
, 0);
5942 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5943 mono_mb_emit_stloc (mb
, conv_arg
);
5945 mono_mb_emit_ldloc (mb
, 0);
5946 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5948 /* Create and set dst */
5949 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5950 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5951 mono_mb_emit_stloc (mb
, conv_arg
);
5952 mono_mb_emit_ldloc (mb
, conv_arg
);
5953 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5954 mono_mb_emit_stloc (mb
, 1);
5956 /* emit valuetype conversion code */
5957 emit_struct_conv (mb
, klass
, TRUE
);
5959 mono_mb_patch_branch (mb
, pos
);
5962 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5963 if (m_class_is_delegate (klass
)) {
5966 mono_mb_emit_ldarg (mb
, argnum
);
5967 mono_mb_emit_ldloc (mb
, conv_arg
);
5968 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, &stind_op
));
5969 mono_mb_emit_byte (mb
, stind_op
);
5975 /* Check for null */
5976 mono_mb_emit_ldloc (mb
, conv_arg
);
5977 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5978 mono_mb_emit_ldarg (mb
, argnum
);
5979 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5980 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5981 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
5983 mono_mb_patch_branch (mb
, pos
);
5986 mono_mb_emit_ldloc (mb
, conv_arg
);
5987 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5988 mono_mb_emit_stloc (mb
, 0);
5990 /* Allocate and set dest */
5991 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5992 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5993 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5994 mono_mb_emit_stloc (mb
, 1);
5996 /* Update argument pointer */
5997 mono_mb_emit_ldarg (mb
, argnum
);
5998 mono_mb_emit_ldloc (mb
, 1);
5999 mono_mb_emit_byte (mb
, CEE_STIND_I
);
6001 /* emit valuetype conversion code */
6002 emit_struct_conv (mb
, klass
, FALSE
);
6004 mono_mb_patch_branch (mb
, pos2
);
6005 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
6006 // FIXME: What to do here ?
6008 /* byval [Out] marshalling */
6010 /* FIXME: Handle null */
6013 mono_mb_emit_ldloc (mb
, conv_arg
);
6014 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6015 mono_mb_emit_stloc (mb
, 0);
6018 mono_mb_emit_ldarg (mb
, argnum
);
6019 mono_mb_emit_stloc (mb
, 1);
6021 /* emit valuetype conversion code */
6022 emit_struct_conv (mb
, klass
, FALSE
);
6026 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
6027 if (m_class_is_delegate (klass
)) {
6028 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
6029 mono_mb_emit_stloc (mb
, 3);
6033 /* The class can not have an automatic layout */
6034 if (mono_class_is_auto_layout (klass
)) {
6035 mono_mb_emit_auto_layout_exception (mb
, klass
);
6039 mono_mb_emit_stloc (mb
, 0);
6040 /* Check for null */
6041 mono_mb_emit_ldloc (mb
, 0);
6042 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6043 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6044 mono_mb_emit_stloc (mb
, 3);
6045 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
6047 mono_mb_patch_branch (mb
, pos
);
6050 mono_mb_emit_ldloc (mb
, 0);
6051 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6052 mono_mb_emit_stloc (mb
, 0);
6054 /* Allocate and set dest */
6055 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
6056 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6057 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
6058 mono_mb_emit_byte (mb
, CEE_DUP
);
6059 mono_mb_emit_stloc (mb
, 1);
6060 mono_mb_emit_stloc (mb
, 3);
6062 emit_struct_conv (mb
, klass
, FALSE
);
6064 mono_mb_patch_branch (mb
, pos2
);
6068 g_assert_not_reached ();
6074 emit_marshal_variant_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
6075 MonoMarshalSpec
*spec
,
6076 int conv_arg
, MonoType
**conv_arg_type
,
6077 MarshalAction action
)
6080 MonoMethodBuilder
*mb
= m
->mb
;
6081 MonoType
*variant_type
= m_class_get_byval_arg (mono_class_get_variant_class ());
6082 MonoType
*variant_type_byref
= m_class_get_this_arg (mono_class_get_variant_class ());
6083 MonoType
*object_type
= mono_get_object_type ();
6086 case MARSHAL_ACTION_CONV_IN
: {
6087 conv_arg
= mono_mb_add_local (mb
, variant_type
);
6090 *conv_arg_type
= variant_type_byref
;
6092 *conv_arg_type
= variant_type
;
6094 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6097 mono_mb_emit_ldarg (mb
, argnum
);
6099 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
6100 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6101 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetNativeVariantForObject (), NULL
);
6105 case MARSHAL_ACTION_CONV_OUT
: {
6106 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6107 mono_mb_emit_ldarg (mb
, argnum
);
6108 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6109 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetObjectForNativeVariant (), NULL
);
6110 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6113 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6114 mono_mb_emit_managed_call (mb
, mono_get_Variant_Clear (), NULL
);
6118 case MARSHAL_ACTION_PUSH
:
6120 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
6122 mono_mb_emit_ldloc (mb
, conv_arg
);
6125 case MARSHAL_ACTION_CONV_RESULT
: {
6126 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6127 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6131 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
6132 conv_arg
= mono_mb_add_local (mb
, object_type
);
6135 *conv_arg_type
= variant_type_byref
;
6137 *conv_arg_type
= variant_type
;
6139 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
6143 mono_mb_emit_ldarg (mb
, argnum
);
6145 mono_mb_emit_ldarg_addr (mb
, argnum
);
6146 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetObjectForNativeVariant (), NULL
);
6147 mono_mb_emit_stloc (mb
, conv_arg
);
6151 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
6152 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
6153 mono_mb_emit_ldloc (mb
, conv_arg
);
6154 mono_mb_emit_ldarg (mb
, argnum
);
6155 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetNativeVariantForObject (), NULL
);
6160 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
6161 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6162 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6167 g_assert_not_reached ();
6169 #endif /* DISABLE_COM */
6175 emit_managed_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, MonoGCHandle target_handle
)
6177 MonoMethodSignature
*sig
, *csig
;
6178 int i
, *tmp_locals
, orig_domain
, attach_cookie
;
6179 gboolean closed
= FALSE
;
6184 MonoType
*int_type
= mono_get_int_type ();
6185 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
6186 /* allocate local 0 (pointer) src_ptr */
6187 mono_mb_add_local (mb
, int_type
);
6188 /* allocate local 1 (pointer) dst_ptr */
6189 mono_mb_add_local (mb
, int_type
);
6190 /* allocate local 2 (boolean) delete_old */
6191 mono_mb_add_local (mb
, boolean_type
);
6193 if (!sig
->hasthis
&& sig
->param_count
!= invoke_sig
->param_count
) {
6194 /* Closed delegate */
6195 g_assert (sig
->param_count
== invoke_sig
->param_count
+ 1);
6197 /* Use a new signature without the first argument */
6198 sig
= mono_metadata_signature_dup (sig
);
6199 memmove (&sig
->params
[0], &sig
->params
[1], (sig
->param_count
- 1) * sizeof (MonoType
*));
6200 sig
->param_count
--;
6203 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
6204 /* allocate local 3 to store the return value */
6205 mono_mb_add_local (mb
, sig
->ret
);
6208 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6209 m
->vtaddr_var
= mono_mb_add_local (mb
, int_type
);
6211 orig_domain
= mono_mb_add_local (mb
, int_type
);
6212 attach_cookie
= mono_mb_add_local (mb
, int_type
);
6215 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
6216 * intptr_t attach_cookie;
6217 * intptr_t orig_domain = mono_threads_attach_coop (domain, &attach_cookie);
6220 * ret = method (...);
6221 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
6222 * mono_threads_detach_coop (orig_domain, &attach_cookie);
6227 mono_mb_emit_icon (mb
, 0);
6228 mono_mb_emit_stloc (mb
, 2);
6230 /* orig_domain = mono_threads_attach_coop (domain, &attach_cookie); */
6231 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6232 mono_mb_emit_byte (mb
, CEE_MONO_LDDOMAIN
);
6233 mono_mb_emit_ldloc_addr (mb
, attach_cookie
);
6235 * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads.
6236 * Keep this in sync with the CEE_JIT_ICALL code in the JIT.
6238 * Special cased in interpreter, keep in sync.
6240 mono_mb_emit_icall (mb
, mono_threads_attach_coop
);
6241 mono_mb_emit_stloc (mb
, orig_domain
);
6243 /* <interrupt check> */
6244 emit_thread_interrupt_checkpoint (mb
);
6246 /* we first do all conversions */
6247 tmp_locals
= g_newa (int, sig
->param_count
);
6248 for (i
= 0; i
< sig
->param_count
; i
++) {
6249 MonoType
*t
= sig
->params
[i
];
6252 case MONO_TYPE_OBJECT
:
6253 case MONO_TYPE_CLASS
:
6254 case MONO_TYPE_VALUETYPE
:
6255 case MONO_TYPE_ARRAY
:
6256 case MONO_TYPE_SZARRAY
:
6257 case MONO_TYPE_STRING
:
6258 case MONO_TYPE_BOOLEAN
:
6259 tmp_locals
[i
] = mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
6268 if (target_handle
) {
6269 mono_mb_emit_icon8 (mb
, (gint64
)target_handle
);
6270 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6271 mono_mb_emit_icall (mb
, mono_gchandle_get_target_internal
);
6274 g_assert_not_reached ();
6276 } else if (closed
) {
6277 mono_mb_emit_icon8 (mb
, (gint64
)target_handle
);
6278 mono_mb_emit_byte (mb
, CEE_CONV_I
);
6279 mono_mb_emit_icall (mb
, mono_gchandle_get_target_internal
);
6282 for (i
= 0; i
< sig
->param_count
; i
++) {
6283 MonoType
*t
= sig
->params
[i
];
6285 if (tmp_locals
[i
]) {
6287 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
6289 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
6292 mono_mb_emit_ldarg (mb
, i
);
6295 /* ret = method (...) */
6296 mono_mb_emit_managed_call (mb
, method
, NULL
);
6298 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
6299 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
6300 mono_class_init_internal (klass
);
6301 if (!(mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
))) {
6302 /* This is used by get_marshal_cb ()->emit_marshal_vtype (), but it needs to go right before the call */
6303 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6304 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
6305 mono_mb_emit_stloc (mb
, m
->vtaddr_var
);
6309 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
6310 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6311 } else if (!sig
->ret
->byref
) {
6312 switch (sig
->ret
->type
) {
6313 case MONO_TYPE_VOID
:
6315 case MONO_TYPE_BOOLEAN
:
6318 case MONO_TYPE_CHAR
:
6330 case MONO_TYPE_OBJECT
:
6331 mono_mb_emit_stloc (mb
, 3);
6333 case MONO_TYPE_STRING
:
6334 csig
->ret
= int_type
;
6335 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6337 case MONO_TYPE_VALUETYPE
:
6338 case MONO_TYPE_CLASS
:
6339 case MONO_TYPE_SZARRAY
:
6340 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6343 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
6344 g_assert_not_reached ();
6347 mono_mb_emit_stloc (mb
, 3);
6350 /* Convert byref arguments back */
6351 for (i
= 0; i
< sig
->param_count
; i
++) {
6352 MonoType
*t
= sig
->params
[i
];
6353 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
6355 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
6356 mono_emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6358 else if (t
->byref
) {
6360 case MONO_TYPE_CLASS
:
6361 case MONO_TYPE_VALUETYPE
:
6362 case MONO_TYPE_OBJECT
:
6363 case MONO_TYPE_STRING
:
6364 case MONO_TYPE_BOOLEAN
:
6365 mono_emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6371 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
6372 /* The [Out] information is encoded in the delegate signature */
6374 case MONO_TYPE_SZARRAY
:
6375 case MONO_TYPE_CLASS
:
6376 case MONO_TYPE_VALUETYPE
:
6377 mono_emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6380 g_assert_not_reached ();
6385 /* mono_threads_detach_coop (orig_domain, &attach_cookie); */
6386 mono_mb_emit_ldloc (mb
, orig_domain
);
6387 mono_mb_emit_ldloc_addr (mb
, attach_cookie
);
6388 /* Special cased in interpreter, keep in sync */
6389 mono_mb_emit_icall (mb
, mono_threads_detach_coop
);
6392 if (m
->retobj_var
) {
6393 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
6394 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6395 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
6398 if (!MONO_TYPE_IS_VOID (sig
->ret
))
6399 mono_mb_emit_ldloc (mb
, 3);
6400 mono_mb_emit_byte (mb
, CEE_RET
);
6408 emit_struct_to_ptr_ilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
6410 MonoType
*int_type
= mono_get_int_type ();
6411 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
6412 if (m_class_is_blittable (klass
)) {
6413 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6414 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6415 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6416 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
6417 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6418 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6421 /* allocate local 0 (pointer) src_ptr */
6422 mono_mb_add_local (mb
, int_type
);
6423 /* allocate local 1 (pointer) dst_ptr */
6424 mono_mb_add_local (mb
, int_type
);
6425 /* allocate local 2 (boolean) delete_old */
6426 mono_mb_add_local (mb
, boolean_type
);
6427 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
6428 mono_mb_emit_stloc (mb
, 2);
6430 /* initialize src_ptr to point to the start of object data */
6431 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6432 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6433 mono_mb_emit_stloc (mb
, 0);
6435 /* initialize dst_ptr */
6436 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6437 mono_mb_emit_stloc (mb
, 1);
6439 emit_struct_conv (mb
, klass
, FALSE
);
6442 mono_mb_emit_byte (mb
, CEE_RET
);
6446 emit_ptr_to_struct_ilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
6448 MonoType
*int_type
= mono_get_int_type ();
6449 if (m_class_is_blittable (klass
)) {
6450 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6451 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6452 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6453 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
6454 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6455 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6458 /* allocate local 0 (pointer) src_ptr */
6459 mono_mb_add_local (mb
, int_type
);
6460 /* allocate local 1 (pointer) dst_ptr */
6461 mono_mb_add_local (mb
, m_class_get_this_arg (klass
));
6463 /* initialize src_ptr to point to the start of object data */
6464 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6465 mono_mb_emit_stloc (mb
, 0);
6467 /* initialize dst_ptr */
6468 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6469 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6470 mono_mb_emit_stloc (mb
, 1);
6472 emit_struct_conv (mb
, klass
, TRUE
);
6475 mono_mb_emit_byte (mb
, CEE_RET
);
6479 emit_create_string_hack_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
6483 #ifdef ENABLE_NETCORE
6484 g_assert (!mono_method_signature_internal (res
)->hasthis
);
6486 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6488 for (i
= 1; i
<= csig
->param_count
; i
++)
6489 mono_mb_emit_ldarg (mb
, i
);
6490 mono_mb_emit_managed_call (mb
, res
, NULL
);
6491 mono_mb_emit_byte (mb
, CEE_RET
);
6494 /* How the arguments of an icall should be wrapped */
6496 /* Don't wrap at all, pass the argument as is */
6497 ICALL_HANDLES_WRAP_NONE
,
6498 /* Wrap the argument in an object handle, pass the handle to the icall */
6499 ICALL_HANDLES_WRAP_OBJ
,
6500 /* Wrap the argument in an object handle, pass the handle to the icall,
6501 write the value out from the handle when the icall returns */
6502 ICALL_HANDLES_WRAP_OBJ_INOUT
,
6503 /* Initialized an object handle to null, pass to the icalls,
6504 write the value out from the handle when the icall returns */
6505 ICALL_HANDLES_WRAP_OBJ_OUT
,
6506 /* Wrap the argument (a valuetype reference) in a handle to pin its
6507 enclosing object, but pass the raw reference to the icall. This is
6508 also how we pass byref generic parameter arguments to generic method
6509 icalls (e.g. System.Array:GetGenericValue_icall<T>(int idx, T out value)) */
6510 ICALL_HANDLES_WRAP_VALUETYPE_REF
,
6514 IcallHandlesWrap wrap
;
6515 // If wrap is OBJ_OUT or OBJ_INOUT this is >= 0 and holds the referenced managed object,
6516 // in case the actual parameter refers to a native frame.
6517 // Otherwise it is -1.
6519 } IcallHandlesLocal
;
6522 * Describes how to wrap the given parameter.
6525 static IcallHandlesWrap
6526 signature_param_uses_handles (MonoMethodSignature
*sig
, MonoMethodSignature
*generic_sig
, int param
)
6528 /* If there is a generic parameter that isn't passed byref, we don't
6529 * know how to pass it to an icall that expects some arguments to be
6530 * wrapped in handles: if the actual argument type is a reference type
6531 * we'd need to wrap it in a handle, otherwise we'd want to pass it as is.
6533 /* FIXME: We should eventually relax the assertion, below, to
6534 * allow generic parameters that are constrained to be reference types.
6536 g_assert (!generic_sig
|| !mono_type_is_generic_parameter (generic_sig
->params
[param
]));
6538 /* If the parameter in the generic version of the method signature is a
6539 * byref type variable T&, pass the corresponding argument by pinning
6540 * the memory and passing the raw pointer to the icall. Note that we
6541 * do this even if the actual instantiation is a byref reference type
6542 * like string& since the C code for the icall has to work uniformly
6543 * for both valuetypes and reference types.
6545 if (generic_sig
&& mono_type_is_byref_internal (generic_sig
->params
[param
]) &&
6546 (generic_sig
->params
[param
]->type
== MONO_TYPE_VAR
|| generic_sig
->params
[param
]->type
== MONO_TYPE_MVAR
))
6547 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
6549 if (MONO_TYPE_IS_REFERENCE (sig
->params
[param
])) {
6550 if (mono_signature_param_is_out (sig
, param
))
6551 return ICALL_HANDLES_WRAP_OBJ_OUT
;
6552 else if (mono_type_is_byref_internal (sig
->params
[param
]))
6553 return ICALL_HANDLES_WRAP_OBJ_INOUT
;
6555 return ICALL_HANDLES_WRAP_OBJ
;
6556 } else if (mono_type_is_byref_internal (sig
->params
[param
]))
6557 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
6559 return ICALL_HANDLES_WRAP_NONE
;
6563 emit_native_icall_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*piinfo
)
6566 MonoMethodSignature
*call_sig
= csig
;
6567 gboolean uses_handles
= FALSE
;
6568 gboolean foreign_icall
= FALSE
;
6569 IcallHandlesLocal
*handles_locals
= NULL
;
6570 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
6571 gboolean need_gc_safe
= FALSE
;
6572 GCSafeTransitionBuilder gc_safe_transition_builder
;
6574 (void) mono_lookup_internal_call_full (method
, FALSE
, &uses_handles
, &foreign_icall
);
6576 if (G_UNLIKELY (foreign_icall
)) {
6577 /* FIXME: we only want the transitions for hybrid suspend. Q: What to do about AOT? */
6578 need_gc_safe
= gc_safe_transition_builder_init (&gc_safe_transition_builder
, mb
, FALSE
);
6581 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder
);
6586 * Add a null check since public icalls can be called with 'call' which
6587 * does no such check.
6589 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6590 const int pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6591 mono_mb_emit_exception (mb
, "NullReferenceException", NULL
);
6592 mono_mb_patch_branch (mb
, pos
);
6596 MonoMethodSignature
*generic_sig
= NULL
;
6598 if (method
->is_inflated
) {
6600 MonoMethod
*generic_method
= ((MonoMethodInflated
*)method
)->declaring
;
6601 generic_sig
= mono_method_signature_checked (generic_method
, error
);
6602 mono_error_assert_ok (error
);
6605 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
6606 call_sig
= mono_metadata_signature_alloc (get_method_image (method
), csig
->param_count
);
6607 call_sig
->param_count
= csig
->param_count
;
6608 call_sig
->ret
= csig
->ret
;
6609 call_sig
->pinvoke
= csig
->pinvoke
;
6611 /* TODO support adding wrappers to non-static struct methods */
6612 g_assert (!sig
->hasthis
|| !m_class_is_valuetype (mono_method_get_class (method
)));
6614 handles_locals
= g_new0 (IcallHandlesLocal
, csig
->param_count
);
6616 for (int i
= 0; i
< csig
->param_count
; ++i
) {
6617 // Determine which args need to be wrapped in handles and adjust icall signature.
6618 // Here, a handle is a pointer to a volatile local in a managed frame -- which is sufficient and efficient.
6619 const IcallHandlesWrap w
= signature_param_uses_handles (csig
, generic_sig
, i
);
6620 handles_locals
[i
].wrap
= w
;
6624 case ICALL_HANDLES_WRAP_OBJ
:
6625 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6626 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6627 call_sig
->params
[i
] = mono_class_get_byref_type (mono_class_from_mono_type_internal (csig
->params
[i
]));
6629 case ICALL_HANDLES_WRAP_NONE
:
6630 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6631 call_sig
->params
[i
] = csig
->params
[i
];
6634 g_assert_not_reached ();
6637 // Add a local var to hold the references for each out arg.
6639 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6640 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6641 // FIXME better type
6642 local
= mono_mb_add_local (mb
, mono_get_object_type ());
6644 if (!mb
->volatile_locals
) {
6645 gpointer mem
= mono_image_alloc0 (get_method_image (method
), mono_bitset_alloc_size (csig
->param_count
+ 1, 0));
6646 mb
->volatile_locals
= mono_bitset_mem_new (mem
, csig
->param_count
+ 1, 0);
6648 mono_bitset_set (mb
->volatile_locals
, local
);
6650 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6651 case ICALL_HANDLES_WRAP_OBJ
:
6652 if (!mb
->volatile_args
) {
6653 gpointer mem
= mono_image_alloc0 (get_method_image (method
), mono_bitset_alloc_size (csig
->param_count
+ 1, 0));
6654 mb
->volatile_args
= mono_bitset_mem_new (mem
, csig
->param_count
+ 1, 0);
6656 mono_bitset_set (mb
->volatile_args
, i
);
6658 case ICALL_HANDLES_WRAP_NONE
:
6661 g_assert_not_reached ();
6663 handles_locals
[i
].handle
= local
;
6665 // Load each argument. References into the managed heap get wrapped in handles.
6666 // Handles here are just pointers to managed volatile locals.
6668 case ICALL_HANDLES_WRAP_NONE
:
6669 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6671 mono_mb_emit_ldarg (mb
, i
);
6673 case ICALL_HANDLES_WRAP_OBJ
:
6675 mono_mb_emit_ldarg_addr (mb
, i
);
6677 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6678 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6679 // If parameter guaranteeably referred to a managed frame,
6680 // then could just be passthrough and volatile. Since
6681 // that cannot be guaranteed, use a managed volatile local intermediate.
6685 // localI = *argI_raw
6687 if (w
== ICALL_HANDLES_WRAP_OBJ_OUT
) {
6688 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6690 mono_mb_emit_ldarg (mb
, i
);
6691 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6693 mono_mb_emit_stloc (mb
, local
);
6694 mono_mb_emit_ldloc_addr (mb
, local
);
6697 g_assert_not_reached ();
6701 for (int i
= 0; i
< csig
->param_count
; i
++)
6702 mono_mb_emit_ldarg (mb
, i
);
6706 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder
, &piinfo
->method
, aot
);
6709 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6710 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
6711 mono_mb_emit_calli (mb
, call_sig
);
6713 g_assert (piinfo
->addr
);
6714 mono_mb_emit_native_call (mb
, call_sig
, piinfo
->addr
);
6718 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder
);
6720 // Copy back ObjOut and ObjInOut from locals through parameters.
6721 if (mb
->volatile_locals
) {
6722 g_assert (handles_locals
);
6723 for (int i
= 0; i
< csig
->param_count
; i
++) {
6724 const int local
= handles_locals
[i
].handle
;
6726 // *argI_raw = localI
6727 mono_mb_emit_ldarg (mb
, i
);
6728 mono_mb_emit_ldloc (mb
, local
);
6729 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6733 g_free (handles_locals
);
6736 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder
);
6738 if (check_exceptions
)
6739 emit_thread_interrupt_checkpoint (mb
);
6740 mono_mb_emit_byte (mb
, CEE_RET
);
6744 mb_emit_exception_ilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
6746 mono_mb_emit_exception_full (mb
, exc_nspace
, exc_name
, msg
);
6750 mb_emit_exception_for_error_ilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
6752 mono_mb_emit_exception_for_error (mb
, (MonoError
*)error
);
6756 emit_vtfixup_ftnptr_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
6758 for (int i
= 0; i
< param_count
; i
++)
6759 mono_mb_emit_ldarg (mb
, i
);
6761 if (type
& VTFIXUP_TYPE_CALL_MOST_DERIVED
)
6762 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
6764 mono_mb_emit_op (mb
, CEE_CALL
, method
);
6765 mono_mb_emit_byte (mb
, CEE_RET
);
6769 emit_icall_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
6771 MonoMethodSignature
*const sig
= callinfo
->sig
;
6774 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6776 for (int i
= 0; i
< sig
->param_count
; i
++)
6777 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
6779 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6780 mono_mb_emit_byte (mb
, CEE_MONO_JIT_ICALL_ADDR
);
6781 mono_mb_emit_i4 (mb
, mono_jit_icall_info_index (callinfo
));
6782 mono_mb_emit_calli (mb
, csig2
);
6783 if (check_exceptions
)
6784 emit_thread_interrupt_checkpoint (mb
);
6785 mono_mb_emit_byte (mb
, CEE_RET
);
6789 emit_return_ilgen (MonoMethodBuilder
*mb
)
6791 mono_mb_emit_byte (mb
, CEE_RET
);
6795 mono_marshal_ilgen_init (void)
6797 MonoMarshalCallbacks cb
;
6798 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6799 cb
.emit_marshal_array
= emit_marshal_array_ilgen
;
6800 cb
.emit_marshal_boolean
= emit_marshal_boolean_ilgen
;
6801 cb
.emit_marshal_ptr
= emit_marshal_ptr_ilgen
;
6802 cb
.emit_marshal_char
= emit_marshal_char_ilgen
;
6803 cb
.emit_marshal_scalar
= emit_marshal_scalar_ilgen
;
6804 cb
.emit_marshal_custom
= emit_marshal_custom_ilgen
;
6805 cb
.emit_marshal_asany
= emit_marshal_asany_ilgen
;
6806 cb
.emit_marshal_vtype
= emit_marshal_vtype_ilgen
;
6807 cb
.emit_marshal_string
= emit_marshal_string_ilgen
;
6808 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_ilgen
;
6809 cb
.emit_marshal_handleref
= emit_marshal_handleref_ilgen
;
6810 cb
.emit_marshal_object
= emit_marshal_object_ilgen
;
6811 cb
.emit_marshal_variant
= emit_marshal_variant_ilgen
;
6812 cb
.emit_castclass
= emit_castclass_ilgen
;
6813 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_ilgen
;
6814 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_ilgen
;
6815 cb
.emit_isinst
= emit_isinst_ilgen
;
6816 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_ilgen
;
6817 cb
.emit_stelemref
= emit_stelemref_ilgen
;
6818 cb
.emit_array_address
= emit_array_address_ilgen
;
6819 cb
.emit_native_wrapper
= emit_native_wrapper_ilgen
;
6820 cb
.emit_managed_wrapper
= emit_managed_wrapper_ilgen
;
6821 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_ilgen
;
6822 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_ilgen
;
6823 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_ilgen
;
6824 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_ilgen
;
6825 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_ilgen
;
6826 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_ilgen
;
6827 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_ilgen
;
6828 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_ilgen
;
6829 cb
.emit_generic_array_helper
= emit_generic_array_helper_ilgen
;
6830 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_ilgen
;
6831 cb
.emit_create_string_hack
= emit_create_string_hack_ilgen
;
6832 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_ilgen
;
6833 cb
.emit_icall_wrapper
= emit_icall_wrapper_ilgen
;
6834 cb
.emit_return
= emit_return_ilgen
;
6835 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_ilgen
;
6836 cb
.mb_skip_visibility
= mb_skip_visibility_ilgen
;
6837 cb
.mb_set_dynamic
= mb_set_dynamic_ilgen
;
6838 cb
.mb_emit_exception
= mb_emit_exception_ilgen
;
6839 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_ilgen
;
6840 cb
.mb_emit_byte
= mb_emit_byte_ilgen
;
6841 mono_install_marshal_callbacks (&cb
);