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"
62 static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute
, "System.Runtime.CompilerServices", "FixedBufferAttribute");
63 static GENERATE_GET_CLASS_WITH_CACHE (date_time
, "System", "DateTime");
64 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler
, "System.Runtime.InteropServices", "ICustomMarshaler");
65 static GENERATE_TRY_GET_CLASS_WITH_CACHE (marshal
, "System.Runtime.InteropServices", "Marshal");
67 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
68 static MonoMethod
*sh_dangerous_add_ref
;
69 static MonoMethod
*sh_dangerous_release
;
72 get_method_nofail (MonoClass
*klass
, const char *method_name
, int num_params
, int flags
)
76 method
= mono_class_get_method_from_name_checked (klass
, method_name
, num_params
, flags
, error
);
77 mono_error_assert_ok (error
);
78 g_assertf (method
, "Could not lookup method %s in %s", method_name
, m_class_get_name (klass
));
83 init_safe_handle (void)
85 sh_dangerous_add_ref
= get_method_nofail (
86 mono_class_try_get_safehandle_class (), "DangerousAddRef", 1, 0);
87 sh_dangerous_release
= get_method_nofail (
88 mono_class_try_get_safehandle_class (), "DangerousRelease", 0, 0);
92 get_method_image (MonoMethod
*method
)
94 return m_class_get_image (method
->klass
);
98 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
101 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
, int offset_of_first_child_field
, MonoMarshalNative string_encoding
);
105 * \param mb the MethodBuilder
108 * Creates a copy of the string \p s that can be referenced from the IL of \c mb.
110 * \returns a pointer to the new string which is owned by the method builder
113 mono_mb_strdup (MonoMethodBuilder
*mb
, const char *s
)
117 res
= mono_image_strdup (get_method_image (mb
->method
), s
);
126 * mono_mb_emit_exception_marshal_directive:
128 * This function assumes ownership of MSG, which should be malloc-ed.
131 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, char *msg
)
133 char *s
= mono_mb_strdup (mb
, msg
);
135 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", s
);
139 offset_of_first_nonstatic_field (MonoClass
*klass
)
142 int fcount
= mono_class_get_field_count (klass
);
143 mono_class_setup_fields (klass
);
144 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
145 for (i
= 0; i
< fcount
; i
++) {
146 if (!(klass_fields
[i
].type
->attrs
& FIELD_ATTRIBUTE_STATIC
) && !mono_field_is_deleted (&klass_fields
[i
]))
147 return klass_fields
[i
].offset
- MONO_ABI_SIZEOF (MonoObject
);
154 get_fixed_buffer_attr (MonoClassField
*field
, MonoType
**out_etype
, int *out_len
)
157 MonoCustomAttrInfo
*cinfo
;
158 MonoCustomAttrEntry
*attr
;
161 cinfo
= mono_custom_attrs_from_field_checked (field
->parent
, field
, error
);
166 for (aindex
= 0; aindex
< cinfo
->num_attrs
; ++aindex
) {
167 MonoClass
*ctor_class
= cinfo
->attrs
[aindex
].ctor
->klass
;
168 if (mono_class_has_parent (ctor_class
, mono_class_get_fixed_buffer_attribute_class ())) {
169 attr
= &cinfo
->attrs
[aindex
];
175 gpointer
*typed_args
, *named_args
;
176 CattrNamedArg
*arginfo
;
179 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
180 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
183 *out_etype
= (MonoType
*)typed_args
[0];
184 *out_len
= *(gint32
*)typed_args
[1];
185 g_free (typed_args
[1]);
190 if (cinfo
&& !cinfo
->cached
)
191 mono_custom_attrs_free (cinfo
);
196 emit_fixed_buf_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoType
*etype
, int len
, gboolean to_object
, int *out_usize
)
198 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
199 MonoClass
*eklass
= mono_class_from_mono_type_internal (etype
);
202 esize
= mono_class_native_size (eklass
, NULL
);
204 MonoMarshalNative string_encoding
= m_class_is_unicode (klass
) ? MONO_NATIVE_LPWSTR
: MONO_NATIVE_LPSTR
;
205 int usize
= mono_class_value_size (eklass
, NULL
);
206 int msize
= mono_class_value_size (eklass
, NULL
);
208 //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), em_class_is_blittable (klass), string_encoding);
210 if (m_class_is_blittable (eklass
)) {
211 /* copy the elements */
212 mono_mb_emit_ldloc (mb
, 1);
213 mono_mb_emit_ldloc (mb
, 0);
214 mono_mb_emit_icon (mb
, len
* esize
);
215 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
216 mono_mb_emit_byte (mb
, CEE_CPBLK
);
219 guint32 label2
, label3
;
221 /* Emit marshalling loop */
222 MonoType
*int_type
= mono_get_int_type ();
223 index_var
= mono_mb_add_local (mb
, int_type
);
224 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
225 mono_mb_emit_stloc (mb
, index_var
);
228 label2
= mono_mb_get_label (mb
);
229 mono_mb_emit_ldloc (mb
, index_var
);
230 mono_mb_emit_icon (mb
, len
);
231 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
233 /* src/dst is already set */
235 /* Do the conversion */
236 MonoTypeEnum t
= etype
->type
;
242 case MONO_TYPE_BOOLEAN
:
251 mono_mb_emit_ldloc (mb
, 1);
252 mono_mb_emit_ldloc (mb
, 0);
253 if (t
== MONO_TYPE_CHAR
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
255 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
256 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
258 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
259 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
263 mono_mb_emit_byte (mb
, mono_type_to_ldind (etype
));
264 mono_mb_emit_byte (mb
, mono_type_to_stind (etype
));
268 g_assert_not_reached ();
273 mono_mb_emit_add_to_local (mb
, 0, usize
);
274 mono_mb_emit_add_to_local (mb
, 1, msize
);
276 mono_mb_emit_add_to_local (mb
, 0, msize
);
277 mono_mb_emit_add_to_local (mb
, 1, usize
);
281 mono_mb_emit_add_to_local (mb
, index_var
, 1);
283 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
285 mono_mb_patch_branch (mb
, label3
);
288 *out_usize
= usize
* len
;
292 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
295 case MONO_MARSHAL_CONV_BOOL_I4
:
296 mono_mb_emit_ldloc (mb
, 1);
297 mono_mb_emit_ldloc (mb
, 0);
298 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
299 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
300 mono_mb_emit_byte (mb
, 3);
301 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
302 mono_mb_emit_byte (mb
, CEE_BR_S
);
303 mono_mb_emit_byte (mb
, 1);
304 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
305 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
307 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
308 mono_mb_emit_ldloc (mb
, 1);
309 mono_mb_emit_ldloc (mb
, 0);
310 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
311 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
312 mono_mb_emit_byte (mb
, 3);
313 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
314 mono_mb_emit_byte (mb
, CEE_BR_S
);
315 mono_mb_emit_byte (mb
, 1);
316 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
317 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
319 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
320 MonoClass
*eklass
= NULL
;
323 if (type
->type
== MONO_TYPE_SZARRAY
) {
324 eklass
= type
->data
.klass
;
326 g_assert_not_reached ();
329 esize
= mono_class_native_size (eklass
, NULL
);
331 /* create a new array */
332 mono_mb_emit_ldloc (mb
, 1);
333 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
334 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
335 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
337 if (m_class_is_blittable (eklass
)) {
338 /* copy the elements */
339 mono_mb_emit_ldloc (mb
, 1);
340 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
341 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
342 mono_mb_emit_byte (mb
, CEE_ADD
);
343 mono_mb_emit_ldloc (mb
, 0);
344 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
345 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
346 mono_mb_emit_byte (mb
, CEE_CPBLK
);
349 int array_var
, src_var
, dst_var
, index_var
;
350 guint32 label2
, label3
;
352 MonoType
*int_type
= mono_get_int_type ();
353 array_var
= mono_mb_add_local (mb
, mono_get_object_type ());
354 src_var
= mono_mb_add_local (mb
, int_type
);
355 dst_var
= mono_mb_add_local (mb
, int_type
);
358 mono_mb_emit_ldloc (mb
, 1);
359 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
360 mono_mb_emit_stloc (mb
, array_var
);
362 /* save the old src pointer */
363 mono_mb_emit_ldloc (mb
, 0);
364 mono_mb_emit_stloc (mb
, src_var
);
365 /* save the old dst pointer */
366 mono_mb_emit_ldloc (mb
, 1);
367 mono_mb_emit_stloc (mb
, dst_var
);
369 /* Emit marshalling loop */
370 index_var
= mono_mb_add_local (mb
, int_type
);
371 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
372 mono_mb_emit_stloc (mb
, index_var
);
375 label2
= mono_mb_get_label (mb
);
376 mono_mb_emit_ldloc (mb
, index_var
);
377 mono_mb_emit_ldloc (mb
, array_var
);
378 mono_mb_emit_byte (mb
, CEE_LDLEN
);
379 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
381 /* src is already set */
384 mono_mb_emit_ldloc (mb
, array_var
);
385 mono_mb_emit_ldloc (mb
, index_var
);
386 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
387 mono_mb_emit_stloc (mb
, 1);
389 /* Do the conversion */
390 emit_struct_conv (mb
, eklass
, TRUE
);
393 mono_mb_emit_add_to_local (mb
, index_var
, 1);
395 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
397 mono_mb_patch_branch (mb
, label3
);
399 /* restore the old src pointer */
400 mono_mb_emit_ldloc (mb
, src_var
);
401 mono_mb_emit_stloc (mb
, 0);
402 /* restore the old dst pointer */
403 mono_mb_emit_ldloc (mb
, dst_var
);
404 mono_mb_emit_stloc (mb
, 1);
408 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
409 MonoClass
*eclass
= mono_defaults
.char_class
;
411 /* create a new array */
412 mono_mb_emit_ldloc (mb
, 1);
413 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
414 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
415 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
417 mono_mb_emit_ldloc (mb
, 1);
418 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
419 mono_mb_emit_ldloc (mb
, 0);
420 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
421 mono_mb_emit_icall (mb
, mono_byvalarray_to_byte_array
);
424 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
425 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
426 mono_mb_emit_ldloc (mb
, 1);
427 mono_mb_emit_ldloc (mb
, 0);
428 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
429 mono_mb_emit_icall (mb
, mono_string_from_byvalstr
);
431 mono_mb_emit_ldloc (mb
, 1);
432 mono_mb_emit_ldloc (mb
, 0);
433 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
435 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
437 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
438 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
439 mono_mb_emit_ldloc (mb
, 1);
440 mono_mb_emit_ldloc (mb
, 0);
441 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
442 mono_mb_emit_icall (mb
, mono_string_from_byvalwstr
);
444 mono_mb_emit_ldloc (mb
, 1);
445 mono_mb_emit_ldloc (mb
, 0);
446 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
448 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
450 case MONO_MARSHAL_CONV_STR_LPTSTR
:
451 mono_mb_emit_ldloc (mb
, 1);
452 mono_mb_emit_ldloc (mb
, 0);
453 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
455 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
457 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
459 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
462 // In Mono historically LPSTR was treated as a UTF8STR
463 case MONO_MARSHAL_CONV_STR_LPSTR
:
464 case MONO_MARSHAL_CONV_STR_UTF8STR
:
465 mono_mb_emit_ldloc (mb
, 1);
466 mono_mb_emit_ldloc (mb
, 0);
467 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
468 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
469 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
471 case MONO_MARSHAL_CONV_STR_LPWSTR
:
472 mono_mb_emit_ldloc (mb
, 1);
473 mono_mb_emit_ldloc (mb
, 0);
474 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
475 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
476 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
478 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
479 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
480 int src_var
, dst_var
;
482 MonoType
*int_type
= mono_get_int_type ();
483 src_var
= mono_mb_add_local (mb
, int_type
);
484 dst_var
= mono_mb_add_local (mb
, int_type
);
486 /* *dst = new object */
487 mono_mb_emit_ldloc (mb
, 1);
488 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
489 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
490 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
492 /* save the old src pointer */
493 mono_mb_emit_ldloc (mb
, 0);
494 mono_mb_emit_stloc (mb
, src_var
);
495 /* save the old dst pointer */
496 mono_mb_emit_ldloc (mb
, 1);
497 mono_mb_emit_stloc (mb
, dst_var
);
499 /* dst = pointer to newly created object data */
500 mono_mb_emit_ldloc (mb
, 1);
501 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
502 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
503 mono_mb_emit_byte (mb
, CEE_ADD
);
504 mono_mb_emit_stloc (mb
, 1);
506 emit_struct_conv (mb
, klass
, TRUE
);
508 /* restore the old src pointer */
509 mono_mb_emit_ldloc (mb
, src_var
);
510 mono_mb_emit_stloc (mb
, 0);
511 /* restore the old dst pointer */
512 mono_mb_emit_ldloc (mb
, dst_var
);
513 mono_mb_emit_stloc (mb
, 1);
516 case MONO_MARSHAL_CONV_DEL_FTN
: {
517 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
519 mono_mb_emit_ldloc (mb
, 1);
520 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
521 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
522 mono_mb_emit_ldloc (mb
, 0);
523 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
524 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
525 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
528 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
: {
529 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
)));
530 mono_mb_emit_exception_marshal_directive (mb
, msg
);
535 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
536 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
537 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
538 mono_cominterop_emit_ptr_to_object_conv (mb
, type
, conv
, mspec
);
540 #endif /* DISABLE_COM */
542 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
544 * Passing SafeHandles as ref does not allow the unmanaged code
545 * to change the SafeHandle value. If the value is changed,
546 * we should issue a diagnostic exception (NotSupportedException)
547 * that informs the user that changes to handles in unmanaged code
550 * Since we currently have no access to the original
551 * SafeHandle that was used during the marshalling,
552 * for now we just ignore this, and ignore/discard any
553 * changes that might have happened to the handle.
558 case MONO_MARSHAL_CONV_HANDLEREF
: {
560 * Passing HandleRefs in a struct that is ref()ed does not
561 * copy the values back to the HandleRef
566 case MONO_MARSHAL_CONV_STR_BSTR
:
567 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
568 case MONO_MARSHAL_CONV_STR_TBSTR
:
569 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
571 char *msg
= g_strdup_printf ("marshaling conversion %d not implemented", conv
);
573 mono_mb_emit_exception_marshal_directive (mb
, msg
);
579 static MonoJitICallId
580 conv_to_icall (MonoMarshalConv conv
, int *ind_store_type
)
582 // FIXME This or its caller might be a good place to inline some
583 // of the wrapper logic. In particular, to produce
584 // volatile stack-based handles. Being data-driven,
589 ind_store_type
= &dummy
;
590 *ind_store_type
= CEE_STIND_I
;
592 case MONO_MARSHAL_CONV_STR_LPWSTR
:
593 return MONO_JIT_ICALL_mono_marshal_string_to_utf16
;
594 case MONO_MARSHAL_CONV_LPWSTR_STR
:
595 *ind_store_type
= CEE_STIND_REF
;
596 return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16
;
597 case MONO_MARSHAL_CONV_LPTSTR_STR
:
598 *ind_store_type
= CEE_STIND_REF
;
599 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
600 case MONO_MARSHAL_CONV_UTF8STR_STR
:
601 case MONO_MARSHAL_CONV_LPSTR_STR
:
602 *ind_store_type
= CEE_STIND_REF
;
603 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
604 case MONO_MARSHAL_CONV_STR_LPTSTR
:
606 return MONO_JIT_ICALL_mono_marshal_string_to_utf16
;
608 return MONO_JIT_ICALL_mono_string_to_utf8str
;
610 // In Mono historically LPSTR was treated as a UTF8STR
611 case MONO_MARSHAL_CONV_STR_UTF8STR
:
612 case MONO_MARSHAL_CONV_STR_LPSTR
:
613 return MONO_JIT_ICALL_mono_string_to_utf8str
;
614 case MONO_MARSHAL_CONV_STR_BSTR
:
615 return MONO_JIT_ICALL_mono_string_to_bstr
;
616 case MONO_MARSHAL_CONV_BSTR_STR
:
617 *ind_store_type
= CEE_STIND_REF
;
618 return MONO_JIT_ICALL_mono_string_from_bstr_icall
;
619 case MONO_MARSHAL_CONV_STR_TBSTR
:
620 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
621 return MONO_JIT_ICALL_mono_string_to_ansibstr
;
622 case MONO_MARSHAL_CONV_SB_UTF8STR
:
623 case MONO_MARSHAL_CONV_SB_LPSTR
:
624 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
625 case MONO_MARSHAL_CONV_SB_LPTSTR
:
627 return MONO_JIT_ICALL_mono_string_builder_to_utf16
;
629 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
631 case MONO_MARSHAL_CONV_SB_LPWSTR
:
632 return MONO_JIT_ICALL_mono_string_builder_to_utf16
;
633 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
634 return MONO_JIT_ICALL_mono_array_to_savearray
;
635 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
636 return MONO_JIT_ICALL_mono_array_to_lparray
;
637 case MONO_MARSHAL_FREE_LPARRAY
:
638 return MONO_JIT_ICALL_mono_free_lparray
;
639 case MONO_MARSHAL_CONV_DEL_FTN
:
640 return MONO_JIT_ICALL_mono_delegate_to_ftnptr
;
641 case MONO_MARSHAL_CONV_FTN_DEL
:
642 *ind_store_type
= CEE_STIND_REF
;
643 return MONO_JIT_ICALL_mono_ftnptr_to_delegate
;
644 case MONO_MARSHAL_CONV_UTF8STR_SB
:
645 case MONO_MARSHAL_CONV_LPSTR_SB
:
646 *ind_store_type
= CEE_STIND_REF
;
647 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
648 case MONO_MARSHAL_CONV_LPTSTR_SB
:
649 *ind_store_type
= CEE_STIND_REF
;
651 return MONO_JIT_ICALL_mono_string_utf16_to_builder
;
653 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
655 case MONO_MARSHAL_CONV_LPWSTR_SB
:
656 *ind_store_type
= CEE_STIND_REF
;
657 return MONO_JIT_ICALL_mono_string_utf16_to_builder
;
658 case MONO_MARSHAL_FREE_ARRAY
:
659 return MONO_JIT_ICALL_mono_marshal_free_array
;
660 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
661 return MONO_JIT_ICALL_mono_string_to_byvalstr
;
662 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
663 return MONO_JIT_ICALL_mono_string_to_byvalwstr
;
665 g_assert_not_reached ();
668 return MONO_JIT_ICALL_ZeroIsReserved
;
672 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
678 case MONO_MARSHAL_CONV_BOOL_I4
:
679 mono_mb_emit_ldloc (mb
, 1);
680 mono_mb_emit_ldloc (mb
, 0);
681 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
682 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
684 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
685 mono_mb_emit_ldloc (mb
, 1);
686 mono_mb_emit_ldloc (mb
, 0);
687 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
688 mono_mb_emit_byte (mb
, CEE_NEG
);
689 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
691 // In Mono historically LPSTR was treated as a UTF8STR
692 case MONO_MARSHAL_CONV_STR_UTF8STR
:
693 case MONO_MARSHAL_CONV_STR_LPWSTR
:
694 case MONO_MARSHAL_CONV_STR_LPSTR
:
695 case MONO_MARSHAL_CONV_STR_LPTSTR
:
696 case MONO_MARSHAL_CONV_STR_BSTR
:
697 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
698 case MONO_MARSHAL_CONV_STR_TBSTR
: {
701 /* free space if free == true */
702 mono_mb_emit_ldloc (mb
, 2);
703 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
704 mono_mb_emit_ldloc (mb
, 1);
705 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
706 mono_mb_emit_icall (mb
, g_free
); // aka monoeg_g_free
707 mono_mb_patch_short_branch (mb
, pos
);
709 mono_mb_emit_ldloc (mb
, 1);
710 mono_mb_emit_ldloc (mb
, 0);
711 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
712 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
713 mono_mb_emit_byte (mb
, stind_op
);
716 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
717 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
718 case MONO_MARSHAL_CONV_DEL_FTN
:
719 mono_mb_emit_ldloc (mb
, 1);
720 mono_mb_emit_ldloc (mb
, 0);
721 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
722 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
723 mono_mb_emit_byte (mb
, stind_op
);
725 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
726 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
729 mono_mb_emit_ldloc (mb
, 1); /* dst */
730 mono_mb_emit_ldloc (mb
, 0);
731 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
732 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
733 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
736 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
737 MonoClass
*eklass
= NULL
;
740 if (type
->type
== MONO_TYPE_SZARRAY
) {
741 eklass
= type
->data
.klass
;
742 } else if (type
->type
== MONO_TYPE_ARRAY
) {
743 eklass
= type
->data
.array
->eklass
;
744 g_assert(m_class_is_blittable (eklass
));
746 g_assert_not_reached ();
749 if (m_class_is_valuetype (eklass
))
750 esize
= mono_class_native_size (eklass
, NULL
);
752 esize
= TARGET_SIZEOF_VOID_P
;
754 mono_mb_emit_ldloc (mb
, 0);
755 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
756 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
758 if (m_class_is_blittable (eklass
)) {
759 mono_mb_emit_ldloc (mb
, 1);
760 mono_mb_emit_ldloc (mb
, 0);
761 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
762 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
763 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
764 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
765 mono_mb_emit_byte (mb
, CEE_CPBLK
);
767 int array_var
, src_var
, dst_var
, index_var
;
768 guint32 label2
, label3
;
770 MonoType
*int_type
= mono_get_int_type ();
771 MonoType
*object_type
= mono_get_object_type ();
772 array_var
= mono_mb_add_local (mb
, object_type
);
773 src_var
= mono_mb_add_local (mb
, int_type
);
774 dst_var
= mono_mb_add_local (mb
, int_type
);
777 mono_mb_emit_ldloc (mb
, 0);
778 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
779 mono_mb_emit_stloc (mb
, array_var
);
781 /* save the old src pointer */
782 mono_mb_emit_ldloc (mb
, 0);
783 mono_mb_emit_stloc (mb
, src_var
);
784 /* save the old dst pointer */
785 mono_mb_emit_ldloc (mb
, 1);
786 mono_mb_emit_stloc (mb
, dst_var
);
788 /* Emit marshalling loop */
789 index_var
= mono_mb_add_local (mb
, int_type
);
790 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
791 mono_mb_emit_stloc (mb
, index_var
);
794 label2
= mono_mb_get_label (mb
);
795 mono_mb_emit_ldloc (mb
, index_var
);
796 mono_mb_emit_ldloc (mb
, array_var
);
797 mono_mb_emit_byte (mb
, CEE_LDLEN
);
798 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
801 mono_mb_emit_ldloc (mb
, array_var
);
802 mono_mb_emit_ldloc (mb
, index_var
);
803 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
804 mono_mb_emit_stloc (mb
, 0);
806 /* dst is already set */
808 /* Do the conversion */
809 emit_struct_conv (mb
, eklass
, FALSE
);
812 mono_mb_emit_add_to_local (mb
, index_var
, 1);
814 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
816 mono_mb_patch_branch (mb
, label3
);
818 /* restore the old src pointer */
819 mono_mb_emit_ldloc (mb
, src_var
);
820 mono_mb_emit_stloc (mb
, 0);
821 /* restore the old dst pointer */
822 mono_mb_emit_ldloc (mb
, dst_var
);
823 mono_mb_emit_stloc (mb
, 1);
826 mono_mb_patch_branch (mb
, pos
);
829 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
830 mono_mb_emit_ldloc (mb
, 0);
831 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
832 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
834 mono_mb_emit_ldloc (mb
, 1);
835 mono_mb_emit_ldloc (mb
, 0);
836 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
837 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
838 mono_mb_emit_icall (mb
, mono_array_to_byte_byvalarray
);
839 mono_mb_patch_short_branch (mb
, pos
);
842 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
843 int src_var
, dst_var
;
845 MonoType
*int_type
= mono_get_int_type ();
846 src_var
= mono_mb_add_local (mb
, int_type
);
847 dst_var
= mono_mb_add_local (mb
, int_type
);
849 mono_mb_emit_ldloc (mb
, 0);
850 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
851 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
853 /* save the old src pointer */
854 mono_mb_emit_ldloc (mb
, 0);
855 mono_mb_emit_stloc (mb
, src_var
);
856 /* save the old dst pointer */
857 mono_mb_emit_ldloc (mb
, 1);
858 mono_mb_emit_stloc (mb
, dst_var
);
860 /* src = pointer to object data */
861 mono_mb_emit_ldloc (mb
, 0);
862 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
863 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
864 mono_mb_emit_byte (mb
, CEE_ADD
);
865 mono_mb_emit_stloc (mb
, 0);
867 emit_struct_conv (mb
, mono_class_from_mono_type_internal (type
), FALSE
);
869 /* restore the old src pointer */
870 mono_mb_emit_ldloc (mb
, src_var
);
871 mono_mb_emit_stloc (mb
, 0);
872 /* restore the old dst pointer */
873 mono_mb_emit_ldloc (mb
, dst_var
);
874 mono_mb_emit_stloc (mb
, 1);
876 mono_mb_patch_branch (mb
, pos
);
881 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
882 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
883 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
884 mono_cominterop_emit_object_to_ptr_conv (mb
, type
, conv
, mspec
);
886 #endif /* DISABLE_COM */
888 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
891 mono_mb_emit_ldloc (mb
, 0);
892 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
893 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
894 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
895 mono_mb_patch_branch (mb
, pos
);
897 /* Pull the handle field from SafeHandle */
898 mono_mb_emit_ldloc (mb
, 1);
899 mono_mb_emit_ldloc (mb
, 0);
900 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
901 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
902 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
903 mono_mb_emit_byte (mb
, CEE_STIND_I
);
907 case MONO_MARSHAL_CONV_HANDLEREF
: {
908 mono_mb_emit_ldloc (mb
, 1);
909 mono_mb_emit_ldloc (mb
, 0);
910 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
911 mono_mb_emit_byte (mb
, CEE_ADD
);
912 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
913 mono_mb_emit_byte (mb
, CEE_STIND_I
);
918 g_error ("marshalling conversion %d not implemented", conv
);
925 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
,
926 int offset_of_first_child_field
, MonoMarshalNative string_encoding
)
928 MonoMarshalType
*info
;
931 if (m_class_get_parent (klass
))
932 emit_struct_conv_full (mb
, m_class_get_parent (klass
), to_object
, offset_of_first_nonstatic_field (klass
), string_encoding
);
934 info
= mono_marshal_load_type_info (klass
);
936 if (info
->native_size
== 0)
939 if (m_class_is_blittable (klass
)) {
940 int usize
= mono_class_value_size (klass
, NULL
);
941 g_assert (usize
== info
->native_size
);
942 mono_mb_emit_ldloc (mb
, 1);
943 mono_mb_emit_ldloc (mb
, 0);
944 mono_mb_emit_icon (mb
, usize
);
945 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
946 mono_mb_emit_byte (mb
, CEE_CPBLK
);
949 mono_mb_emit_add_to_local (mb
, 0, usize
);
950 mono_mb_emit_add_to_local (mb
, 1, offset_of_first_child_field
);
952 mono_mb_emit_add_to_local (mb
, 0, offset_of_first_child_field
);
953 mono_mb_emit_add_to_local (mb
, 1, usize
);
958 if (klass
!= mono_class_try_get_safehandle_class ()) {
959 if (mono_class_is_auto_layout (klass
)) {
960 char *msg
= g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
961 mono_type_full_name (m_class_get_byval_arg (klass
)));
962 mono_mb_emit_exception_marshal_directive (mb
, msg
);
967 for (i
= 0; i
< info
->num_fields
; i
++) {
968 MonoMarshalNative ntype
;
969 MonoMarshalConv conv
;
970 MonoType
*ftype
= info
->fields
[i
].field
->type
;
973 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
975 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
978 ntype
= (MonoMarshalNative
)mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, m_class_is_unicode (klass
), &conv
);
981 msize
= m_class_get_instance_size (klass
) - info
->fields
[i
].field
->offset
;
982 usize
= info
->native_size
- info
->fields
[i
].offset
;
984 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
985 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
988 if (klass
!= mono_class_try_get_safehandle_class ()){
990 * FIXME: Should really check for usize==0 and msize>0, but we apply
991 * the layout to the managed structure as well.
994 if (mono_class_is_explicit_layout (klass
) && (usize
== 0)) {
995 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
996 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
997 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
998 "reference field at the same offset as another field.",
999 mono_type_full_name (m_class_get_byval_arg (klass
)));
1004 case MONO_MARSHAL_CONV_NONE
: {
1007 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
1008 g_assert (!ftype
->byref
);
1009 if (ftype
->type
== MONO_TYPE_I
|| ftype
->type
== MONO_TYPE_U
) {
1010 mono_mb_emit_ldloc (mb
, 1);
1011 mono_mb_emit_ldloc (mb
, 0);
1012 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1013 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1024 case MONO_TYPE_BOOLEAN
:
1027 case MONO_TYPE_CHAR
:
1033 mono_mb_emit_ldloc (mb
, 1);
1034 mono_mb_emit_ldloc (mb
, 0);
1035 if (t
== MONO_TYPE_CHAR
&& ntype
== MONO_NATIVE_U1
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
1037 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1038 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
1040 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
1041 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1044 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
1045 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
1048 case MONO_TYPE_GENERICINST
:
1049 if (!mono_type_generic_inst_is_valuetype (ftype
)) {
1050 char *msg
= g_strdup_printf ("Generic type %s cannot be marshaled as field in a struct.",
1051 mono_type_full_name (ftype
));
1052 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1056 case MONO_TYPE_VALUETYPE
: {
1057 int src_var
, dst_var
;
1061 if (t
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (ftype
->data
.klass
)) {
1062 ftype
= mono_class_enum_basetype_internal (ftype
->data
.klass
);
1066 MonoType
*int_type
= mono_get_int_type ();
1067 src_var
= mono_mb_add_local (mb
, int_type
);
1068 dst_var
= mono_mb_add_local (mb
, int_type
);
1070 /* save the old src pointer */
1071 mono_mb_emit_ldloc (mb
, 0);
1072 mono_mb_emit_stloc (mb
, src_var
);
1073 /* save the old dst pointer */
1074 mono_mb_emit_ldloc (mb
, 1);
1075 mono_mb_emit_stloc (mb
, dst_var
);
1077 if (get_fixed_buffer_attr (info
->fields
[i
].field
, &etype
, &len
)) {
1078 emit_fixed_buf_conv (mb
, ftype
, etype
, len
, to_object
, &usize
);
1080 emit_struct_conv (mb
, mono_class_from_mono_type_internal (ftype
), to_object
);
1083 /* restore the old src pointer */
1084 mono_mb_emit_ldloc (mb
, src_var
);
1085 mono_mb_emit_stloc (mb
, 0);
1086 /* restore the old dst pointer */
1087 mono_mb_emit_ldloc (mb
, dst_var
);
1088 mono_mb_emit_stloc (mb
, 1);
1091 case MONO_TYPE_OBJECT
: {
1094 static MonoMethod
*variant_clear
= NULL
;
1095 static MonoMethod
*get_object_for_native_variant
= NULL
;
1098 variant_clear
= get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
1099 if (!get_object_for_native_variant
)
1100 get_object_for_native_variant
= get_method_nofail (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0);
1101 mono_mb_emit_ldloc (mb
, 1);
1102 mono_mb_emit_ldloc (mb
, 0);
1103 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
1104 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1106 mono_mb_emit_ldloc (mb
, 0);
1107 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
1110 static MonoMethod
*get_native_variant_for_object
= NULL
;
1112 if (!get_native_variant_for_object
)
1113 get_native_variant_for_object
= get_method_nofail (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0);
1115 mono_mb_emit_ldloc (mb
, 0);
1116 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
1117 mono_mb_emit_ldloc (mb
, 1);
1118 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
1121 char *msg
= g_strdup_printf ("COM support was disabled at compilation time.");
1122 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1128 g_warning ("marshaling type %02x not implemented", ftype
->type
);
1129 g_assert_not_reached ();
1134 int src_var
, dst_var
;
1136 MonoType
*int_type
= mono_get_int_type ();
1137 src_var
= mono_mb_add_local (mb
, int_type
);
1138 dst_var
= mono_mb_add_local (mb
, int_type
);
1140 /* save the old src pointer */
1141 mono_mb_emit_ldloc (mb
, 0);
1142 mono_mb_emit_stloc (mb
, src_var
);
1143 /* save the old dst pointer */
1144 mono_mb_emit_ldloc (mb
, 1);
1145 mono_mb_emit_stloc (mb
, dst_var
);
1148 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1150 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1152 /* restore the old src pointer */
1153 mono_mb_emit_ldloc (mb
, src_var
);
1154 mono_mb_emit_stloc (mb
, 0);
1155 /* restore the old dst pointer */
1156 mono_mb_emit_ldloc (mb
, dst_var
);
1157 mono_mb_emit_stloc (mb
, 1);
1162 mono_mb_emit_add_to_local (mb
, 0, usize
);
1163 mono_mb_emit_add_to_local (mb
, 1, msize
);
1165 mono_mb_emit_add_to_local (mb
, 0, msize
);
1166 mono_mb_emit_add_to_local (mb
, 1, usize
);
1172 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
1174 emit_struct_conv_full (mb
, klass
, to_object
, 0, (MonoMarshalNative
)-1);
1178 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
1180 /* Call DestroyStructure */
1181 /* FIXME: Only do this if needed */
1182 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1183 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1184 mono_mb_emit_ldloc (mb
, struct_var
);
1185 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
1189 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, MonoJitICallId checkpoint_icall_id
)
1191 int pos_noabort
, pos_noex
;
1193 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1194 mono_mb_emit_byte (mb
, CEE_MONO_LDPTR_INT_REQ_FLAG
);
1195 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
1196 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1198 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1199 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
1201 mono_mb_emit_icall_id (mb
, checkpoint_icall_id
);
1202 /* Throw the exception returned by the checkpoint function, if any */
1203 mono_mb_emit_byte (mb
, CEE_DUP
);
1204 pos_noex
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1206 mono_mb_emit_byte (mb
, CEE_DUP
);
1207 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoException
, caught_in_unmanaged
));
1208 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1209 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
1211 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1212 mono_mb_emit_byte (mb
, CEE_MONO_RETHROW
);
1214 mono_mb_patch_branch (mb
, pos_noex
);
1215 mono_mb_emit_byte (mb
, CEE_POP
);
1217 mono_mb_patch_branch (mb
, pos_noabort
);
1221 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1223 // FIXME Put a boolean in MonoMethodBuilder instead.
1224 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
1227 emit_thread_interrupt_checkpoint_call (mb
, MONO_JIT_ICALL_mono_thread_interruption_checkpoint
);
1231 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1233 emit_thread_interrupt_checkpoint_call (mb
, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise
);
1237 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1239 emit_thread_interrupt_checkpoint (mb
);
1243 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1245 emit_thread_force_interrupt_checkpoint (mb
);
1249 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
1251 int i
, params_var
, tmp_var
;
1253 MonoType
*int_type
= mono_get_int_type ();
1254 /* allocate local (pointer) *params[] */
1255 params_var
= mono_mb_add_local (mb
, int_type
);
1256 /* allocate local (pointer) tmp */
1257 tmp_var
= mono_mb_add_local (mb
, int_type
);
1259 /* alloate space on stack to store an array of pointers to the arguments */
1260 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* (sig
->param_count
+ 1));
1261 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1262 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1263 mono_mb_emit_stloc (mb
, params_var
);
1266 mono_mb_emit_ldloc (mb
, params_var
);
1267 mono_mb_emit_stloc (mb
, tmp_var
);
1269 if (save_this
&& sig
->hasthis
) {
1270 mono_mb_emit_ldloc (mb
, tmp_var
);
1271 mono_mb_emit_ldarg_addr (mb
, 0);
1272 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1273 /* tmp = tmp + sizeof (gpointer) */
1274 if (sig
->param_count
)
1275 mono_mb_emit_add_to_local (mb
, tmp_var
, TARGET_SIZEOF_VOID_P
);
1279 for (i
= 0; i
< sig
->param_count
; i
++) {
1280 mono_mb_emit_ldloc (mb
, tmp_var
);
1281 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
1282 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1283 /* tmp = tmp + sizeof (gpointer) */
1284 if (i
< (sig
->param_count
- 1))
1285 mono_mb_emit_add_to_local (mb
, tmp_var
, TARGET_SIZEOF_VOID_P
);
1293 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
1295 MonoType
*t
= mono_type_get_underlying_type (return_type
);
1296 MonoType
*int_type
= mono_get_int_type ();
1298 if (return_type
->byref
)
1299 return_type
= int_type
;
1302 case MONO_TYPE_VOID
:
1303 g_assert_not_reached ();
1306 case MONO_TYPE_STRING
:
1307 case MONO_TYPE_CLASS
:
1308 case MONO_TYPE_OBJECT
:
1309 case MONO_TYPE_ARRAY
:
1310 case MONO_TYPE_SZARRAY
:
1314 case MONO_TYPE_BOOLEAN
:
1317 case MONO_TYPE_CHAR
:
1327 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type_internal (return_type
));
1328 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
1330 case MONO_TYPE_GENERICINST
:
1331 if (!mono_type_generic_inst_is_valuetype (t
))
1334 case MONO_TYPE_VALUETYPE
: {
1335 MonoClass
*klass
= mono_class_from_mono_type_internal (return_type
);
1336 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
1337 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
1341 case MONO_TYPE_MVAR
: {
1342 MonoClass
*klass
= mono_class_from_mono_type_internal (return_type
);
1343 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, klass
);
1347 g_warning ("type 0x%x not handled", return_type
->type
);
1348 g_assert_not_reached ();
1351 mono_mb_emit_byte (mb
, CEE_RET
);
1357 * Emit the call to the wrapper method from a runtime invoke wrapper.
1360 emit_invoke_call (MonoMethodBuilder
*mb
, MonoMethod
*method
,
1361 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
1363 gboolean virtual_
, gboolean need_direct_wrapper
)
1365 static MonoString
*string_dummy
= NULL
;
1367 int *tmp_nullable_locals
;
1368 gboolean void_ret
= FALSE
;
1369 gboolean string_ctor
= method
&& method
->string_ctor
;
1371 /* to make it work with our special string constructors */
1372 if (!string_dummy
) {
1375 // FIXME Allow for static construction of MonoString.
1377 SETUP_ICALL_FUNCTION
;
1380 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy
, MONO_ROOT_SOURCE_MARSHAL
, NULL
, "Marshal Dummy String");
1382 MonoStringHandle string_dummy_handle
= mono_string_new_utf8_len (mono_get_root_domain (), "dummy", 5, error
);
1383 string_dummy
= MONO_HANDLE_RAW (string_dummy_handle
);
1384 mono_error_assert_ok (error
);
1390 g_assert (sig
->hasthis
);
1391 g_assert (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
);
1396 if (mono_gc_is_moving ()) {
1397 mono_mb_emit_ptr (mb
, &string_dummy
);
1398 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1400 mono_mb_emit_ptr (mb
, string_dummy
);
1403 mono_mb_emit_ldarg (mb
, 0);
1407 tmp_nullable_locals
= g_new0 (int, sig
->param_count
);
1409 for (i
= 0; i
< sig
->param_count
; i
++) {
1410 MonoType
*t
= sig
->params
[i
];
1413 mono_mb_emit_ldarg (mb
, 1);
1415 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1416 mono_mb_emit_byte (mb
, CEE_ADD
);
1420 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1421 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
1422 * So to make this work we unbox it to a local variablee and push a reference to that.
1424 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
1425 tmp_nullable_locals
[i
] = mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_from_mono_type_internal (t
)));
1427 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type_internal (t
));
1428 mono_mb_emit_stloc (mb
, tmp_nullable_locals
[i
]);
1429 mono_mb_emit_ldloc_addr (mb
, tmp_nullable_locals
[i
]);
1434 type
= sig
->params
[i
]->type
;
1438 case MONO_TYPE_BOOLEAN
:
1442 case MONO_TYPE_CHAR
:
1451 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1452 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1454 case MONO_TYPE_STRING
:
1455 case MONO_TYPE_CLASS
:
1456 case MONO_TYPE_ARRAY
:
1458 case MONO_TYPE_SZARRAY
:
1459 case MONO_TYPE_OBJECT
:
1460 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1462 case MONO_TYPE_GENERICINST
:
1463 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
1464 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1468 t
= m_class_get_byval_arg (t
->data
.generic_class
->container_class
);
1471 case MONO_TYPE_VALUETYPE
:
1472 if (type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (t
->data
.klass
)) {
1473 type
= mono_class_enum_basetype_internal (t
->data
.klass
)->type
;
1476 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1477 if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig
->params
[i
]))) {
1478 /* Need to convert a boxed vtype to an mp to a Nullable struct */
1479 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1480 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1482 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1486 g_assert_not_reached ();
1491 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
1492 } else if (need_direct_wrapper
) {
1493 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1495 mono_mb_emit_ldarg (mb
, 3);
1496 mono_mb_emit_calli (mb
, callsig
);
1499 if (sig
->ret
->byref
) {
1500 /* perform indirect load and return by value */
1501 #ifdef ENABLE_NETCORE
1503 mono_mb_emit_byte (mb
, CEE_DUP
);
1504 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1505 mono_mb_emit_exception_full (mb
, "Mono", "NullByRefReturnException", NULL
);
1506 mono_mb_patch_branch (mb
, pos
);
1510 MonoType
* ret_byval
= m_class_get_byval_arg (mono_class_from_mono_type_internal (sig
->ret
));
1511 g_assert (!ret_byval
->byref
);
1512 // TODO: Handle null references
1513 ldind_op
= mono_type_to_ldind (ret_byval
);
1514 /* taken from similar code in mini-generic-sharing.c
1515 * we need to use mono_mb_emit_op to add method data when loading
1516 * a structure since method-to-ir needs this data for wrapper methods */
1517 if (ldind_op
== CEE_LDOBJ
)
1518 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (ret_byval
));
1520 mono_mb_emit_byte (mb
, ldind_op
);
1523 switch (sig
->ret
->type
) {
1524 case MONO_TYPE_VOID
:
1528 case MONO_TYPE_BOOLEAN
:
1529 case MONO_TYPE_CHAR
:
1542 case MONO_TYPE_VALUETYPE
:
1543 case MONO_TYPE_TYPEDBYREF
:
1544 case MONO_TYPE_GENERICINST
:
1545 /* box value types */
1546 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (sig
->ret
));
1548 case MONO_TYPE_STRING
:
1549 case MONO_TYPE_CLASS
:
1550 case MONO_TYPE_ARRAY
:
1551 case MONO_TYPE_SZARRAY
:
1552 case MONO_TYPE_OBJECT
:
1556 /* The result is an IntPtr */
1557 mono_mb_emit_op (mb
, CEE_BOX
, mono_defaults
.int_class
);
1560 g_assert_not_reached ();
1564 mono_mb_emit_stloc (mb
, loc_res
);
1566 /* Convert back nullable-byref arguments */
1567 for (i
= 0; i
< sig
->param_count
; i
++) {
1568 MonoType
*t
= sig
->params
[i
];
1571 * Box the result and put it back into the array, the caller will have
1572 * to obtain it from there.
1574 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
1575 mono_mb_emit_ldarg (mb
, 1);
1576 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1577 mono_mb_emit_byte (mb
, CEE_ADD
);
1579 mono_mb_emit_ldloc (mb
, tmp_nullable_locals
[i
]);
1580 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (t
));
1582 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1586 g_free (tmp_nullable_locals
);
1590 emit_runtime_invoke_body_ilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
1591 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
1592 gboolean virtual_
, gboolean need_direct_wrapper
)
1595 MonoExceptionClause
*clause
;
1596 int loc_res
, loc_exc
;
1598 mono_mb_set_param_names (mb
, param_names
);
1600 /* The wrapper looks like this:
1606 * } catch (Exception e) {
1614 MonoType
*object_type
= mono_get_object_type ();
1615 /* allocate local 0 (object) tmp */
1616 loc_res
= mono_mb_add_local (mb
, object_type
);
1617 /* allocate local 1 (object) exc */
1618 loc_exc
= mono_mb_add_local (mb
, object_type
);
1620 /* *exc is assumed to be initialized to NULL by the caller */
1622 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1623 labels
[0] = mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1628 labels
[1] = mono_mb_get_label (mb
);
1629 emit_thread_force_interrupt_checkpoint (mb
);
1630 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
1632 labels
[2] = mono_mb_emit_branch (mb
, CEE_LEAVE
);
1634 /* Add a try clause around the call */
1635 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
1636 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
1637 clause
->data
.catch_class
= mono_defaults
.exception_class
;
1638 clause
->try_offset
= labels
[1];
1639 clause
->try_len
= mono_mb_get_label (mb
) - labels
[1];
1641 clause
->handler_offset
= mono_mb_get_label (mb
);
1644 mono_mb_emit_stloc (mb
, loc_exc
);
1645 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1646 mono_mb_emit_ldloc (mb
, loc_exc
);
1647 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1649 mono_mb_emit_branch (mb
, CEE_LEAVE
);
1651 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
1653 mono_mb_set_clauses (mb
, 1, clause
);
1655 mono_mb_patch_branch (mb
, labels
[2]);
1656 mono_mb_emit_ldloc (mb
, loc_res
);
1657 mono_mb_emit_byte (mb
, CEE_RET
);
1662 mono_mb_patch_branch (mb
, labels
[0]);
1663 emit_thread_force_interrupt_checkpoint (mb
);
1664 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
1666 mono_mb_emit_ldloc (mb
, 0);
1667 mono_mb_emit_byte (mb
, CEE_RET
);
1671 emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder
*mb
)
1674 MonoExceptionClause
*clause
;
1676 MonoType
*object_type
= mono_get_object_type ();
1677 /* allocate local 0 (object) tmp */
1678 mono_mb_add_local (mb
, object_type
);
1679 /* allocate local 1 (object) exc */
1680 mono_mb_add_local (mb
, object_type
);
1682 /* cond set *exc to null */
1683 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1684 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1685 mono_mb_emit_byte (mb
, 3);
1686 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1687 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1688 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1690 emit_thread_force_interrupt_checkpoint (mb
);
1692 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1693 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1694 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1695 mono_mb_emit_byte (mb
, CEE_MONO_DYN_CALL
);
1697 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
1699 clause
= (MonoExceptionClause
*)mono_image_alloc0 (mono_defaults
.corlib
, sizeof (MonoExceptionClause
));
1700 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
1701 clause
->try_len
= mono_mb_get_label (mb
);
1704 clause
->data
.filter_offset
= mono_mb_get_label (mb
);
1706 mono_mb_emit_byte (mb
, CEE_POP
);
1707 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1708 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1709 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1710 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
1711 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1712 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
1714 clause
->handler_offset
= mono_mb_get_label (mb
);
1717 /* store exception */
1718 mono_mb_emit_stloc (mb
, 1);
1720 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1721 mono_mb_emit_ldloc (mb
, 1);
1722 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1724 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1725 mono_mb_emit_stloc (mb
, 0);
1727 mono_mb_emit_branch (mb
, CEE_LEAVE
);
1729 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
1731 mono_mb_set_clauses (mb
, 1, clause
);
1734 mono_mb_patch_branch (mb
, pos
);
1735 //mono_mb_emit_ldloc (mb, 0);
1736 mono_mb_emit_byte (mb
, CEE_RET
);
1740 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
1742 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
));
1743 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1746 typedef struct EmitGCSafeTransitionBuilder
{
1747 MonoMethodBuilder
*mb
;
1748 gboolean func_param
;
1749 int coop_gc_stack_dummy
;
1752 int coop_cominterop_fnptr
;
1754 } GCSafeTransitionBuilder
;
1757 gc_safe_transition_builder_init (GCSafeTransitionBuilder
*builder
, MonoMethodBuilder
*mb
, gboolean func_param
)
1760 builder
->func_param
= func_param
;
1761 builder
->coop_gc_stack_dummy
= -1;
1762 builder
->coop_gc_var
= -1;
1764 builder
->coop_cominterop_fnptr
= -1;
1766 #if defined (TARGET_WASM)
1774 * adds locals for the gc safe transition to the method builder.
1777 gc_safe_transition_builder_add_locals (GCSafeTransitionBuilder
*builder
)
1779 MonoType
*int_type
= mono_get_int_type();
1780 /* local 4, dummy local used to get a stack address for suspend funcs */
1781 builder
->coop_gc_stack_dummy
= mono_mb_add_local (builder
->mb
, int_type
);
1782 /* local 5, the local to be used when calling the suspend funcs */
1783 builder
->coop_gc_var
= mono_mb_add_local (builder
->mb
, int_type
);
1785 if (!builder
->func_param
&& MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
)) {
1786 builder
->coop_cominterop_fnptr
= mono_mb_add_local (builder
->mb
, int_type
);
1793 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1797 gc_safe_transition_builder_emit_enter (GCSafeTransitionBuilder
*builder
, MonoMethod
*method
, gboolean aot
)
1800 // Perform an extra, early lookup of the function address, so any exceptions
1801 // potentially resulting from the lookup occur before entering blocking mode.
1802 if (!builder
->func_param
&& !MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
) && aot
) {
1803 mono_mb_emit_byte (builder
->mb
, MONO_CUSTOM_PREFIX
);
1804 mono_mb_emit_op (builder
->mb
, CEE_MONO_ICALL_ADDR
, method
);
1805 mono_mb_emit_byte (builder
->mb
, CEE_POP
); // Result not needed yet
1809 if (!builder
->func_param
&& MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
)) {
1810 mono_mb_emit_cominterop_get_function_pointer (builder
->mb
, method
);
1811 mono_mb_emit_stloc (builder
->mb
, builder
->coop_cominterop_fnptr
);
1815 mono_mb_emit_ldloc_addr (builder
->mb
, builder
->coop_gc_stack_dummy
);
1816 mono_mb_emit_icall (builder
->mb
, mono_threads_enter_gc_safe_region_unbalanced
);
1817 mono_mb_emit_stloc (builder
->mb
, builder
->coop_gc_var
);
1822 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1826 gc_safe_transition_builder_emit_exit (GCSafeTransitionBuilder
*builder
)
1828 mono_mb_emit_ldloc (builder
->mb
, builder
->coop_gc_var
);
1829 mono_mb_emit_ldloc_addr (builder
->mb
, builder
->coop_gc_stack_dummy
);
1830 mono_mb_emit_icall (builder
->mb
, mono_threads_exit_gc_safe_region_unbalanced
);
1834 gc_safe_transition_builder_cleanup (GCSafeTransitionBuilder
*builder
)
1837 builder
->coop_gc_stack_dummy
= -1;
1838 builder
->coop_gc_var
= -1;
1840 builder
->coop_cominterop_fnptr
= -1;
1845 * emit_native_wrapper_ilgen:
1846 * \param image the image to use for looking up custom marshallers
1847 * \param sig The signature of the native function
1848 * \param piinfo Marshalling information
1849 * \param mspecs Marshalling information
1850 * \param aot whenever the created method will be compiled by the AOT compiler
1851 * \param method if non-NULL, the pinvoke method to call
1852 * \param check_exceptions Whenever to check for pending exceptions after the native call
1853 * \param func_param the function to call is passed as a boxed IntPtr as the first parameter
1855 * generates IL code for the pinvoke wrapper, the generated code calls \p func .
1858 emit_native_wrapper_ilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
)
1860 EmitMarshalContext m
;
1861 MonoMethodSignature
*csig
;
1863 int i
, argnum
, *tmp_locals
;
1864 int type
, param_shift
= 0;
1865 gboolean need_gc_safe
= FALSE
;
1866 GCSafeTransitionBuilder gc_safe_transition_builder
;
1868 memset (&m
, 0, sizeof (m
));
1873 need_gc_safe
= gc_safe_transition_builder_init (&gc_safe_transition_builder
, mb
, func_param
);
1875 /* we copy the signature, so that we can set pinvoke to 0 */
1877 /* The function address is passed as the first argument */
1878 g_assert (!sig
->hasthis
);
1881 csig
= mono_metadata_signature_dup_full (get_method_image (mb
->method
), sig
);
1889 MonoType
*int_type
= mono_get_int_type ();
1890 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
1891 /* we allocate local for use with emit_struct_conv() */
1892 /* allocate local 0 (pointer) src_ptr */
1893 mono_mb_add_local (mb
, int_type
);
1894 /* allocate local 1 (pointer) dst_ptr */
1895 mono_mb_add_local (mb
, int_type
);
1896 /* allocate local 2 (boolean) delete_old */
1897 mono_mb_add_local (mb
, boolean_type
);
1899 /* delete_old = FALSE */
1900 mono_mb_emit_icon (mb
, 0);
1901 mono_mb_emit_stloc (mb
, 2);
1903 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
1904 /* allocate local 3 to store the return value */
1905 mono_mb_add_local (mb
, sig
->ret
);
1909 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder
);
1913 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1915 * ret = method (...);
1917 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1924 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
1925 m
.vtaddr_var
= mono_mb_add_local (mb
, int_type
);
1927 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
1928 /* Return type custom marshaling */
1930 * Since we can't determine the return type of the unmanaged function,
1931 * we assume it returns a pointer, and pass that pointer to
1932 * MarshalNativeToManaged.
1934 csig
->ret
= int_type
;
1937 /* we first do all conversions */
1938 tmp_locals
= g_newa (int, sig
->param_count
);
1939 m
.orig_conv_args
= g_newa (int, sig
->param_count
+ 1);
1941 for (i
= 0; i
< sig
->param_count
; i
++) {
1942 tmp_locals
[i
] = mono_emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
1945 // In coop mode need to register blocking state during native call
1947 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder
, &piinfo
->method
, aot
);
1949 /* push all arguments */
1952 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1954 for (i
= 0; i
< sig
->param_count
; i
++) {
1955 mono_emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
1958 /* call the native method */
1960 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1961 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_defaults
.int_class
);
1962 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1963 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1964 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1965 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
1967 mono_mb_emit_calli (mb
, csig
);
1968 } else if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
1970 mono_mb_emit_ldloc (mb
, gc_safe_transition_builder
.coop_cominterop_fnptr
);
1971 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1972 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1973 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
1975 mono_mb_emit_cominterop_call_function_pointer (mb
, csig
);
1977 g_assert_not_reached ();
1981 /* Reuse the ICALL_ADDR opcode for pinvokes too */
1982 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1983 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
1984 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1985 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1986 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
1988 mono_mb_emit_calli (mb
, csig
);
1990 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1991 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1992 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
1994 mono_mb_emit_native_call (mb
, csig
, func
);
1998 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1999 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
2000 mono_class_init_internal (klass
);
2001 if (!(mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
))) {
2002 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
2003 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2004 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
2005 mono_mb_emit_stloc (mb
, m
.vtaddr_var
);
2009 /* Unblock before converting the result, since that can involve calls into the runtime */
2011 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder
);
2013 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder
);
2015 /* convert the result */
2016 if (!sig
->ret
->byref
) {
2017 MonoMarshalSpec
*spec
= mspecs
[0];
2018 type
= sig
->ret
->type
;
2020 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
2021 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2025 case MONO_TYPE_VOID
:
2027 case MONO_TYPE_VALUETYPE
:
2028 klass
= sig
->ret
->data
.klass
;
2029 if (m_class_is_enumtype (klass
)) {
2030 type
= mono_class_enum_basetype_internal (sig
->ret
->data
.klass
)->type
;
2033 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2047 case MONO_TYPE_FNPTR
:
2048 case MONO_TYPE_STRING
:
2049 case MONO_TYPE_CLASS
:
2050 case MONO_TYPE_OBJECT
:
2051 case MONO_TYPE_BOOLEAN
:
2052 case MONO_TYPE_ARRAY
:
2053 case MONO_TYPE_SZARRAY
:
2054 case MONO_TYPE_CHAR
:
2056 case MONO_TYPE_GENERICINST
:
2057 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2059 case MONO_TYPE_TYPEDBYREF
:
2061 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
2062 g_assert_not_reached ();
2066 mono_mb_emit_stloc (mb
, 3);
2070 * Need to call this after converting the result since MONO_VTADDR needs
2071 * to be adjacent to the call instruction.
2073 if (check_exceptions
)
2074 emit_thread_interrupt_checkpoint (mb
);
2076 /* we need to convert byref arguments back and free string arrays */
2077 for (i
= 0; i
< sig
->param_count
; i
++) {
2078 MonoType
*t
= sig
->params
[i
];
2079 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
2081 argnum
= i
+ param_shift
;
2083 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
2084 mono_emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
2089 case MONO_TYPE_STRING
:
2090 case MONO_TYPE_VALUETYPE
:
2091 case MONO_TYPE_CLASS
:
2092 case MONO_TYPE_OBJECT
:
2093 case MONO_TYPE_SZARRAY
:
2094 case MONO_TYPE_BOOLEAN
:
2095 mono_emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
2102 if (!MONO_TYPE_IS_VOID(sig
->ret
))
2103 mono_mb_emit_ldloc (mb
, 3);
2105 mono_mb_emit_byte (mb
, CEE_RET
);
2109 * The code directly following this is the cache hit, value positive branch
2111 * This function takes a new method builder with 0 locals and adds two locals
2112 * to create multiple out-branches and the fall through state of having the object
2113 * on the stack after a cache miss
2116 generate_check_cache (int obj_arg_position
, int class_arg_position
, int cache_arg_position
, // In-parameters
2117 int *null_obj
, int *cache_hit_neg
, int *cache_hit_pos
, // Out-parameters
2118 MonoMethodBuilder
*mb
)
2122 MonoType
*int_type
= mono_get_int_type ();
2123 /* allocate local 0 (pointer) obj_vtable */
2124 mono_mb_add_local (mb
, int_type
);
2125 /* allocate local 1 (pointer) cached_vtable */
2126 mono_mb_add_local (mb
, int_type
);
2129 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2130 *null_obj
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2132 /*obj_vtable = obj->vtable;*/
2133 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2134 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2135 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2136 mono_mb_emit_stloc (mb
, 0);
2138 /* cached_vtable = *cache*/
2139 mono_mb_emit_ldarg (mb
, cache_arg_position
);
2140 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2141 mono_mb_emit_stloc (mb
, 1);
2143 mono_mb_emit_ldloc (mb
, 1);
2144 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
2145 mono_mb_emit_i4 (mb
, ~0x1);
2146 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2147 mono_mb_emit_byte (mb
, CEE_AND
);
2148 mono_mb_emit_ldloc (mb
, 0);
2149 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
2150 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
2152 /*return (cached_vtable & 0x1) ? NULL : obj;*/
2153 mono_mb_emit_ldloc (mb
, 1);
2154 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
2155 mono_mb_emit_byte (mb
, CEE_CONV_U
);
2156 mono_mb_emit_byte (mb
, CEE_AND
);
2157 *cache_hit_neg
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
2158 *cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BR
);
2161 mono_mb_patch_branch (mb
, cache_miss_pos
);
2164 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2165 mono_mb_emit_ldarg (mb
, class_arg_position
);
2166 mono_mb_emit_ldarg (mb
, cache_arg_position
);
2167 mono_mb_emit_icall (mb
, mono_marshal_isinst_with_cache
);
2171 emit_castclass_ilgen (MonoMethodBuilder
*mb
)
2173 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
, invalid_cast_pos
;
2174 const int obj_arg_position
= TYPECHECK_OBJECT_ARG_POS
;
2175 const int class_arg_position
= TYPECHECK_CLASS_ARG_POS
;
2176 const int cache_arg_position
= TYPECHECK_CACHE_ARG_POS
;
2178 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
2179 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
2180 invalid_cast_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2183 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
2184 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2185 mono_mb_emit_byte (mb
, CEE_RET
);
2188 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
2189 mono_mb_patch_branch (mb
, invalid_cast_pos
);
2190 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
2193 mono_mb_patch_branch (mb
, return_null_pos
);
2194 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2195 mono_mb_emit_byte (mb
, CEE_RET
);
2199 emit_isinst_ilgen (MonoMethodBuilder
*mb
)
2201 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
;
2202 const int obj_arg_position
= TYPECHECK_OBJECT_ARG_POS
;
2203 const int class_arg_position
= TYPECHECK_CLASS_ARG_POS
;
2204 const int cache_arg_position
= TYPECHECK_CACHE_ARG_POS
;
2206 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
2207 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
2208 // Return the object gotten via the slow path.
2209 mono_mb_emit_byte (mb
, CEE_RET
);
2212 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
2213 mono_mb_patch_branch (mb
, return_null_pos
);
2214 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2215 mono_mb_emit_byte (mb
, CEE_RET
);
2218 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
2219 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2220 mono_mb_emit_byte (mb
, CEE_RET
);
2224 load_array_element_address (MonoMethodBuilder
*mb
)
2226 mono_mb_emit_ldarg (mb
, 0);
2227 mono_mb_emit_ldarg (mb
, 1);
2228 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
2232 load_array_class (MonoMethodBuilder
*mb
, int aklass
)
2234 mono_mb_emit_ldarg (mb
, 0);
2235 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2236 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2237 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
2238 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2239 mono_mb_emit_ldflda (mb
, m_class_offsetof_element_class ());
2240 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2241 mono_mb_emit_stloc (mb
, aklass
);
2245 load_value_class (MonoMethodBuilder
*mb
, int vklass
)
2247 mono_mb_emit_ldarg (mb
, 2);
2248 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2249 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2250 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
2251 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2252 mono_mb_emit_stloc (mb
, vklass
);
2256 emit_marshal_array_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2257 MonoMarshalSpec
*spec
,
2258 int conv_arg
, MonoType
**conv_arg_type
,
2259 MarshalAction action
)
2261 MonoMethodBuilder
*mb
= m
->mb
;
2262 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
2263 gboolean need_convert
, need_free
;
2264 MonoMarshalNative encoding
;
2266 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
2267 MonoType
*int_type
= mono_get_int_type ();
2268 MonoType
*object_type
= mono_get_object_type ();
2270 MonoClass
*eklass
= m_class_get_element_class (klass
);
2273 case MARSHAL_ACTION_CONV_IN
:
2274 *conv_arg_type
= object_type
;
2275 conv_arg
= mono_mb_add_local (mb
, object_type
);
2277 if (m_class_is_blittable (eklass
)) {
2278 mono_mb_emit_ldarg (mb
, argnum
);
2280 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2281 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
, NULL
));
2282 mono_mb_emit_stloc (mb
, conv_arg
);
2284 guint32 label1
, label2
, label3
;
2285 int index_var
, src_var
, dest_ptr
, esize
;
2286 MonoMarshalConv conv
;
2287 gboolean is_string
= FALSE
;
2289 dest_ptr
= mono_mb_add_local (mb
, int_type
);
2291 if (eklass
== mono_defaults
.string_class
) {
2293 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2295 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2297 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
2300 conv
= MONO_MARSHAL_CONV_INVALID
;
2302 if (is_string
&& conv
== MONO_MARSHAL_CONV_INVALID
) {
2303 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
2304 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2308 src_var
= mono_mb_add_local (mb
, object_type
);
2309 mono_mb_emit_ldarg (mb
, argnum
);
2311 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2312 mono_mb_emit_stloc (mb
, src_var
);
2315 mono_mb_emit_ldloc (mb
, src_var
);
2316 mono_mb_emit_stloc (mb
, conv_arg
);
2317 mono_mb_emit_ldloc (mb
, src_var
);
2318 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2321 esize
= TARGET_SIZEOF_VOID_P
;
2322 else if (eklass
== mono_defaults
.char_class
) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
2323 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2325 esize
= mono_class_native_size (eklass
, NULL
);
2327 /* allocate space for the native struct and store the address */
2328 mono_mb_emit_icon (mb
, esize
);
2329 mono_mb_emit_ldloc (mb
, src_var
);
2330 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2332 if (eklass
== mono_defaults
.string_class
) {
2333 /* Make the array bigger for the terminating null */
2334 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
2335 mono_mb_emit_byte (mb
, CEE_ADD
);
2337 mono_mb_emit_byte (mb
, CEE_MUL
);
2338 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2339 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2340 mono_mb_emit_stloc (mb
, conv_arg
);
2342 mono_mb_emit_ldloc (mb
, conv_arg
);
2343 mono_mb_emit_stloc (mb
, dest_ptr
);
2345 /* Emit marshalling loop */
2346 index_var
= mono_mb_add_local (mb
, int_type
);
2347 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2348 mono_mb_emit_stloc (mb
, index_var
);
2349 label2
= mono_mb_get_label (mb
);
2350 mono_mb_emit_ldloc (mb
, index_var
);
2351 mono_mb_emit_ldloc (mb
, src_var
);
2352 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2353 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2355 /* Emit marshalling code */
2359 mono_mb_emit_ldloc (mb
, dest_ptr
);
2360 mono_mb_emit_ldloc (mb
, src_var
);
2361 mono_mb_emit_ldloc (mb
, index_var
);
2362 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2363 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2364 mono_mb_emit_byte (mb
, stind_op
);
2366 /* set the src_ptr */
2367 mono_mb_emit_ldloc (mb
, src_var
);
2368 mono_mb_emit_ldloc (mb
, index_var
);
2369 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2370 mono_mb_emit_stloc (mb
, 0);
2373 mono_mb_emit_ldloc (mb
, dest_ptr
);
2374 mono_mb_emit_stloc (mb
, 1);
2376 /* emit valuetype conversion code */
2377 emit_struct_conv_full (mb
, eklass
, FALSE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
2380 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2381 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
2383 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2385 mono_mb_patch_branch (mb
, label3
);
2387 if (eklass
== mono_defaults
.string_class
) {
2388 /* Null terminate */
2389 mono_mb_emit_ldloc (mb
, dest_ptr
);
2390 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2391 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2394 mono_mb_patch_branch (mb
, label1
);
2399 case MARSHAL_ACTION_CONV_OUT
:
2400 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
2401 need_convert
= ((eklass
== mono_defaults
.char_class
) && (encoding
== MONO_NATIVE_LPWSTR
)) || (eklass
== mono_class_try_get_stringbuilder_class ()) || (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
2402 need_free
= mono_marshal_need_free (m_class_get_byval_arg (eklass
), m
->piinfo
, spec
);
2404 if ((t
->attrs
& PARAM_ATTRIBUTE_OUT
) && spec
&& spec
->native
== MONO_NATIVE_LPARRAY
&& spec
->data
.array_data
.param_num
!= -1) {
2405 int param_num
= spec
->data
.array_data
.param_num
;
2406 MonoType
*param_type
;
2408 param_type
= m
->sig
->params
[param_num
];
2410 if (param_type
->byref
&& param_type
->type
!= MONO_TYPE_I4
) {
2411 char *msg
= g_strdup ("Not implemented.");
2412 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2417 mono_mb_emit_ldarg (mb
, argnum
);
2419 /* Create the managed array */
2420 mono_mb_emit_ldarg (mb
, param_num
);
2421 if (m
->sig
->params
[param_num
]->byref
)
2422 // FIXME: Support other types
2423 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
2424 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
2425 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
2426 /* Store into argument */
2427 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2431 if (need_convert
|| need_free
) {
2432 /* FIXME: Optimize blittable case */
2433 guint32 label1
, label2
, label3
;
2434 int index_var
, src_ptr
, loc
, esize
;
2436 if ((eklass
== mono_class_try_get_stringbuilder_class ()) || (eklass
== mono_defaults
.string_class
))
2437 esize
= TARGET_SIZEOF_VOID_P
;
2438 else if (eklass
== mono_defaults
.char_class
)
2439 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2441 esize
= mono_class_native_size (eklass
, NULL
);
2442 src_ptr
= mono_mb_add_local (mb
, int_type
);
2443 loc
= mono_mb_add_local (mb
, int_type
);
2446 mono_mb_emit_ldarg (mb
, argnum
);
2448 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2449 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2451 mono_mb_emit_ldloc (mb
, conv_arg
);
2452 mono_mb_emit_stloc (mb
, src_ptr
);
2454 /* Emit marshalling loop */
2455 index_var
= mono_mb_add_local (mb
, int_type
);
2456 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2457 mono_mb_emit_stloc (mb
, index_var
);
2458 label2
= mono_mb_get_label (mb
);
2459 mono_mb_emit_ldloc (mb
, index_var
);
2460 mono_mb_emit_ldarg (mb
, argnum
);
2462 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2463 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2464 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2466 /* Emit marshalling code */
2468 if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2469 gboolean need_free2
;
2470 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
2472 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2475 mono_mb_emit_ldarg (mb
, argnum
);
2477 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2478 mono_mb_emit_ldloc (mb
, index_var
);
2479 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2482 mono_mb_emit_ldloc (mb
, src_ptr
);
2483 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2485 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
2489 mono_mb_emit_ldloc (mb
, src_ptr
);
2490 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2492 mono_mb_emit_icall (mb
, mono_marshal_free
);
2495 else if (eklass
== mono_defaults
.string_class
) {
2498 mono_mb_emit_ldloc (mb
, src_ptr
);
2499 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2501 mono_mb_emit_icall (mb
, mono_marshal_free
);
2506 /* set the src_ptr */
2507 mono_mb_emit_ldloc (mb
, src_ptr
);
2508 mono_mb_emit_stloc (mb
, 0);
2511 mono_mb_emit_ldarg (mb
, argnum
);
2513 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2514 mono_mb_emit_ldloc (mb
, index_var
);
2515 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2516 mono_mb_emit_stloc (mb
, 1);
2518 /* emit valuetype conversion code */
2519 emit_struct_conv_full (mb
, eklass
, TRUE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
2523 mono_mb_emit_ldloc (mb
, src_ptr
);
2524 mono_mb_emit_stloc (mb
, loc
);
2526 emit_struct_free (mb
, eklass
, loc
);
2530 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2531 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
2533 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2535 mono_mb_patch_branch (mb
, label1
);
2536 mono_mb_patch_branch (mb
, label3
);
2539 if (m_class_is_blittable (eklass
)) {
2540 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
2542 mono_mb_emit_ldarg (mb
, argnum
);
2544 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2545 mono_mb_emit_ldloc (mb
, conv_arg
);
2546 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY
, NULL
));
2551 case MARSHAL_ACTION_PUSH
:
2553 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
2555 mono_mb_emit_ldloc (mb
, conv_arg
);
2558 case MARSHAL_ACTION_CONV_RESULT
:
2559 /* fixme: we need conversions here */
2560 mono_mb_emit_stloc (mb
, 3);
2563 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
2564 guint32 label1
, label2
, label3
;
2565 int index_var
, src_ptr
, esize
, param_num
, num_elem
;
2566 MonoMarshalConv conv
;
2567 gboolean is_string
= FALSE
;
2569 conv_arg
= mono_mb_add_local (mb
, object_type
);
2570 *conv_arg_type
= int_type
;
2573 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
2574 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2578 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
2579 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2583 switch (spec
->native
) {
2584 case MONO_NATIVE_LPARRAY
:
2586 case MONO_NATIVE_SAFEARRAY
:
2588 if (spec
->data
.safearray_data
.elem_type
!= MONO_VARIANT_VARIANT
) {
2589 char *msg
= g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented.");
2590 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2593 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
2596 char *msg
= g_strdup ("Unsupported array type marshalling to managed code.");
2597 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2602 /* FIXME: t is from the method which is wrapped, not the delegate type */
2603 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
2605 param_num
= spec
->data
.array_data
.param_num
;
2606 num_elem
= spec
->data
.array_data
.num_elem
;
2607 if (spec
->data
.array_data
.elem_mult
== 0)
2608 /* param_num is not specified */
2611 if (param_num
== -1) {
2612 if (num_elem
<= 0) {
2613 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
2614 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2619 /* FIXME: Optimize blittable case */
2621 if (eklass
== mono_defaults
.string_class
) {
2623 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
2625 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2627 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
2630 conv
= MONO_MARSHAL_CONV_INVALID
;
2632 mono_marshal_load_type_info (eklass
);
2635 esize
= TARGET_SIZEOF_VOID_P
;
2637 esize
= mono_class_native_size (eklass
, NULL
);
2638 src_ptr
= mono_mb_add_local (mb
, int_type
);
2640 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2641 mono_mb_emit_stloc (mb
, conv_arg
);
2643 /* Check param index */
2644 if (param_num
!= -1) {
2645 if (param_num
>= m
->sig
->param_count
) {
2646 char *msg
= g_strdup ("Array size control parameter index is out of range.");
2647 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2650 switch (m
->sig
->params
[param_num
]->type
) {
2663 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
2664 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2671 mono_mb_emit_ldarg (mb
, argnum
);
2672 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2674 mono_mb_emit_ldarg (mb
, argnum
);
2675 mono_mb_emit_stloc (mb
, src_ptr
);
2677 /* Create managed array */
2679 * The LPArray marshalling spec says that sometimes param_num starts
2680 * from 1, sometimes it starts from 0. But MS seems to allways start
2684 if (param_num
== -1) {
2685 mono_mb_emit_icon (mb
, num_elem
);
2687 mono_mb_emit_ldarg (mb
, param_num
);
2689 mono_mb_emit_icon (mb
, num_elem
);
2690 mono_mb_emit_byte (mb
, CEE_ADD
);
2692 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
2695 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
2696 mono_mb_emit_stloc (mb
, conv_arg
);
2698 if (m_class_is_blittable (eklass
)) {
2699 mono_mb_emit_ldloc (mb
, conv_arg
);
2700 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2701 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
2702 mono_mb_emit_byte (mb
, CEE_ADD
);
2703 mono_mb_emit_ldarg (mb
, argnum
);
2704 mono_mb_emit_ldloc (mb
, conv_arg
);
2705 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2706 mono_mb_emit_icon (mb
, esize
);
2707 mono_mb_emit_byte (mb
, CEE_MUL
);
2708 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2709 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2710 mono_mb_patch_branch (mb
, label1
);
2714 /* Emit marshalling loop */
2715 index_var
= mono_mb_add_local (mb
, int_type
);
2716 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2717 mono_mb_emit_stloc (mb
, index_var
);
2718 label2
= mono_mb_get_label (mb
);
2719 mono_mb_emit_ldloc (mb
, index_var
);
2720 mono_mb_emit_ldloc (mb
, conv_arg
);
2721 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2722 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2724 /* Emit marshalling code */
2726 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2728 mono_mb_emit_ldloc (mb
, conv_arg
);
2729 mono_mb_emit_ldloc (mb
, index_var
);
2731 mono_mb_emit_ldloc (mb
, src_ptr
);
2732 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2734 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
2735 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
2738 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2739 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2743 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2744 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
2746 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2748 mono_mb_patch_branch (mb
, label1
);
2749 mono_mb_patch_branch (mb
, label3
);
2753 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
2754 guint32 label1
, label2
, label3
;
2755 int index_var
, dest_ptr
, esize
, param_num
, num_elem
;
2756 MonoMarshalConv conv
;
2757 gboolean is_string
= FALSE
;
2760 /* Already handled in CONV_IN */
2763 /* These are already checked in CONV_IN */
2764 g_assert (!t
->byref
);
2765 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
2766 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
2768 param_num
= spec
->data
.array_data
.param_num
;
2769 num_elem
= spec
->data
.array_data
.num_elem
;
2771 if (spec
->data
.array_data
.elem_mult
== 0)
2772 /* param_num is not specified */
2775 if (param_num
== -1) {
2776 if (num_elem
<= 0) {
2777 g_assert_not_reached ();
2781 /* FIXME: Optimize blittable case */
2783 if (eklass
== mono_defaults
.string_class
) {
2785 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2787 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2789 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
2792 conv
= MONO_MARSHAL_CONV_INVALID
;
2794 mono_marshal_load_type_info (eklass
);
2797 esize
= TARGET_SIZEOF_VOID_P
;
2799 esize
= mono_class_native_size (eklass
, NULL
);
2801 dest_ptr
= mono_mb_add_local (mb
, int_type
);
2804 mono_mb_emit_ldloc (mb
, conv_arg
);
2805 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2807 mono_mb_emit_ldarg (mb
, argnum
);
2808 mono_mb_emit_stloc (mb
, dest_ptr
);
2810 if (m_class_is_blittable (eklass
)) {
2812 mono_mb_emit_ldarg (mb
, argnum
);
2814 mono_mb_emit_ldloc (mb
, conv_arg
);
2815 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2816 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
2817 mono_mb_emit_byte (mb
, CEE_ADD
);
2819 mono_mb_emit_ldloc (mb
, conv_arg
);
2820 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2821 mono_mb_emit_icon (mb
, esize
);
2822 mono_mb_emit_byte (mb
, CEE_MUL
);
2823 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2824 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2828 /* Emit marshalling loop */
2829 index_var
= mono_mb_add_local (mb
, int_type
);
2830 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2831 mono_mb_emit_stloc (mb
, index_var
);
2832 label2
= mono_mb_get_label (mb
);
2833 mono_mb_emit_ldloc (mb
, index_var
);
2834 mono_mb_emit_ldloc (mb
, conv_arg
);
2835 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2836 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2838 /* Emit marshalling code */
2841 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2844 mono_mb_emit_ldloc (mb
, dest_ptr
);
2847 mono_mb_emit_ldloc (mb
, conv_arg
);
2848 mono_mb_emit_ldloc (mb
, index_var
);
2850 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2852 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2853 mono_mb_emit_byte (mb
, stind_op
);
2856 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2857 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2861 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2862 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
2864 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2866 mono_mb_patch_branch (mb
, label1
);
2867 mono_mb_patch_branch (mb
, label3
);
2871 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
2872 guint32 label1
, label2
, label3
;
2873 int index_var
, src
, dest
, esize
;
2874 MonoMarshalConv conv
= MONO_MARSHAL_CONV_INVALID
;
2875 gboolean is_string
= FALSE
;
2877 g_assert (!t
->byref
);
2879 mono_marshal_load_type_info (eklass
);
2881 if (eklass
== mono_defaults
.string_class
) {
2883 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2886 g_assert_not_reached ();
2890 esize
= TARGET_SIZEOF_VOID_P
;
2891 else if (eklass
== mono_defaults
.char_class
)
2892 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2894 esize
= mono_class_native_size (eklass
, NULL
);
2896 src
= mono_mb_add_local (mb
, object_type
);
2897 dest
= mono_mb_add_local (mb
, int_type
);
2899 mono_mb_emit_stloc (mb
, src
);
2900 mono_mb_emit_ldloc (mb
, src
);
2901 mono_mb_emit_stloc (mb
, 3);
2903 /* Check for null */
2904 mono_mb_emit_ldloc (mb
, src
);
2905 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2907 /* Allocate native array */
2908 mono_mb_emit_icon (mb
, esize
);
2909 mono_mb_emit_ldloc (mb
, src
);
2910 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2912 if (eklass
== mono_defaults
.string_class
) {
2913 /* Make the array bigger for the terminating null */
2914 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
2915 mono_mb_emit_byte (mb
, CEE_ADD
);
2917 mono_mb_emit_byte (mb
, CEE_MUL
);
2918 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
2919 mono_mb_emit_stloc (mb
, dest
);
2920 mono_mb_emit_ldloc (mb
, dest
);
2921 mono_mb_emit_stloc (mb
, 3);
2923 /* Emit marshalling loop */
2924 index_var
= mono_mb_add_local (mb
, int_type
);
2925 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2926 mono_mb_emit_stloc (mb
, index_var
);
2927 label2
= mono_mb_get_label (mb
);
2928 mono_mb_emit_ldloc (mb
, index_var
);
2929 mono_mb_emit_ldloc (mb
, src
);
2930 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2931 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2933 /* Emit marshalling code */
2936 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2939 mono_mb_emit_ldloc (mb
, dest
);
2942 mono_mb_emit_ldloc (mb
, src
);
2943 mono_mb_emit_ldloc (mb
, index_var
);
2945 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2947 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2948 mono_mb_emit_byte (mb
, stind_op
);
2951 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
2952 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2956 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2957 mono_mb_emit_add_to_local (mb
, dest
, esize
);
2959 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2961 mono_mb_patch_branch (mb
, label3
);
2962 mono_mb_patch_branch (mb
, label1
);
2966 g_assert_not_reached ();
2972 emit_marshal_boolean_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2973 MonoMarshalSpec
*spec
,
2974 int conv_arg
, MonoType
**conv_arg_type
,
2975 MarshalAction action
)
2977 MonoMethodBuilder
*mb
= m
->mb
;
2978 MonoType
*int_type
= mono_get_int_type ();
2979 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
2982 case MARSHAL_ACTION_CONV_IN
: {
2983 MonoType
*local_type
;
2985 guint8 ldc_op
= CEE_LDC_I4_1
;
2987 local_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, &ldc_op
);
2989 *conv_arg_type
= int_type
;
2991 *conv_arg_type
= local_type
;
2992 conv_arg
= mono_mb_add_local (mb
, local_type
);
2994 mono_mb_emit_ldarg (mb
, argnum
);
2996 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
2997 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2998 mono_mb_emit_byte (mb
, ldc_op
);
2999 mono_mb_emit_stloc (mb
, conv_arg
);
3000 mono_mb_patch_branch (mb
, label_false
);
3005 case MARSHAL_ACTION_CONV_OUT
:
3007 int label_false
, label_end
;
3011 mono_mb_emit_ldarg (mb
, argnum
);
3012 mono_mb_emit_ldloc (mb
, conv_arg
);
3014 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3015 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3017 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
3018 mono_mb_patch_branch (mb
, label_false
);
3019 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3020 mono_mb_patch_branch (mb
, label_end
);
3022 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
3026 case MARSHAL_ACTION_PUSH
:
3028 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
3030 mono_mb_emit_ldloc (mb
, conv_arg
);
3032 mono_mb_emit_ldarg (mb
, argnum
);
3035 case MARSHAL_ACTION_CONV_RESULT
:
3036 /* maybe we need to make sure that it fits within 8 bits */
3037 mono_mb_emit_stloc (mb
, 3);
3040 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3041 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3042 guint8 ldop
= CEE_LDIND_I4
;
3043 int label_null
, label_false
;
3045 conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, &ldop
);
3046 conv_arg
= mono_mb_add_local (mb
, boolean_type
);
3049 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3051 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3054 mono_mb_emit_ldarg (mb
, argnum
);
3058 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3059 mono_mb_emit_ldarg (mb
, argnum
);
3060 mono_mb_emit_byte (mb
, ldop
);
3064 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3065 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3066 mono_mb_emit_stloc (mb
, conv_arg
);
3067 mono_mb_patch_branch (mb
, label_false
);
3070 mono_mb_patch_branch (mb
, label_null
);
3074 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
3075 guint8 stop
= CEE_STIND_I4
;
3076 guint8 ldc_op
= CEE_LDC_I4_1
;
3077 int label_null
,label_false
, label_end
;
3082 switch (spec
->native
) {
3083 case MONO_NATIVE_I1
:
3084 case MONO_NATIVE_U1
:
3085 stop
= CEE_STIND_I1
;
3087 case MONO_NATIVE_VARIANTBOOL
:
3088 stop
= CEE_STIND_I2
;
3089 ldc_op
= CEE_LDC_I4_M1
;
3097 mono_mb_emit_ldarg (mb
, argnum
);
3098 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3100 mono_mb_emit_ldarg (mb
, argnum
);
3101 mono_mb_emit_ldloc (mb
, conv_arg
);
3103 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3104 mono_mb_emit_byte (mb
, ldc_op
);
3105 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
3107 mono_mb_patch_branch (mb
, label_false
);
3108 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3109 mono_mb_patch_branch (mb
, label_end
);
3111 mono_mb_emit_byte (mb
, stop
);
3112 mono_mb_patch_branch (mb
, label_null
);
3117 g_assert_not_reached ();
3123 emit_marshal_ptr_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3124 MonoMarshalSpec
*spec
, int conv_arg
,
3125 MonoType
**conv_arg_type
, MarshalAction action
)
3127 MonoMethodBuilder
*mb
= m
->mb
;
3130 case MARSHAL_ACTION_CONV_IN
:
3131 /* MS seems to allow this in some cases, ie. bxc #158 */
3133 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) {
3134 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
3135 mono_mb_emit_exception_marshal_directive (m->mb, msg);
3140 case MARSHAL_ACTION_PUSH
:
3141 mono_mb_emit_ldarg (mb
, argnum
);
3144 case MARSHAL_ACTION_CONV_RESULT
:
3145 /* no conversions necessary */
3146 mono_mb_emit_stloc (mb
, 3);
3156 emit_marshal_char_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3157 MonoMarshalSpec
*spec
, int conv_arg
,
3158 MonoType
**conv_arg_type
, MarshalAction action
)
3160 MonoMethodBuilder
*mb
= m
->mb
;
3163 case MARSHAL_ACTION_PUSH
:
3164 /* fixme: dont know how to marshal that. We cant simply
3165 * convert it to a one byte UTF8 character, because an
3166 * unicode character may need more that one byte in UTF8 */
3167 mono_mb_emit_ldarg (mb
, argnum
);
3170 case MARSHAL_ACTION_CONV_RESULT
:
3171 /* fixme: we need conversions here */
3172 mono_mb_emit_stloc (mb
, 3);
3182 emit_marshal_scalar_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3183 MonoMarshalSpec
*spec
, int conv_arg
,
3184 MonoType
**conv_arg_type
, MarshalAction action
)
3186 MonoMethodBuilder
*mb
= m
->mb
;
3189 case MARSHAL_ACTION_PUSH
:
3190 mono_mb_emit_ldarg (mb
, argnum
);
3193 case MARSHAL_ACTION_CONV_RESULT
:
3194 /* no conversions necessary */
3195 mono_mb_emit_stloc (mb
, 3);
3205 emit_virtual_stelemref_ilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
3207 guint32 b1
, b2
, b3
, b4
;
3208 int aklass
, vklass
, vtable
, uiid
;
3209 int array_slot_addr
;
3211 mono_mb_set_param_names (mb
, param_names
);
3212 MonoType
*int_type
= mono_get_int_type ();
3213 MonoType
*int32_type
= m_class_get_byval_arg (mono_defaults
.int32_class
);
3214 MonoType
*object_type_byref
= m_class_get_this_arg (mono_defaults
.object_class
);
3216 /*For now simply call plain old stelemref*/
3218 case STELEMREF_OBJECT
:
3219 /* ldelema (implicit bound check) */
3220 load_array_element_address (mb
);
3222 mono_mb_emit_ldarg (mb
, 2);
3223 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3224 mono_mb_emit_byte (mb
, CEE_RET
);
3227 case STELEMREF_COMPLEX
: {
3230 <ldelema (bound check)>
3233 if (!mono_object_isinst (value, aklass))
3237 *array_slot_addr = value;
3240 throw new ArrayTypeMismatchException ();
3243 aklass
= mono_mb_add_local (mb
, int_type
);
3244 vklass
= mono_mb_add_local (mb
, int_type
);
3245 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3249 /*Use this to debug/record stores that are going thru the slow path*/
3250 MonoMethodSignature
*csig
;
3251 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3252 csig
->ret
= mono_get_void_type ();
3253 csig
->params
[0] = object_type
;
3254 csig
->params
[1] = int_type
; /* this is a natural sized int */
3255 csig
->params
[2] = object_type
;
3256 mono_mb_emit_ldarg (mb
, 0);
3257 mono_mb_emit_ldarg (mb
, 1);
3258 mono_mb_emit_ldarg (mb
, 2);
3259 mono_mb_emit_native_call (mb
, csig
, record_slot_vstore
);
3263 /* ldelema (implicit bound check) */
3264 load_array_element_address (mb
);
3265 mono_mb_emit_stloc (mb
, array_slot_addr
);
3267 /* if (!value) goto do_store */
3268 mono_mb_emit_ldarg (mb
, 2);
3269 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3271 /* aklass = array->vtable->klass->element_class */
3272 load_array_class (mb
, aklass
);
3273 /* vklass = value->vtable->klass */
3274 load_value_class (mb
, vklass
);
3277 mono_mb_emit_ldloc (mb
, vklass
);
3278 mono_mb_emit_ldloc (mb
, aklass
);
3279 b_fast
= mono_mb_emit_branch (mb
, CEE_BEQ
);
3281 /*if (mono_object_isinst (value, aklass)) */
3282 mono_mb_emit_ldarg (mb
, 2);
3283 mono_mb_emit_ldloc (mb
, aklass
);
3284 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
3285 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3288 mono_mb_patch_branch (mb
, b1
);
3289 mono_mb_patch_branch (mb
, b_fast
);
3290 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3291 mono_mb_emit_ldarg (mb
, 2);
3292 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3293 mono_mb_emit_byte (mb
, CEE_RET
);
3296 mono_mb_patch_branch (mb
, b2
);
3298 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3301 case STELEMREF_SEALED_CLASS
:
3303 <ldelema (bound check)>
3307 aklass = array->vtable->m_class_get_element_class (klass);
3308 vklass = value->vtable->klass;
3310 if (vklass != aklass)
3314 *array_slot_addr = value;
3317 throw new ArrayTypeMismatchException ();
3319 aklass
= mono_mb_add_local (mb
, int_type
);
3320 vklass
= mono_mb_add_local (mb
, int_type
);
3321 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3323 /* ldelema (implicit bound check) */
3324 load_array_element_address (mb
);
3325 mono_mb_emit_stloc (mb
, array_slot_addr
);
3327 /* if (!value) goto do_store */
3328 mono_mb_emit_ldarg (mb
, 2);
3329 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3331 /* aklass = array->vtable->klass->element_class */
3332 load_array_class (mb
, aklass
);
3334 /* vklass = value->vtable->klass */
3335 load_value_class (mb
, vklass
);
3337 /*if (vklass != aklass) goto do_exception; */
3338 mono_mb_emit_ldloc (mb
, aklass
);
3339 mono_mb_emit_ldloc (mb
, vklass
);
3340 b2
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3343 mono_mb_patch_branch (mb
, b1
);
3344 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3345 mono_mb_emit_ldarg (mb
, 2);
3346 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3347 mono_mb_emit_byte (mb
, CEE_RET
);
3350 mono_mb_patch_branch (mb
, b2
);
3351 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3354 case STELEMREF_CLASS
: {
3357 <ldelema (bound check)>
3361 aklass = array->vtable->m_class_get_element_class (klass);
3362 vklass = value->vtable->klass;
3364 if (vklass->idepth < aklass->idepth)
3367 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3371 *array_slot_addr = value;
3375 throw new ArrayTypeMismatchException ();
3377 aklass
= mono_mb_add_local (mb
, int_type
);
3378 vklass
= mono_mb_add_local (mb
, int_type
);
3379 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3381 /* ldelema (implicit bound check) */
3382 load_array_element_address (mb
);
3383 mono_mb_emit_stloc (mb
, array_slot_addr
);
3385 /* if (!value) goto do_store */
3386 mono_mb_emit_ldarg (mb
, 2);
3387 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3389 /* aklass = array->vtable->klass->element_class */
3390 load_array_class (mb
, aklass
);
3392 /* vklass = value->vtable->klass */
3393 load_value_class (mb
, vklass
);
3395 /* if (vklass->idepth < aklass->idepth) goto failue */
3396 mono_mb_emit_ldloc (mb
, vklass
);
3397 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3398 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3400 mono_mb_emit_ldloc (mb
, aklass
);
3401 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3402 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3404 b3
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
3406 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3407 mono_mb_emit_ldloc (mb
, vklass
);
3408 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3409 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3411 mono_mb_emit_ldloc (mb
, aklass
);
3412 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3413 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3414 mono_mb_emit_icon (mb
, 1);
3415 mono_mb_emit_byte (mb
, CEE_SUB
);
3416 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3417 mono_mb_emit_byte (mb
, CEE_MUL
);
3418 mono_mb_emit_byte (mb
, CEE_ADD
);
3419 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3421 mono_mb_emit_ldloc (mb
, aklass
);
3422 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3425 mono_mb_patch_branch (mb
, b1
);
3426 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3427 mono_mb_emit_ldarg (mb
, 2);
3428 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3429 mono_mb_emit_byte (mb
, CEE_RET
);
3432 mono_mb_patch_branch (mb
, b3
);
3433 mono_mb_patch_branch (mb
, b4
);
3435 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3439 case STELEMREF_CLASS_SMALL_IDEPTH
:
3442 <ldelema (bound check)>
3446 aklass = array->vtable->m_class_get_element_class (klass);
3447 vklass = value->vtable->klass;
3449 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3453 *array_slot_addr = value;
3457 throw new ArrayTypeMismatchException ();
3459 aklass
= mono_mb_add_local (mb
, int_type
);
3460 vklass
= mono_mb_add_local (mb
, int_type
);
3461 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3463 /* ldelema (implicit bound check) */
3464 load_array_element_address (mb
);
3465 mono_mb_emit_stloc (mb
, array_slot_addr
);
3467 /* if (!value) goto do_store */
3468 mono_mb_emit_ldarg (mb
, 2);
3469 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3471 /* aklass = array->vtable->klass->element_class */
3472 load_array_class (mb
, aklass
);
3474 /* vklass = value->vtable->klass */
3475 load_value_class (mb
, vklass
);
3477 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3478 mono_mb_emit_ldloc (mb
, vklass
);
3479 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3480 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3482 mono_mb_emit_ldloc (mb
, aklass
);
3483 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3484 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3485 mono_mb_emit_icon (mb
, 1);
3486 mono_mb_emit_byte (mb
, CEE_SUB
);
3487 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3488 mono_mb_emit_byte (mb
, CEE_MUL
);
3489 mono_mb_emit_byte (mb
, CEE_ADD
);
3490 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3492 mono_mb_emit_ldloc (mb
, aklass
);
3493 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3496 mono_mb_patch_branch (mb
, b1
);
3497 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3498 mono_mb_emit_ldarg (mb
, 2);
3499 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3500 mono_mb_emit_byte (mb
, CEE_RET
);
3503 mono_mb_patch_branch (mb
, b4
);
3505 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3508 case STELEMREF_INTERFACE
:
3515 klass = array->obj.vtable->klass->element_class;
3517 uiid = klass->interface_id;
3518 if (uiid > vt->max_interface_id)
3520 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
3523 mono_array_setref_internal (array, index, value);
3526 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
3528 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3529 aklass
= mono_mb_add_local (mb
, int_type
);
3530 vtable
= mono_mb_add_local (mb
, int_type
);
3531 uiid
= mono_mb_add_local (mb
, int32_type
);
3533 /* ldelema (implicit bound check) */
3534 load_array_element_address (mb
);
3535 mono_mb_emit_stloc (mb
, array_slot_addr
);
3537 /* if (!value) goto do_store */
3538 mono_mb_emit_ldarg (mb
, 2);
3539 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3541 /* klass = array->vtable->m_class_get_element_class (klass) */
3542 load_array_class (mb
, aklass
);
3544 /* vt = value->vtable */
3545 mono_mb_emit_ldarg (mb
, 2);
3546 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3547 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3548 mono_mb_emit_stloc (mb
, vtable
);
3550 /* uiid = klass->interface_id; */
3551 mono_mb_emit_ldloc (mb
, aklass
);
3552 mono_mb_emit_ldflda (mb
, m_class_offsetof_interface_id ());
3553 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
3554 mono_mb_emit_stloc (mb
, uiid
);
3556 /*if (uiid > vt->max_interface_id)*/
3557 mono_mb_emit_ldloc (mb
, uiid
);
3558 mono_mb_emit_ldloc (mb
, vtable
);
3559 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
3560 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
3561 b2
= mono_mb_emit_branch (mb
, CEE_BGT_UN
);
3563 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
3565 /*vt->interface_bitmap*/
3566 mono_mb_emit_ldloc (mb
, vtable
);
3567 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, interface_bitmap
));
3568 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3571 mono_mb_emit_ldloc (mb
, uiid
);
3572 mono_mb_emit_icon (mb
, 3);
3573 mono_mb_emit_byte (mb
, CEE_SHR_UN
);
3575 /*vt->interface_bitmap [(uiid) >> 3]*/
3576 mono_mb_emit_byte (mb
, CEE_ADD
); /*interface_bitmap is a guint8 array*/
3577 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
3579 /*(1 << ((uiid)&7)))*/
3580 mono_mb_emit_icon (mb
, 1);
3581 mono_mb_emit_ldloc (mb
, uiid
);
3582 mono_mb_emit_icon (mb
, 7);
3583 mono_mb_emit_byte (mb
, CEE_AND
);
3584 mono_mb_emit_byte (mb
, CEE_SHL
);
3586 /*bitwise and the whole thing*/
3587 mono_mb_emit_byte (mb
, CEE_AND
);
3588 b3
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3591 mono_mb_patch_branch (mb
, b1
);
3592 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3593 mono_mb_emit_ldarg (mb
, 2);
3594 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3595 mono_mb_emit_byte (mb
, CEE_RET
);
3598 mono_mb_patch_branch (mb
, b2
);
3599 mono_mb_patch_branch (mb
, b3
);
3600 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3604 mono_mb_emit_ldarg (mb
, 0);
3605 mono_mb_emit_ldarg (mb
, 1);
3606 mono_mb_emit_ldarg (mb
, 2);
3607 mono_mb_emit_managed_call (mb
, mono_marshal_get_stelemref (), NULL
);
3608 mono_mb_emit_byte (mb
, CEE_RET
);
3614 emit_stelemref_ilgen (MonoMethodBuilder
*mb
)
3616 guint32 b1
, b2
, b3
, b4
;
3619 int array_slot_addr
;
3621 MonoType
*int_type
= mono_get_int_type ();
3622 MonoType
*object_type_byref
= m_class_get_this_arg (mono_defaults
.object_class
);
3624 aklass
= mono_mb_add_local (mb
, int_type
);
3625 vklass
= mono_mb_add_local (mb
, int_type
);
3626 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3630 <ldelema (bound check)>
3634 aklass = array->vtable->m_class_get_element_class (klass);
3635 vklass = value->vtable->klass;
3637 if (vklass->idepth < aklass->idepth)
3640 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3644 *array_slot_addr = value;
3648 if (mono_object_isinst (value, aklass))
3651 throw new ArrayTypeMismatchException ();
3654 /* ldelema (implicit bound check) */
3655 mono_mb_emit_ldarg (mb
, 0);
3656 mono_mb_emit_ldarg (mb
, 1);
3657 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
3658 mono_mb_emit_stloc (mb
, array_slot_addr
);
3660 /* if (!value) goto do_store */
3661 mono_mb_emit_ldarg (mb
, 2);
3662 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3664 /* aklass = array->vtable->klass->element_class */
3665 mono_mb_emit_ldarg (mb
, 0);
3666 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3667 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3668 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3669 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3670 mono_mb_emit_ldflda (mb
, m_class_offsetof_element_class ());
3671 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3672 mono_mb_emit_stloc (mb
, aklass
);
3674 /* vklass = value->vtable->klass */
3675 mono_mb_emit_ldarg (mb
, 2);
3676 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3677 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3678 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3679 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3680 mono_mb_emit_stloc (mb
, vklass
);
3682 /* if (vklass->idepth < aklass->idepth) goto failue */
3683 mono_mb_emit_ldloc (mb
, vklass
);
3684 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3685 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3687 mono_mb_emit_ldloc (mb
, aklass
);
3688 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3689 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3691 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
3693 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3694 mono_mb_emit_ldloc (mb
, vklass
);
3695 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3696 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3698 mono_mb_emit_ldloc (mb
, aklass
);
3699 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3700 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3701 mono_mb_emit_icon (mb
, 1);
3702 mono_mb_emit_byte (mb
, CEE_SUB
);
3703 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3704 mono_mb_emit_byte (mb
, CEE_MUL
);
3705 mono_mb_emit_byte (mb
, CEE_ADD
);
3706 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3708 mono_mb_emit_ldloc (mb
, aklass
);
3710 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3712 copy_pos
= mono_mb_get_label (mb
);
3714 mono_mb_patch_branch (mb
, b1
);
3715 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3716 mono_mb_emit_ldarg (mb
, 2);
3717 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3719 mono_mb_emit_byte (mb
, CEE_RET
);
3722 mono_mb_patch_branch (mb
, b2
);
3723 mono_mb_patch_branch (mb
, b3
);
3725 mono_mb_emit_ldarg (mb
, 2);
3726 mono_mb_emit_ldloc (mb
, aklass
);
3727 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
3729 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3730 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
3731 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3733 mono_mb_emit_byte (mb
, CEE_RET
);
3737 mb_emit_byte_ilgen (MonoMethodBuilder
*mb
, guint8 op
)
3739 mono_mb_emit_byte (mb
, op
);
3743 emit_array_address_ilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
3745 int i
, bounds
, ind
, realidx
;
3746 int branch_pos
, *branch_positions
;
3748 MonoType
*int_type
= mono_get_int_type ();
3749 MonoType
*int32_type
= mono_get_int32_type ();
3751 branch_positions
= g_new0 (int, rank
);
3753 bounds
= mono_mb_add_local (mb
, int_type
);
3754 ind
= mono_mb_add_local (mb
, int32_type
);
3755 realidx
= mono_mb_add_local (mb
, int32_type
);
3757 /* bounds = array->bounds; */
3758 mono_mb_emit_ldarg (mb
, 0);
3759 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
3760 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3761 mono_mb_emit_stloc (mb
, bounds
);
3763 /* ind is the overall element index, realidx is the partial index in a single dimension */
3764 /* ind = idx0 - bounds [0].lower_bound */
3765 mono_mb_emit_ldarg (mb
, 1);
3766 mono_mb_emit_ldloc (mb
, bounds
);
3767 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
3768 mono_mb_emit_byte (mb
, CEE_ADD
);
3769 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3770 mono_mb_emit_byte (mb
, CEE_SUB
);
3771 mono_mb_emit_stloc (mb
, ind
);
3772 /* if (ind >= bounds [0].length) goto exeception; */
3773 mono_mb_emit_ldloc (mb
, ind
);
3774 mono_mb_emit_ldloc (mb
, bounds
);
3775 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3776 mono_mb_emit_byte (mb
, CEE_ADD
);
3777 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3778 /* note that we use unsigned comparison */
3779 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
3781 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
3782 * We could also decide to ignore the passed elem_size and get it
3783 * from the array object, to reduce the number of methods we generate:
3784 * the additional cost is 3 memory loads and a non-immediate mul.
3786 for (i
= 1; i
< rank
; ++i
) {
3787 /* realidx = idxi - bounds [i].lower_bound */
3788 mono_mb_emit_ldarg (mb
, 1 + i
);
3789 mono_mb_emit_ldloc (mb
, bounds
);
3790 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
3791 mono_mb_emit_byte (mb
, CEE_ADD
);
3792 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3793 mono_mb_emit_byte (mb
, CEE_SUB
);
3794 mono_mb_emit_stloc (mb
, realidx
);
3795 /* if (realidx >= bounds [i].length) goto exeception; */
3796 mono_mb_emit_ldloc (mb
, realidx
);
3797 mono_mb_emit_ldloc (mb
, bounds
);
3798 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3799 mono_mb_emit_byte (mb
, CEE_ADD
);
3800 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3801 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
3802 /* ind = ind * bounds [i].length + realidx */
3803 mono_mb_emit_ldloc (mb
, ind
);
3804 mono_mb_emit_ldloc (mb
, bounds
);
3805 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3806 mono_mb_emit_byte (mb
, CEE_ADD
);
3807 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3808 mono_mb_emit_byte (mb
, CEE_MUL
);
3809 mono_mb_emit_ldloc (mb
, realidx
);
3810 mono_mb_emit_byte (mb
, CEE_ADD
);
3811 mono_mb_emit_stloc (mb
, ind
);
3814 /* return array->vector + ind * element_size */
3815 mono_mb_emit_ldarg (mb
, 0);
3816 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
3817 mono_mb_emit_ldloc (mb
, ind
);
3819 mono_mb_emit_icon (mb
, elem_size
);
3821 /* Load arr->vtable->klass->sizes.element_class */
3822 mono_mb_emit_ldarg (mb
, 0);
3823 mono_mb_emit_byte (mb
, CEE_CONV_I
);
3824 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3825 mono_mb_emit_byte (mb
, CEE_ADD
);
3826 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3827 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3828 mono_mb_emit_byte (mb
, CEE_ADD
);
3829 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3830 /* sizes is an union, so this reads sizes.element_size */
3831 mono_mb_emit_icon (mb
, m_class_offsetof_sizes ());
3832 mono_mb_emit_byte (mb
, CEE_ADD
);
3833 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3835 mono_mb_emit_byte (mb
, CEE_MUL
);
3836 mono_mb_emit_byte (mb
, CEE_ADD
);
3837 mono_mb_emit_byte (mb
, CEE_RET
);
3839 /* patch the branches to get here and throw */
3840 for (i
= 1; i
< rank
; ++i
) {
3841 mono_mb_patch_branch (mb
, branch_positions
[i
]);
3843 mono_mb_patch_branch (mb
, branch_pos
);
3844 /* throw exception */
3845 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
3847 g_free (branch_positions
);
3851 emit_delegate_begin_invoke_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
3854 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3856 mono_mb_emit_ldarg (mb
, 0);
3857 mono_mb_emit_ldloc (mb
, params_var
);
3858 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
3859 mono_mb_emit_byte (mb
, CEE_RET
);
3863 emit_delegate_end_invoke_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
3866 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3868 mono_mb_emit_ldarg (mb
, 0);
3869 mono_mb_emit_ldloc (mb
, params_var
);
3870 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
3872 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
3873 mono_mb_emit_byte (mb
, CEE_POP
);
3874 mono_mb_emit_byte (mb
, CEE_RET
);
3876 mono_mb_emit_restore_result (mb
, sig
->ret
);
3880 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
)
3882 int local_i
, local_len
, local_delegates
, local_d
, local_target
, local_res
;
3883 int pos0
, pos1
, pos2
;
3887 MonoType
*int32_type
= mono_get_int32_type ();
3888 MonoType
*object_type
= mono_get_object_type ();
3890 void_ret
= sig
->ret
->type
== MONO_TYPE_VOID
&& !method
->string_ctor
;
3892 /* allocate local 0 (object) */
3893 local_i
= mono_mb_add_local (mb
, int32_type
);
3894 local_len
= mono_mb_add_local (mb
, int32_type
);
3895 local_delegates
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_defaults
.array_class
));
3896 local_d
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_defaults
.multicastdelegate_class
));
3897 local_target
= mono_mb_add_local (mb
, object_type
);
3900 local_res
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_from_mono_type_internal (sig
->ret
)));
3902 g_assert (sig
->hasthis
);
3905 * {type: sig->ret} res;
3906 * if (delegates == null) {
3907 * return this.<target> ( args .. );
3909 * int i = 0, len = this.delegates.Length;
3911 * res = this.delegates [i].Invoke ( args .. );
3912 * } while (++i < len);
3917 /* this wrapper can be used in unmanaged-managed transitions */
3918 emit_thread_interrupt_checkpoint (mb
);
3920 /* delegates = this.delegates */
3921 mono_mb_emit_ldarg (mb
, 0);
3922 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoMulticastDelegate
, delegates
));
3923 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3924 mono_mb_emit_stloc (mb
, local_delegates
);
3926 /* if (delegates == null) */
3927 mono_mb_emit_ldloc (mb
, local_delegates
);
3928 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3930 /* return target.<target_method|method_ptr> ( args .. ); */
3932 /* target = d.target; */
3933 mono_mb_emit_ldarg (mb
, 0);
3934 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
3935 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3936 mono_mb_emit_stloc (mb
, local_target
);
3938 /*static methods with bound first arg can have null target and still be bound*/
3939 if (!static_method_with_first_arg_bound
) {
3940 /* if target != null */
3941 mono_mb_emit_ldloc (mb
, local_target
);
3942 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3944 /* then call this->method_ptr nonstatic */
3947 mono_mb_emit_exception_full (mb
, "System", "NotImplementedException", "");
3949 mono_mb_emit_ldloc (mb
, local_target
);
3950 for (i
= 0; i
< sig
->param_count
; ++i
)
3951 mono_mb_emit_ldarg (mb
, i
+ 1);
3952 mono_mb_emit_ldarg (mb
, 0);
3953 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3954 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3955 mono_mb_emit_ldarg (mb
, 0);
3956 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3957 mono_mb_emit_byte (mb
, CEE_MONO_LD_DELEGATE_METHOD_PTR
);
3958 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3959 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, sig
);
3960 mono_mb_emit_byte (mb
, CEE_RET
);
3963 /* else [target == null] call this->method_ptr static */
3964 mono_mb_patch_branch (mb
, pos0
);
3968 if (!closed_over_null
) {
3969 /* if target_method is not really virtual, turn it into a direct call */
3970 if (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || m_class_is_valuetype (target_class
)) {
3971 mono_mb_emit_ldarg (mb
, 1);
3972 for (i
= 1; i
< sig
->param_count
; ++i
)
3973 mono_mb_emit_ldarg (mb
, i
+ 1);
3974 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3976 mono_mb_emit_ldarg (mb
, 1);
3977 mono_mb_emit_op (mb
, CEE_CASTCLASS
, target_class
);
3978 for (i
= 1; i
< sig
->param_count
; ++i
)
3979 mono_mb_emit_ldarg (mb
, i
+ 1);
3980 mono_mb_emit_op (mb
, CEE_CALLVIRT
, target_method
);
3983 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3984 for (i
= 0; i
< sig
->param_count
; ++i
)
3985 mono_mb_emit_ldarg (mb
, i
+ 1);
3986 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3989 if (static_method_with_first_arg_bound
) {
3990 mono_mb_emit_ldloc (mb
, local_target
);
3991 if (!MONO_TYPE_IS_REFERENCE (invoke_sig
->params
[0]))
3992 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type_internal (invoke_sig
->params
[0]));
3994 for (i
= 0; i
< sig
->param_count
; ++i
)
3995 mono_mb_emit_ldarg (mb
, i
+ 1);
3996 mono_mb_emit_ldarg (mb
, 0);
3997 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3998 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3999 mono_mb_emit_ldarg (mb
, 0);
4000 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4001 mono_mb_emit_byte (mb
, CEE_MONO_LD_DELEGATE_METHOD_PTR
);
4002 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4003 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, invoke_sig
);
4006 mono_mb_emit_byte (mb
, CEE_RET
);
4008 /* else [delegates != null] */
4009 mono_mb_patch_branch (mb
, pos2
);
4011 /* len = delegates.Length; */
4012 mono_mb_emit_ldloc (mb
, local_delegates
);
4013 mono_mb_emit_byte (mb
, CEE_LDLEN
);
4014 mono_mb_emit_byte (mb
, CEE_CONV_I4
);
4015 mono_mb_emit_stloc (mb
, local_len
);
4018 mono_mb_emit_icon (mb
, 0);
4019 mono_mb_emit_stloc (mb
, local_i
);
4021 pos1
= mono_mb_get_label (mb
);
4023 /* d = delegates [i]; */
4024 mono_mb_emit_ldloc (mb
, local_delegates
);
4025 mono_mb_emit_ldloc (mb
, local_i
);
4026 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4027 mono_mb_emit_stloc (mb
, local_d
);
4029 /* res = d.Invoke ( args .. ); */
4030 mono_mb_emit_ldloc (mb
, local_d
);
4031 for (i
= 0; i
< sig
->param_count
; i
++)
4032 mono_mb_emit_ldarg (mb
, i
+ 1);
4034 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4037 mono_mb_emit_op (mb
, CEE_CALLVIRT
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
));
4038 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4041 mono_mb_emit_stloc (mb
, local_res
);
4044 mono_mb_emit_add_to_local (mb
, local_i
, 1);
4047 mono_mb_emit_ldloc (mb
, local_i
);
4048 mono_mb_emit_ldloc (mb
, local_len
);
4049 mono_mb_emit_branch_label (mb
, CEE_BLT
, pos1
);
4053 mono_mb_emit_ldloc (mb
, local_res
);
4054 mono_mb_emit_byte (mb
, CEE_RET
);
4058 mb_skip_visibility_ilgen (MonoMethodBuilder
*mb
)
4060 mb
->skip_visibility
= 1;
4064 mb_set_dynamic_ilgen (MonoMethodBuilder
*mb
)
4070 emit_synchronized_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4072 int i
, pos
, pos2
, this_local
, taken_local
, ret_local
= 0;
4073 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4074 MonoExceptionClause
*clause
;
4077 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4078 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
4080 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4081 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4082 mono_class_set_type_load_failure (method
->klass
, "");
4083 /* This will throw the type load exception when the wrapper is compiled */
4084 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4085 mono_mb_emit_op (mb
, CEE_ISINST
, method
->klass
);
4086 mono_mb_emit_byte (mb
, CEE_POP
);
4088 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4089 mono_mb_emit_ldloc (mb
, ret_local
);
4090 mono_mb_emit_byte (mb
, CEE_RET
);
4095 MonoType
*object_type
= mono_get_object_type ();
4096 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
4098 this_local
= mono_mb_add_local (mb
, object_type
);
4099 taken_local
= mono_mb_add_local (mb
, boolean_type
);
4101 clause
= (MonoExceptionClause
*)mono_image_alloc0 (get_method_image (method
), sizeof (MonoExceptionClause
));
4102 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
4104 /* Push this or the type object */
4105 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
4106 /* We have special handling for this in the JIT */
4107 int index
= mono_mb_add_data (mb
, method
->klass
);
4108 mono_mb_add_data (mb
, mono_defaults
.typehandle_class
);
4109 mono_mb_emit_byte (mb
, CEE_LDTOKEN
);
4110 mono_mb_emit_i4 (mb
, index
);
4112 mono_mb_emit_managed_call (mb
, gettypefromhandle_method
, NULL
);
4115 mono_mb_emit_ldarg (mb
, 0);
4116 mono_mb_emit_stloc (mb
, this_local
);
4118 clause
->try_offset
= mono_mb_get_label (mb
);
4119 /* Call Monitor::Enter() */
4120 mono_mb_emit_ldloc (mb
, this_local
);
4121 mono_mb_emit_ldloc_addr (mb
, taken_local
);
4122 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
4124 /* Call the method */
4126 mono_mb_emit_ldarg (mb
, 0);
4127 for (i
= 0; i
< sig
->param_count
; i
++)
4128 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
4132 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
), NULL
);
4133 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4135 mono_mb_emit_managed_call (mb
, method
, NULL
);
4138 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4139 mono_mb_emit_stloc (mb
, ret_local
);
4141 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4143 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
4144 clause
->handler_offset
= mono_mb_get_label (mb
);
4146 /* Call Monitor::Exit() if needed */
4147 mono_mb_emit_ldloc (mb
, taken_local
);
4148 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4149 mono_mb_emit_ldloc (mb
, this_local
);
4150 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
4151 mono_mb_patch_branch (mb
, pos2
);
4152 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
4154 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4156 mono_mb_patch_branch (mb
, pos
);
4157 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4158 mono_mb_emit_ldloc (mb
, ret_local
);
4159 mono_mb_emit_byte (mb
, CEE_RET
);
4161 mono_mb_set_clauses (mb
, 1, clause
);
4165 emit_unbox_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4167 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4169 mono_mb_emit_ldarg (mb
, 0);
4170 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
4171 mono_mb_emit_byte (mb
, CEE_ADD
);
4172 for (int i
= 0; i
< sig
->param_count
; ++i
)
4173 mono_mb_emit_ldarg (mb
, i
+ 1);
4174 mono_mb_emit_managed_call (mb
, method
, NULL
);
4175 mono_mb_emit_byte (mb
, CEE_RET
);
4179 emit_array_accessor_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4181 MonoGenericContainer
*container
= NULL
;
4182 /* Call the method */
4184 mono_mb_emit_ldarg (mb
, 0);
4185 for (int i
= 0; i
< sig
->param_count
; i
++)
4186 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
4190 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
), NULL
);
4191 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4193 mono_mb_emit_managed_call (mb
, method
, NULL
);
4195 mono_mb_emit_byte (mb
, CEE_RET
);
4199 emit_generic_array_helper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
4201 mono_mb_emit_ldarg (mb
, 0);
4202 for (int i
= 0; i
< csig
->param_count
; i
++)
4203 mono_mb_emit_ldarg (mb
, i
+ 1);
4204 mono_mb_emit_managed_call (mb
, method
, NULL
);
4205 mono_mb_emit_byte (mb
, CEE_RET
);
4209 emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
4211 MonoImage
*image
= get_method_image (method
);
4212 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4213 int param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
4214 int pos_leave
, coop_gc_var
= 0, coop_gc_stack_dummy
= 0;
4215 MonoExceptionClause
*clause
;
4216 MonoType
*object_type
= mono_get_object_type ();
4217 #if defined (TARGET_WASM)
4218 const gboolean do_blocking_transition
= FALSE
;
4220 const gboolean do_blocking_transition
= TRUE
;
4223 /* local 0 (temp for exception object) */
4224 mono_mb_add_local (mb
, object_type
);
4226 /* local 1 (temp for result) */
4227 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4228 mono_mb_add_local (mb
, sig
->ret
);
4230 if (do_blocking_transition
) {
4231 /* local 4, dummy local used to get a stack address for suspend funcs */
4232 coop_gc_stack_dummy
= mono_mb_add_local (mb
, mono_get_int_type ());
4233 /* local 5, the local to be used when calling the suspend funcs */
4234 coop_gc_var
= mono_mb_add_local (mb
, mono_get_int_type ());
4237 /* clear exception arg */
4238 mono_mb_emit_ldarg (mb
, param_count
- 1);
4239 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4240 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4242 if (do_blocking_transition
) {
4243 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
4244 mono_mb_emit_icall (mb
, mono_threads_enter_gc_unsafe_region_unbalanced
);
4245 mono_mb_emit_stloc (mb
, coop_gc_var
);
4249 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
4250 clause
->try_offset
= mono_mb_get_label (mb
);
4252 /* push method's args */
4253 for (int i
= 0; i
< param_count
- 1; i
++) {
4257 mono_mb_emit_ldarg (mb
, i
);
4259 /* get the byval type of the param */
4260 klass
= mono_class_from_mono_type_internal (csig
->params
[i
]);
4261 type
= m_class_get_byval_arg (klass
);
4263 /* unbox struct args */
4264 if (MONO_TYPE_ISSTRUCT (type
)) {
4265 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
4267 /* byref args & and the "this" arg must remain a ptr.
4268 Otherwise make a copy of the value type */
4269 if (!(csig
->params
[i
]->byref
|| (i
== 0 && sig
->hasthis
)))
4270 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
4272 csig
->params
[i
] = object_type
;
4277 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
4278 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4280 mono_mb_emit_op (mb
, CEE_CALL
, method
);
4282 /* save result at local 1 */
4283 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4284 mono_mb_emit_stloc (mb
, 1);
4286 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4289 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4290 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
4291 clause
->data
.catch_class
= mono_defaults
.object_class
;
4293 clause
->handler_offset
= mono_mb_get_label (mb
);
4295 /* store exception at local 0 */
4296 mono_mb_emit_stloc (mb
, 0);
4297 mono_mb_emit_ldarg (mb
, param_count
- 1);
4298 mono_mb_emit_ldloc (mb
, 0);
4299 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4300 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4302 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4304 mono_mb_set_clauses (mb
, 1, clause
);
4306 mono_mb_patch_branch (mb
, pos_leave
);
4309 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
4310 mono_mb_emit_ldloc (mb
, 1);
4312 /* box the return value */
4313 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
4314 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (sig
->ret
));
4317 if (do_blocking_transition
) {
4318 mono_mb_emit_ldloc (mb
, coop_gc_var
);
4319 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
4320 mono_mb_emit_icall (mb
, mono_threads_exit_gc_unsafe_region_unbalanced
);
4323 mono_mb_emit_byte (mb
, CEE_RET
);
4327 emit_marshal_custom_get_instance (MonoMethodBuilder
*mb
, MonoClass
*klass
, MonoMarshalSpec
*spec
)
4329 static MonoClass
*Marshal
= NULL
;
4330 static MonoMethod
*get_instance
;
4333 Marshal
= mono_class_try_get_marshal_class ();
4336 get_instance
= get_method_nofail (Marshal
, "GetCustomMarshalerInstance", 2, 0);
4337 g_assert (get_instance
);
4340 // HACK: We cannot use ldtoken in this type of wrapper.
4341 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4342 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
4343 mono_mb_emit_icall (mb
, mono_marshal_get_type_object
);
4344 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4346 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4350 emit_marshal_custom_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4351 MonoMarshalSpec
*spec
,
4352 int conv_arg
, MonoType
**conv_arg_type
,
4353 MarshalAction action
)
4358 static MonoClass
*ICustomMarshaler
= NULL
;
4359 static MonoMethod
*cleanup_native
, *cleanup_managed
;
4360 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
4361 MonoMethodBuilder
*mb
= m
->mb
;
4365 MonoType
*int_type
= mono_get_int_type ();
4366 MonoType
*object_type
= mono_get_object_type ();
4368 if (!ICustomMarshaler
) {
4369 MonoClass
*klass
= mono_class_try_get_icustom_marshaler_class ();
4371 char *exception_msg
= g_strdup ("Current profile doesn't support ICustomMarshaler");
4372 /* Throw exception and emit compensation code if neccesary */
4374 case MARSHAL_ACTION_CONV_IN
:
4375 case MARSHAL_ACTION_CONV_RESULT
:
4376 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4377 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
4378 mono_mb_emit_byte (mb
, CEE_POP
);
4380 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
4383 case MARSHAL_ACTION_PUSH
:
4384 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4392 cleanup_native
= get_method_nofail (klass
, "CleanUpNativeData", 1, 0);
4393 g_assert (cleanup_native
);
4394 cleanup_managed
= get_method_nofail (klass
, "CleanUpManagedData", 1, 0);
4395 g_assert (cleanup_managed
);
4396 marshal_managed_to_native
= get_method_nofail (klass
, "MarshalManagedToNative", 1, 0);
4397 g_assert (marshal_managed_to_native
);
4398 marshal_native_to_managed
= get_method_nofail (klass
, "MarshalNativeToManaged", 1, 0);
4399 g_assert (marshal_native_to_managed
);
4401 mono_memory_barrier ();
4402 ICustomMarshaler
= klass
;
4405 if (spec
->data
.custom_data
.image
)
4406 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, spec
->data
.custom_data
.image
, error
);
4408 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, m
->image
, error
);
4409 g_assert (mtype
!= NULL
);
4410 mono_error_assert_ok (error
);
4411 mklass
= mono_class_from_mono_type_internal (mtype
);
4412 g_assert (mklass
!= NULL
);
4415 case MARSHAL_ACTION_CONV_IN
:
4417 case MONO_TYPE_CLASS
:
4418 case MONO_TYPE_OBJECT
:
4419 case MONO_TYPE_STRING
:
4420 case MONO_TYPE_ARRAY
:
4421 case MONO_TYPE_SZARRAY
:
4422 case MONO_TYPE_VALUETYPE
:
4426 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
4427 g_assert_not_reached ();
4431 conv_arg
= mono_mb_add_local (mb
, int_type
);
4433 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4434 mono_mb_emit_stloc (mb
, conv_arg
);
4436 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4439 /* Minic MS.NET behavior */
4440 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
4443 /* Check for null */
4444 mono_mb_emit_ldarg (mb
, argnum
);
4446 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4447 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4449 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4451 mono_mb_emit_ldarg (mb
, argnum
);
4453 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4455 if (t
->type
== MONO_TYPE_VALUETYPE
) {
4457 * Since we can't determine the type of the argument, we
4458 * will assume the unmanaged function takes a pointer.
4460 *conv_arg_type
= int_type
;
4462 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (t
));
4465 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4466 mono_mb_emit_stloc (mb
, conv_arg
);
4468 mono_mb_patch_branch (mb
, pos2
);
4471 case MARSHAL_ACTION_CONV_OUT
:
4472 /* Check for null */
4473 mono_mb_emit_ldloc (mb
, conv_arg
);
4474 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4477 mono_mb_emit_ldarg (mb
, argnum
);
4479 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4481 mono_mb_emit_ldloc (mb
, conv_arg
);
4482 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4483 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4484 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
4485 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4487 mono_mb_emit_ldloc (mb
, conv_arg
);
4488 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4490 /* We have nowhere to store the result */
4491 mono_mb_emit_byte (mb
, CEE_POP
);
4494 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4496 mono_mb_emit_ldloc (mb
, conv_arg
);
4498 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4500 mono_mb_patch_branch (mb
, pos2
);
4503 case MARSHAL_ACTION_PUSH
:
4505 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4507 mono_mb_emit_ldloc (mb
, conv_arg
);
4510 case MARSHAL_ACTION_CONV_RESULT
:
4511 loc1
= mono_mb_add_local (mb
, int_type
);
4513 mono_mb_emit_stloc (mb
, 3);
4515 mono_mb_emit_ldloc (mb
, 3);
4516 mono_mb_emit_stloc (mb
, loc1
);
4518 /* Check for null */
4519 mono_mb_emit_ldloc (mb
, 3);
4520 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4522 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4523 mono_mb_emit_byte (mb
, CEE_DUP
);
4525 mono_mb_emit_ldloc (mb
, 3);
4526 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4527 mono_mb_emit_stloc (mb
, 3);
4529 mono_mb_emit_ldloc (mb
, loc1
);
4530 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4532 mono_mb_patch_branch (mb
, pos2
);
4535 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4536 conv_arg
= mono_mb_add_local (mb
, object_type
);
4538 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4539 mono_mb_emit_stloc (mb
, conv_arg
);
4541 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4544 /* Check for null */
4545 mono_mb_emit_ldarg (mb
, argnum
);
4547 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4548 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4550 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4552 mono_mb_emit_ldarg (mb
, argnum
);
4554 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4556 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4557 mono_mb_emit_stloc (mb
, conv_arg
);
4559 mono_mb_patch_branch (mb
, pos2
);
4562 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4563 g_assert (!t
->byref
);
4565 loc1
= mono_mb_add_local (mb
, object_type
);
4567 mono_mb_emit_stloc (mb
, 3);
4569 mono_mb_emit_ldloc (mb
, 3);
4570 mono_mb_emit_stloc (mb
, loc1
);
4572 /* Check for null */
4573 mono_mb_emit_ldloc (mb
, 3);
4574 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4576 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4577 mono_mb_emit_byte (mb
, CEE_DUP
);
4579 mono_mb_emit_ldloc (mb
, 3);
4580 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4581 mono_mb_emit_stloc (mb
, 3);
4583 mono_mb_emit_ldloc (mb
, loc1
);
4584 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4586 mono_mb_patch_branch (mb
, pos2
);
4589 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4591 /* Check for null */
4592 mono_mb_emit_ldloc (mb
, conv_arg
);
4593 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4596 mono_mb_emit_ldarg (mb
, argnum
);
4598 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4600 mono_mb_emit_ldloc (mb
, conv_arg
);
4601 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4602 mono_mb_emit_byte (mb
, CEE_STIND_I
);
4605 /* Call CleanUpManagedData */
4606 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4608 mono_mb_emit_ldloc (mb
, conv_arg
);
4609 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4611 mono_mb_patch_branch (mb
, pos2
);
4615 g_assert_not_reached ();
4621 emit_marshal_asany_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4622 MonoMarshalSpec
*spec
,
4623 int conv_arg
, MonoType
**conv_arg_type
,
4624 MarshalAction action
)
4626 MonoMethodBuilder
*mb
= m
->mb
;
4628 MonoType
*int_type
= mono_get_int_type ();
4630 case MARSHAL_ACTION_CONV_IN
: {
4631 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4633 g_assert (t
->type
== MONO_TYPE_OBJECT
);
4634 g_assert (!t
->byref
);
4636 conv_arg
= mono_mb_add_local (mb
, int_type
);
4637 mono_mb_emit_ldarg (mb
, argnum
);
4638 mono_mb_emit_icon (mb
, encoding
);
4639 mono_mb_emit_icon (mb
, t
->attrs
);
4640 mono_mb_emit_icall (mb
, mono_marshal_asany
);
4641 mono_mb_emit_stloc (mb
, conv_arg
);
4645 case MARSHAL_ACTION_PUSH
:
4646 mono_mb_emit_ldloc (mb
, conv_arg
);
4649 case MARSHAL_ACTION_CONV_OUT
: {
4650 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4652 mono_mb_emit_ldarg (mb
, argnum
);
4653 mono_mb_emit_ldloc (mb
, conv_arg
);
4654 mono_mb_emit_icon (mb
, encoding
);
4655 mono_mb_emit_icon (mb
, t
->attrs
);
4656 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
4661 g_assert_not_reached ();
4667 emit_marshal_vtype_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4668 MonoMarshalSpec
*spec
,
4669 int conv_arg
, MonoType
**conv_arg_type
,
4670 MarshalAction action
)
4672 MonoMethodBuilder
*mb
= m
->mb
;
4673 MonoClass
*klass
, *date_time_class
;
4676 klass
= mono_class_from_mono_type_internal (t
);
4678 date_time_class
= mono_class_get_date_time_class ();
4680 MonoType
*int_type
= mono_get_int_type ();
4681 MonoType
*double_type
= m_class_get_byval_arg (mono_defaults
.double_class
);
4684 case MARSHAL_ACTION_CONV_IN
:
4685 if (klass
== date_time_class
) {
4686 /* Convert it to an OLE DATE type */
4687 static MonoMethod
*to_oadate
;
4690 to_oadate
= get_method_nofail (date_time_class
, "ToOADate", 0, 0);
4691 g_assert (to_oadate
);
4693 conv_arg
= mono_mb_add_local (mb
, double_type
);
4696 mono_mb_emit_ldarg (mb
, argnum
);
4697 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4700 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4702 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = double_type
;
4704 mono_mb_emit_ldarg_addr (mb
, argnum
);
4705 mono_mb_emit_managed_call (mb
, to_oadate
, NULL
);
4706 mono_mb_emit_stloc (mb
, conv_arg
);
4710 mono_mb_patch_branch (mb
, pos
);
4714 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4717 conv_arg
= mono_mb_add_local (mb
, int_type
);
4719 /* store the address of the source into local variable 0 */
4721 mono_mb_emit_ldarg (mb
, argnum
);
4723 mono_mb_emit_ldarg_addr (mb
, argnum
);
4725 mono_mb_emit_stloc (mb
, 0);
4727 /* allocate space for the native struct and
4728 * store the address into local variable 1 (dest) */
4729 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
4730 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4731 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
4732 mono_mb_emit_stloc (mb
, conv_arg
);
4735 mono_mb_emit_ldloc (mb
, 0);
4736 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4739 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4741 mono_mb_emit_ldloc (mb
, conv_arg
);
4742 mono_mb_emit_stloc (mb
, 1);
4744 /* emit valuetype conversion code */
4745 emit_struct_conv (mb
, klass
, FALSE
);
4749 mono_mb_patch_branch (mb
, pos
);
4752 case MARSHAL_ACTION_PUSH
:
4753 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
4755 g_assert (!t
->byref
);
4757 /* Have to change the signature since the vtype is passed byref */
4758 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = int_type
;
4760 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4761 mono_mb_emit_ldarg_addr (mb
, argnum
);
4763 mono_mb_emit_ldloc (mb
, conv_arg
);
4767 if (klass
== date_time_class
) {
4769 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4771 mono_mb_emit_ldloc (mb
, conv_arg
);
4775 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4776 mono_mb_emit_ldarg (mb
, argnum
);
4779 mono_mb_emit_ldloc (mb
, conv_arg
);
4781 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4782 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
4786 case MARSHAL_ACTION_CONV_OUT
:
4787 if (klass
== date_time_class
) {
4788 /* Convert from an OLE DATE type */
4789 static MonoMethod
*from_oadate
;
4794 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4796 from_oadate
= get_method_nofail (date_time_class
, "FromOADate", 1, 0);
4797 g_assert (from_oadate
);
4799 mono_mb_emit_ldarg (mb
, argnum
);
4800 mono_mb_emit_ldloc (mb
, conv_arg
);
4801 mono_mb_emit_managed_call (mb
, from_oadate
, NULL
);
4802 mono_mb_emit_op (mb
, CEE_STOBJ
, date_time_class
);
4807 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4811 /* dst = argument */
4812 mono_mb_emit_ldarg (mb
, argnum
);
4813 mono_mb_emit_stloc (mb
, 1);
4815 mono_mb_emit_ldloc (mb
, 1);
4816 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4818 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4819 /* src = tmp_locals [i] */
4820 mono_mb_emit_ldloc (mb
, conv_arg
);
4821 mono_mb_emit_stloc (mb
, 0);
4823 /* emit valuetype conversion code */
4824 emit_struct_conv (mb
, klass
, TRUE
);
4828 emit_struct_free (mb
, klass
, conv_arg
);
4831 mono_mb_patch_branch (mb
, pos
);
4834 case MARSHAL_ACTION_CONV_RESULT
:
4835 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
)) {
4836 mono_mb_emit_stloc (mb
, 3);
4840 /* load pointer to returned value type */
4841 g_assert (m
->vtaddr_var
);
4842 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
4843 /* store the address of the source into local variable 0 */
4844 mono_mb_emit_stloc (mb
, 0);
4846 mono_mb_emit_ldloc_addr (mb
, 3);
4847 mono_mb_emit_stloc (mb
, 1);
4849 /* emit valuetype conversion code */
4850 emit_struct_conv (mb
, klass
, TRUE
);
4853 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4854 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4859 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
4861 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4865 mono_mb_emit_ldarg (mb
, argnum
);
4867 mono_mb_emit_ldarg_addr (mb
, argnum
);
4868 mono_mb_emit_stloc (mb
, 0);
4871 mono_mb_emit_ldloc (mb
, 0);
4872 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4875 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4876 mono_mb_emit_stloc (mb
, 1);
4878 /* emit valuetype conversion code */
4879 emit_struct_conv (mb
, klass
, TRUE
);
4882 mono_mb_patch_branch (mb
, pos
);
4885 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4886 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4888 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4891 /* Check for null */
4892 mono_mb_emit_ldarg (mb
, argnum
);
4893 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4896 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4897 mono_mb_emit_stloc (mb
, 0);
4900 mono_mb_emit_ldarg (mb
, argnum
);
4901 mono_mb_emit_stloc (mb
, 1);
4903 /* emit valuetype conversion code */
4904 emit_struct_conv (mb
, klass
, FALSE
);
4906 mono_mb_patch_branch (mb
, pos2
);
4909 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4910 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4911 mono_mb_emit_stloc (mb
, 3);
4916 /* load pointer to returned value type */
4917 g_assert (m
->vtaddr_var
);
4918 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
4920 /* store the address of the source into local variable 0 */
4921 mono_mb_emit_stloc (mb
, 0);
4922 /* allocate space for the native struct and
4923 * store the address into dst_ptr */
4924 m
->retobj_var
= mono_mb_add_local (mb
, int_type
);
4925 m
->retobj_class
= klass
;
4926 g_assert (m
->retobj_var
);
4927 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
4928 mono_mb_emit_byte (mb
, CEE_CONV_I
);
4929 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
4930 mono_mb_emit_stloc (mb
, 1);
4931 mono_mb_emit_ldloc (mb
, 1);
4932 mono_mb_emit_stloc (mb
, m
->retobj_var
);
4934 /* emit valuetype conversion code */
4935 emit_struct_conv (mb
, klass
, FALSE
);
4939 g_assert_not_reached ();
4945 emit_marshal_string_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4946 MonoMarshalSpec
*spec
,
4947 int conv_arg
, MonoType
**conv_arg_type
,
4948 MarshalAction action
)
4950 MonoMethodBuilder
*mb
= m
->mb
;
4951 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
4952 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
4955 MonoType
*int_type
= mono_get_int_type ();
4956 MonoType
*object_type
= mono_get_object_type ();
4958 case MARSHAL_ACTION_CONV_IN
:
4959 *conv_arg_type
= int_type
;
4960 conv_arg
= mono_mb_add_local (mb
, int_type
);
4963 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4966 mono_mb_emit_ldarg (mb
, argnum
);
4967 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4969 mono_mb_emit_ldarg (mb
, argnum
);
4972 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
4973 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
4974 mono_mb_emit_exception_marshal_directive (mb
, msg
);
4976 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
4978 mono_mb_emit_stloc (mb
, conv_arg
);
4982 case MARSHAL_ACTION_CONV_OUT
:
4983 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
4984 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
4985 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
4986 mono_mb_emit_exception_marshal_directive (mb
, msg
);
4990 if (encoding
== MONO_NATIVE_VBBYREFSTR
) {
4991 static MonoMethod
*m
;
4994 m
= get_method_nofail (mono_defaults
.string_class
, "get_Length", -1, 0);
4997 char *msg
= g_strdup ("VBByRefStr marshalling requires a ref parameter.");
4998 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5003 * Have to allocate a new string with the same length as the original, and
5004 * copy the contents of the buffer pointed to by CONV_ARG into it.
5006 g_assert (t
->byref
);
5007 mono_mb_emit_ldarg (mb
, argnum
);
5008 mono_mb_emit_ldloc (mb
, conv_arg
);
5009 mono_mb_emit_ldarg (mb
, argnum
);
5010 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5011 mono_mb_emit_managed_call (mb
, m
, NULL
);
5012 mono_mb_emit_icall (mb
, mono_string_new_len_wrapper
);
5013 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5014 } else if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5016 mono_mb_emit_ldarg (mb
, argnum
);
5017 mono_mb_emit_ldloc (mb
, conv_arg
);
5018 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
5019 mono_mb_emit_byte (mb
, stind_op
);
5024 mono_mb_emit_ldloc (mb
, conv_arg
);
5025 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5026 mono_mb_emit_icall (mb
, mono_free_bstr
);
5028 mono_mb_emit_icall (mb
, mono_marshal_free
);
5032 case MARSHAL_ACTION_PUSH
:
5033 if (t
->byref
&& encoding
!= MONO_NATIVE_VBBYREFSTR
)
5034 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5036 mono_mb_emit_ldloc (mb
, conv_arg
);
5039 case MARSHAL_ACTION_CONV_RESULT
:
5040 mono_mb_emit_stloc (mb
, 0);
5042 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5043 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5044 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5045 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5049 mono_mb_emit_ldloc (mb
, 0);
5050 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5051 mono_mb_emit_stloc (mb
, 3);
5053 /* free the string */
5054 mono_mb_emit_ldloc (mb
, 0);
5055 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5056 mono_mb_emit_icall (mb
, mono_free_bstr
);
5058 mono_mb_emit_icall (mb
, mono_marshal_free
);
5061 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5062 conv_arg
= mono_mb_add_local (mb
, object_type
);
5064 *conv_arg_type
= int_type
;
5067 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5071 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5072 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5073 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5074 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5078 mono_mb_emit_ldarg (mb
, argnum
);
5080 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5081 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5082 mono_mb_emit_stloc (mb
, conv_arg
);
5085 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5089 mono_mb_emit_ldarg (mb
, argnum
);
5090 mono_mb_emit_ldloc (mb
, conv_arg
);
5091 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
5092 mono_mb_emit_byte (mb
, stind_op
);
5097 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5098 if (conv_to_icall (conv
, NULL
) == MONO_JIT_ICALL_mono_marshal_string_to_utf16
)
5099 /* We need to make a copy so the caller is able to free it */
5100 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
5102 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5103 mono_mb_emit_stloc (mb
, 3);
5107 g_assert_not_reached ();
5114 emit_marshal_safehandle_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5115 MonoMarshalSpec
*spec
, int conv_arg
,
5116 MonoType
**conv_arg_type
, MarshalAction action
)
5118 MonoMethodBuilder
*mb
= m
->mb
;
5119 MonoType
*int_type
= mono_get_int_type ();
5120 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
5123 case MARSHAL_ACTION_CONV_IN
: {
5124 int dar_release_slot
, pos
;
5126 conv_arg
= mono_mb_add_local (mb
, int_type
);
5127 *conv_arg_type
= int_type
;
5129 if (!sh_dangerous_add_ref
)
5130 init_safe_handle ();
5132 mono_mb_emit_ldarg (mb
, argnum
);
5133 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5134 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5136 mono_mb_patch_branch (mb
, pos
);
5139 * My tests in show that ref SafeHandles are not really
5140 * passed as ref objects. Instead a NULL is passed as the
5143 mono_mb_emit_icon (mb
, 0);
5144 mono_mb_emit_stloc (mb
, conv_arg
);
5148 /* Create local to hold the ref parameter to DangerousAddRef */
5149 dar_release_slot
= mono_mb_add_local (mb
, boolean_type
);
5151 /* set release = false; */
5152 mono_mb_emit_icon (mb
, 0);
5153 mono_mb_emit_stloc (mb
, dar_release_slot
);
5155 /* safehandle.DangerousAddRef (ref release) */
5156 mono_mb_emit_ldarg (mb
, argnum
);
5157 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5158 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5160 /* Pull the handle field from SafeHandle */
5161 mono_mb_emit_ldarg (mb
, argnum
);
5162 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5163 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5164 mono_mb_emit_stloc (mb
, conv_arg
);
5169 case MARSHAL_ACTION_PUSH
:
5171 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5173 mono_mb_emit_ldloc (mb
, conv_arg
);
5176 case MARSHAL_ACTION_CONV_OUT
: {
5177 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5178 int dar_release_slot
= conv_arg
+ 1;
5181 if (!sh_dangerous_release
)
5182 init_safe_handle ();
5189 * My tests indicate that ref SafeHandles parameters are not actually
5190 * passed by ref, but instead a new Handle is created regardless of
5191 * whether a change happens in the unmanaged side.
5193 * Also, the Handle is created before calling into unmanaged code,
5194 * but we do not support that mechanism (getting to the original
5195 * handle) and it makes no difference where we create this
5197 ctor
= mono_class_get_method_from_name_checked (t
->data
.klass
, ".ctor", 0, 0, error
);
5198 if (ctor
== NULL
|| !is_ok (error
)){
5199 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5200 mono_error_cleanup (error
);
5203 /* refval = new SafeHandleDerived ()*/
5204 mono_mb_emit_ldarg (mb
, argnum
);
5205 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5206 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5208 /* refval.handle = returned_handle */
5209 mono_mb_emit_ldarg (mb
, argnum
);
5210 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5211 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5212 mono_mb_emit_ldloc (mb
, conv_arg
);
5213 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5215 mono_mb_emit_ldloc (mb
, dar_release_slot
);
5216 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5217 mono_mb_emit_ldarg (mb
, argnum
);
5218 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5219 mono_mb_patch_branch (mb
, label_next
);
5224 case MARSHAL_ACTION_CONV_RESULT
: {
5226 MonoMethod
*ctor
= NULL
;
5227 int intptr_handle_slot
;
5229 if (mono_class_is_abstract (t
->data
.klass
)) {
5230 mono_mb_emit_byte (mb
, CEE_POP
);
5231 mono_mb_emit_exception_marshal_directive (mb
, g_strdup ("Returned SafeHandles should not be abstract"));
5235 ctor
= mono_class_get_method_from_name_checked (t
->data
.klass
, ".ctor", 0, 0, error
);
5236 if (ctor
== NULL
|| !is_ok (error
)){
5237 mono_error_cleanup (error
);
5238 mono_mb_emit_byte (mb
, CEE_POP
);
5239 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5242 /* Store the IntPtr results into a local */
5243 intptr_handle_slot
= mono_mb_add_local (mb
, int_type
);
5244 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
5246 /* Create return value */
5247 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5248 mono_mb_emit_stloc (mb
, 3);
5250 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5251 mono_mb_emit_ldloc (mb
, 3);
5252 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5253 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
5254 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5258 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5259 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5262 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5263 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5266 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5267 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5270 printf ("Unhandled case for MarshalAction: %d\n", action
);
5277 emit_marshal_handleref_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5278 MonoMarshalSpec
*spec
, int conv_arg
,
5279 MonoType
**conv_arg_type
, MarshalAction action
)
5281 MonoMethodBuilder
*mb
= m
->mb
;
5283 MonoType
*int_type
= mono_get_int_type ();
5285 case MARSHAL_ACTION_CONV_IN
: {
5286 conv_arg
= mono_mb_add_local (mb
, int_type
);
5287 *conv_arg_type
= int_type
;
5290 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5291 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5294 mono_mb_emit_ldarg_addr (mb
, argnum
);
5295 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
5296 mono_mb_emit_byte (mb
, CEE_ADD
);
5297 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5298 mono_mb_emit_stloc (mb
, conv_arg
);
5302 case MARSHAL_ACTION_PUSH
:
5303 mono_mb_emit_ldloc (mb
, conv_arg
);
5306 case MARSHAL_ACTION_CONV_OUT
: {
5307 /* no resource release required */
5311 case MARSHAL_ACTION_CONV_RESULT
: {
5312 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5313 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5317 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5318 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5321 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5322 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5325 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5326 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5329 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
5336 emit_marshal_object_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5337 MonoMarshalSpec
*spec
,
5338 int conv_arg
, MonoType
**conv_arg_type
,
5339 MarshalAction action
)
5341 MonoMethodBuilder
*mb
= m
->mb
;
5342 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
5345 MonoType
*int_type
= mono_get_int_type ();
5347 case MARSHAL_ACTION_CONV_IN
:
5348 *conv_arg_type
= int_type
;
5349 conv_arg
= mono_mb_add_local (mb
, int_type
);
5351 m
->orig_conv_args
[argnum
] = 0;
5353 if (mono_class_from_mono_type_internal (t
) == mono_defaults
.object_class
) {
5354 char *msg
= g_strdup_printf ("Marshalling of type object is not implemented");
5355 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5359 if (m_class_is_delegate (klass
)) {
5361 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5362 char *msg
= g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5363 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5365 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5366 mono_mb_emit_stloc (mb
, conv_arg
);
5368 mono_mb_emit_ldarg (mb
, argnum
);
5369 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5370 mono_mb_emit_stloc (mb
, conv_arg
);
5372 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5373 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5374 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
5378 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5379 char *msg
= g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5380 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5386 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5389 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5390 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
5391 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5395 mono_mb_emit_ldarg (mb
, argnum
);
5397 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5399 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5400 mono_mb_emit_stloc (mb
, conv_arg
);
5401 } else if (m_class_is_blittable (klass
)) {
5402 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5403 mono_mb_emit_stloc (mb
, conv_arg
);
5405 mono_mb_emit_ldarg (mb
, argnum
);
5406 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5408 mono_mb_emit_ldarg (mb
, argnum
);
5409 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5410 mono_mb_emit_stloc (mb
, conv_arg
);
5412 mono_mb_patch_branch (mb
, pos
);
5415 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5416 mono_mb_emit_stloc (mb
, conv_arg
);
5419 /* we dont need any conversions for out parameters */
5420 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5423 mono_mb_emit_ldarg (mb
, argnum
);
5424 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5427 mono_mb_emit_ldarg (mb
, argnum
);
5428 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5429 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5432 /* store the address of the source into local variable 0 */
5433 mono_mb_emit_stloc (mb
, 0);
5434 mono_mb_emit_ldloc (mb
, 0);
5435 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5437 /* allocate space for the native struct and store the address */
5438 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5439 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5440 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5441 mono_mb_emit_stloc (mb
, conv_arg
);
5444 /* Need to store the original buffer so we can free it later */
5445 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, int_type
);
5446 mono_mb_emit_ldloc (mb
, conv_arg
);
5447 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
5450 /* set the src_ptr */
5451 mono_mb_emit_ldloc (mb
, 0);
5452 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5453 mono_mb_emit_stloc (mb
, 0);
5456 mono_mb_emit_ldloc (mb
, conv_arg
);
5457 mono_mb_emit_stloc (mb
, 1);
5459 /* emit valuetype conversion code */
5460 emit_struct_conv (mb
, klass
, FALSE
);
5462 mono_mb_patch_branch (mb
, pos
);
5466 case MARSHAL_ACTION_CONV_OUT
:
5467 if (klass
== mono_class_try_get_stringbuilder_class ()) {
5469 MonoMarshalNative encoding
;
5470 MonoMarshalConv conv
;
5472 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5473 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
5475 g_assert (encoding
!= -1);
5478 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5482 mono_mb_emit_ldarg (mb
, argnum
);
5483 mono_mb_emit_ldloc (mb
, conv_arg
);
5486 case MONO_NATIVE_LPWSTR
:
5487 mono_mb_emit_icall (mb
, mono_string_utf16_to_builder2
);
5489 case MONO_NATIVE_LPSTR
:
5490 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5492 case MONO_NATIVE_UTF8STR
:
5493 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5496 g_assert_not_reached ();
5499 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5500 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
)) {
5501 mono_mb_emit_ldarg (mb
, argnum
);
5502 mono_mb_emit_ldloc (mb
, conv_arg
);
5504 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5508 mono_mb_emit_ldloc (mb
, conv_arg
);
5509 mono_mb_emit_icall (mb
, mono_marshal_free
);
5514 if (m_class_is_delegate (klass
)) {
5516 mono_mb_emit_ldarg (mb
, argnum
);
5517 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5518 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5519 mono_mb_emit_ldloc (mb
, conv_arg
);
5520 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5521 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5526 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5527 /* allocate a new object */
5528 mono_mb_emit_ldarg (mb
, argnum
);
5529 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5530 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5531 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5534 /* dst = *argument */
5535 mono_mb_emit_ldarg (mb
, argnum
);
5538 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5540 mono_mb_emit_stloc (mb
, 1);
5542 mono_mb_emit_ldloc (mb
, 1);
5543 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5545 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5546 mono_mb_emit_ldloc (mb
, 1);
5547 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
5548 mono_mb_emit_byte (mb
, CEE_ADD
);
5549 mono_mb_emit_stloc (mb
, 1);
5551 /* src = tmp_locals [i] */
5552 mono_mb_emit_ldloc (mb
, conv_arg
);
5553 mono_mb_emit_stloc (mb
, 0);
5555 /* emit valuetype conversion code */
5556 emit_struct_conv (mb
, klass
, TRUE
);
5558 /* Free the structure returned by the native code */
5559 emit_struct_free (mb
, klass
, conv_arg
);
5561 if (m
->orig_conv_args
[argnum
]) {
5563 * If the native function changed the pointer, then free
5564 * the original structure plus the new pointer.
5566 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
5567 mono_mb_emit_ldloc (mb
, conv_arg
);
5568 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5570 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5571 g_assert (m
->orig_conv_args
[argnum
]);
5573 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
5576 mono_mb_emit_ldloc (mb
, conv_arg
);
5577 mono_mb_emit_icall (mb
, mono_marshal_free
);
5579 mono_mb_patch_branch (mb
, pos2
);
5583 /* Free the original structure passed to native code */
5584 emit_struct_free (mb
, klass
, conv_arg
);
5586 mono_mb_patch_branch (mb
, pos
);
5589 case MARSHAL_ACTION_PUSH
:
5591 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5593 mono_mb_emit_ldloc (mb
, conv_arg
);
5596 case MARSHAL_ACTION_CONV_RESULT
:
5597 if (m_class_is_delegate (klass
)) {
5598 g_assert (!t
->byref
);
5599 mono_mb_emit_stloc (mb
, 0);
5600 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5601 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5602 mono_mb_emit_ldloc (mb
, 0);
5603 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5604 mono_mb_emit_stloc (mb
, 3);
5605 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5607 char *msg
= g_strdup_printf ("Return marshalling of stringbuilders is not implemented.");
5608 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5611 mono_mb_emit_stloc (mb
, 0);
5613 /* Make a copy since emit_conv modifies local 0 */
5614 loc
= mono_mb_add_local (mb
, int_type
);
5615 mono_mb_emit_ldloc (mb
, 0);
5616 mono_mb_emit_stloc (mb
, loc
);
5618 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5619 mono_mb_emit_stloc (mb
, 3);
5621 mono_mb_emit_ldloc (mb
, 0);
5622 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5624 /* allocate result object */
5626 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5627 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5628 mono_mb_emit_stloc (mb
, 3);
5632 mono_mb_emit_ldloc (mb
, 3);
5633 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5634 mono_mb_emit_stloc (mb
, 1);
5636 /* emit conversion code */
5637 emit_struct_conv (mb
, klass
, TRUE
);
5639 emit_struct_free (mb
, klass
, loc
);
5641 /* Free the pointer allocated by unmanaged code */
5642 mono_mb_emit_ldloc (mb
, loc
);
5643 mono_mb_emit_icall (mb
, mono_marshal_free
);
5644 mono_mb_patch_branch (mb
, pos
);
5648 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5649 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
5651 if (m_class_is_delegate (klass
)) {
5652 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5653 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5654 mono_mb_emit_ldarg (mb
, argnum
);
5656 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5657 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5658 mono_mb_emit_stloc (mb
, conv_arg
);
5662 if (klass
== mono_class_try_get_stringbuilder_class ()) {
5663 MonoMarshalNative encoding
;
5665 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5668 g_assert (encoding
== MONO_NATIVE_LPSTR
|| encoding
== MONO_NATIVE_UTF8STR
);
5670 g_assert (!t
->byref
);
5671 g_assert (encoding
!= -1);
5673 mono_mb_emit_ldarg (mb
, argnum
);
5674 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5675 mono_mb_emit_stloc (mb
, conv_arg
);
5679 /* The class can not have an automatic layout */
5680 if (mono_class_is_auto_layout (klass
)) {
5681 mono_mb_emit_auto_layout_exception (mb
, klass
);
5685 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
5686 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5687 mono_mb_emit_stloc (mb
, conv_arg
);
5692 mono_mb_emit_ldarg (mb
, argnum
);
5696 /* Check for NULL and raise an exception */
5697 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5699 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5701 mono_mb_patch_branch (mb
, pos2
);
5702 mono_mb_emit_ldarg (mb
, argnum
);
5703 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5706 mono_mb_emit_stloc (mb
, 0);
5708 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5709 mono_mb_emit_stloc (mb
, conv_arg
);
5711 mono_mb_emit_ldloc (mb
, 0);
5712 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5714 /* Create and set dst */
5715 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5716 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5717 mono_mb_emit_stloc (mb
, conv_arg
);
5718 mono_mb_emit_ldloc (mb
, conv_arg
);
5719 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5720 mono_mb_emit_stloc (mb
, 1);
5722 /* emit valuetype conversion code */
5723 emit_struct_conv (mb
, klass
, TRUE
);
5725 mono_mb_patch_branch (mb
, pos
);
5728 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5729 if (m_class_is_delegate (klass
)) {
5732 mono_mb_emit_ldarg (mb
, argnum
);
5733 mono_mb_emit_ldloc (mb
, conv_arg
);
5734 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, &stind_op
));
5735 mono_mb_emit_byte (mb
, stind_op
);
5741 /* Check for null */
5742 mono_mb_emit_ldloc (mb
, conv_arg
);
5743 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5744 mono_mb_emit_ldarg (mb
, argnum
);
5745 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5746 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5747 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
5749 mono_mb_patch_branch (mb
, pos
);
5752 mono_mb_emit_ldloc (mb
, conv_arg
);
5753 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5754 mono_mb_emit_stloc (mb
, 0);
5756 /* Allocate and set dest */
5757 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5758 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5759 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5760 mono_mb_emit_stloc (mb
, 1);
5762 /* Update argument pointer */
5763 mono_mb_emit_ldarg (mb
, argnum
);
5764 mono_mb_emit_ldloc (mb
, 1);
5765 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5767 /* emit valuetype conversion code */
5768 emit_struct_conv (mb
, klass
, FALSE
);
5770 mono_mb_patch_branch (mb
, pos2
);
5771 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5772 // FIXME: What to do here ?
5774 /* byval [Out] marshalling */
5776 /* FIXME: Handle null */
5779 mono_mb_emit_ldloc (mb
, conv_arg
);
5780 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5781 mono_mb_emit_stloc (mb
, 0);
5784 mono_mb_emit_ldarg (mb
, argnum
);
5785 mono_mb_emit_stloc (mb
, 1);
5787 /* emit valuetype conversion code */
5788 emit_struct_conv (mb
, klass
, FALSE
);
5792 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5793 if (m_class_is_delegate (klass
)) {
5794 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5795 mono_mb_emit_stloc (mb
, 3);
5799 /* The class can not have an automatic layout */
5800 if (mono_class_is_auto_layout (klass
)) {
5801 mono_mb_emit_auto_layout_exception (mb
, klass
);
5805 mono_mb_emit_stloc (mb
, 0);
5806 /* Check for null */
5807 mono_mb_emit_ldloc (mb
, 0);
5808 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5809 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5810 mono_mb_emit_stloc (mb
, 3);
5811 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
5813 mono_mb_patch_branch (mb
, pos
);
5816 mono_mb_emit_ldloc (mb
, 0);
5817 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5818 mono_mb_emit_stloc (mb
, 0);
5820 /* Allocate and set dest */
5821 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5822 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5823 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5824 mono_mb_emit_byte (mb
, CEE_DUP
);
5825 mono_mb_emit_stloc (mb
, 1);
5826 mono_mb_emit_stloc (mb
, 3);
5828 emit_struct_conv (mb
, klass
, FALSE
);
5830 mono_mb_patch_branch (mb
, pos2
);
5834 g_assert_not_reached ();
5841 emit_marshal_variant_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5842 MonoMarshalSpec
*spec
,
5843 int conv_arg
, MonoType
**conv_arg_type
,
5844 MarshalAction action
)
5847 MonoMethodBuilder
*mb
= m
->mb
;
5848 static MonoMethod
*get_object_for_native_variant
= NULL
;
5849 static MonoMethod
*get_native_variant_for_object
= NULL
;
5850 MonoType
*variant_type
= m_class_get_byval_arg (mono_class_get_variant_class ());
5851 MonoType
*variant_type_byref
= m_class_get_this_arg (mono_class_get_variant_class ());
5852 MonoType
*object_type
= mono_get_object_type ();
5854 if (!get_object_for_native_variant
)
5855 get_object_for_native_variant
= get_method_nofail (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0);
5856 g_assert (get_object_for_native_variant
);
5858 if (!get_native_variant_for_object
)
5859 get_native_variant_for_object
= get_method_nofail (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0);
5860 g_assert (get_native_variant_for_object
);
5863 case MARSHAL_ACTION_CONV_IN
: {
5864 conv_arg
= mono_mb_add_local (mb
, variant_type
);
5867 *conv_arg_type
= variant_type_byref
;
5869 *conv_arg_type
= variant_type
;
5871 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5874 mono_mb_emit_ldarg (mb
, argnum
);
5876 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
5877 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5878 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
5882 case MARSHAL_ACTION_CONV_OUT
: {
5883 static MonoMethod
*variant_clear
= NULL
;
5886 variant_clear
= get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
5887 g_assert (variant_clear
);
5890 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5891 mono_mb_emit_ldarg (mb
, argnum
);
5892 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5893 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
5894 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5897 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5898 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
5902 case MARSHAL_ACTION_PUSH
:
5904 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5906 mono_mb_emit_ldloc (mb
, conv_arg
);
5909 case MARSHAL_ACTION_CONV_RESULT
: {
5910 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
5911 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5915 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
5916 conv_arg
= mono_mb_add_local (mb
, object_type
);
5919 *conv_arg_type
= variant_type_byref
;
5921 *conv_arg_type
= variant_type
;
5923 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5927 mono_mb_emit_ldarg (mb
, argnum
);
5929 mono_mb_emit_ldarg_addr (mb
, argnum
);
5930 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
5931 mono_mb_emit_stloc (mb
, conv_arg
);
5935 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
5936 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5937 mono_mb_emit_ldloc (mb
, conv_arg
);
5938 mono_mb_emit_ldarg (mb
, argnum
);
5939 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
5944 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
5945 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
5946 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5951 g_assert_not_reached ();
5953 #endif /* DISABLE_COM */
5959 emit_managed_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
5961 MonoMethodSignature
*sig
, *csig
;
5962 int i
, *tmp_locals
, orig_domain
, attach_cookie
;
5963 gboolean closed
= FALSE
;
5968 MonoType
*int_type
= mono_get_int_type ();
5969 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
5970 /* allocate local 0 (pointer) src_ptr */
5971 mono_mb_add_local (mb
, int_type
);
5972 /* allocate local 1 (pointer) dst_ptr */
5973 mono_mb_add_local (mb
, int_type
);
5974 /* allocate local 2 (boolean) delete_old */
5975 mono_mb_add_local (mb
, boolean_type
);
5977 if (!sig
->hasthis
&& sig
->param_count
!= invoke_sig
->param_count
) {
5978 /* Closed delegate */
5979 g_assert (sig
->param_count
== invoke_sig
->param_count
+ 1);
5981 /* Use a new signature without the first argument */
5982 sig
= mono_metadata_signature_dup (sig
);
5983 memmove (&sig
->params
[0], &sig
->params
[1], (sig
->param_count
- 1) * sizeof (MonoType
*));
5984 sig
->param_count
--;
5987 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
5988 /* allocate local 3 to store the return value */
5989 mono_mb_add_local (mb
, sig
->ret
);
5992 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
5993 m
->vtaddr_var
= mono_mb_add_local (mb
, int_type
);
5995 orig_domain
= mono_mb_add_local (mb
, int_type
);
5996 attach_cookie
= mono_mb_add_local (mb
, int_type
);
5999 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
6000 * intptr_t attach_cookie;
6001 * intptr_t orig_domain = mono_threads_attach_coop (domain, &attach_cookie);
6004 * ret = method (...);
6005 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
6006 * mono_threads_detach_coop (orig_domain, &attach_cookie);
6011 mono_mb_emit_icon (mb
, 0);
6012 mono_mb_emit_stloc (mb
, 2);
6014 /* orig_domain = mono_threads_attach_coop (domain, &attach_cookie); */
6015 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6016 mono_mb_emit_byte (mb
, CEE_MONO_LDDOMAIN
);
6017 mono_mb_emit_ldloc_addr (mb
, attach_cookie
);
6019 * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads.
6020 * Keep this in sync with the CEE_JIT_ICALL code in the JIT.
6022 * Special cased in interpreter, keep in sync.
6024 mono_mb_emit_icall (mb
, mono_threads_attach_coop
);
6025 mono_mb_emit_stloc (mb
, orig_domain
);
6027 /* <interrupt check> */
6028 emit_thread_interrupt_checkpoint (mb
);
6030 /* we first do all conversions */
6031 tmp_locals
= g_newa (int, sig
->param_count
);
6032 for (i
= 0; i
< sig
->param_count
; i
++) {
6033 MonoType
*t
= sig
->params
[i
];
6036 case MONO_TYPE_OBJECT
:
6037 case MONO_TYPE_CLASS
:
6038 case MONO_TYPE_VALUETYPE
:
6039 case MONO_TYPE_ARRAY
:
6040 case MONO_TYPE_SZARRAY
:
6041 case MONO_TYPE_STRING
:
6042 case MONO_TYPE_BOOLEAN
:
6043 tmp_locals
[i
] = mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
6052 if (target_handle
) {
6053 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
6054 mono_mb_emit_icall (mb
, mono_gchandle_get_target_internal
);
6057 g_assert_not_reached ();
6059 } else if (closed
) {
6060 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
6061 mono_mb_emit_icall (mb
, mono_gchandle_get_target_internal
);
6064 for (i
= 0; i
< sig
->param_count
; i
++) {
6065 MonoType
*t
= sig
->params
[i
];
6067 if (tmp_locals
[i
]) {
6069 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
6071 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
6074 mono_mb_emit_ldarg (mb
, i
);
6077 /* ret = method (...) */
6078 mono_mb_emit_managed_call (mb
, method
, NULL
);
6080 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
6081 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
6082 mono_class_init_internal (klass
);
6083 if (!(mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
))) {
6084 /* This is used by get_marshal_cb ()->emit_marshal_vtype (), but it needs to go right before the call */
6085 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6086 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
6087 mono_mb_emit_stloc (mb
, m
->vtaddr_var
);
6091 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
6092 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6093 } else if (!sig
->ret
->byref
) {
6094 switch (sig
->ret
->type
) {
6095 case MONO_TYPE_VOID
:
6097 case MONO_TYPE_BOOLEAN
:
6100 case MONO_TYPE_CHAR
:
6112 case MONO_TYPE_OBJECT
:
6113 mono_mb_emit_stloc (mb
, 3);
6115 case MONO_TYPE_STRING
:
6116 csig
->ret
= int_type
;
6117 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6119 case MONO_TYPE_VALUETYPE
:
6120 case MONO_TYPE_CLASS
:
6121 case MONO_TYPE_SZARRAY
:
6122 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6125 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
6126 g_assert_not_reached ();
6129 mono_mb_emit_stloc (mb
, 3);
6132 /* Convert byref arguments back */
6133 for (i
= 0; i
< sig
->param_count
; i
++) {
6134 MonoType
*t
= sig
->params
[i
];
6135 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
6137 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
6138 mono_emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6140 else if (t
->byref
) {
6142 case MONO_TYPE_CLASS
:
6143 case MONO_TYPE_VALUETYPE
:
6144 case MONO_TYPE_OBJECT
:
6145 case MONO_TYPE_STRING
:
6146 case MONO_TYPE_BOOLEAN
:
6147 mono_emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6153 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
6154 /* The [Out] information is encoded in the delegate signature */
6156 case MONO_TYPE_SZARRAY
:
6157 case MONO_TYPE_CLASS
:
6158 case MONO_TYPE_VALUETYPE
:
6159 mono_emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6162 g_assert_not_reached ();
6167 /* mono_threads_detach_coop (orig_domain, &attach_cookie); */
6168 mono_mb_emit_ldloc (mb
, orig_domain
);
6169 mono_mb_emit_ldloc_addr (mb
, attach_cookie
);
6170 /* Special cased in interpreter, keep in sync */
6171 mono_mb_emit_icall (mb
, mono_threads_detach_coop
);
6174 if (m
->retobj_var
) {
6175 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
6176 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6177 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
6180 if (!MONO_TYPE_IS_VOID (sig
->ret
))
6181 mono_mb_emit_ldloc (mb
, 3);
6182 mono_mb_emit_byte (mb
, CEE_RET
);
6190 emit_struct_to_ptr_ilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
6192 MonoType
*int_type
= mono_get_int_type ();
6193 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
6194 if (m_class_is_blittable (klass
)) {
6195 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6196 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6197 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6198 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
6199 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6200 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6203 /* allocate local 0 (pointer) src_ptr */
6204 mono_mb_add_local (mb
, int_type
);
6205 /* allocate local 1 (pointer) dst_ptr */
6206 mono_mb_add_local (mb
, int_type
);
6207 /* allocate local 2 (boolean) delete_old */
6208 mono_mb_add_local (mb
, boolean_type
);
6209 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
6210 mono_mb_emit_stloc (mb
, 2);
6212 /* initialize src_ptr to point to the start of object data */
6213 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6214 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6215 mono_mb_emit_stloc (mb
, 0);
6217 /* initialize dst_ptr */
6218 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6219 mono_mb_emit_stloc (mb
, 1);
6221 emit_struct_conv (mb
, klass
, FALSE
);
6224 mono_mb_emit_byte (mb
, CEE_RET
);
6228 emit_ptr_to_struct_ilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
6230 MonoType
*int_type
= mono_get_int_type ();
6231 if (m_class_is_blittable (klass
)) {
6232 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6233 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6234 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6235 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
6236 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6237 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6240 /* allocate local 0 (pointer) src_ptr */
6241 mono_mb_add_local (mb
, int_type
);
6242 /* allocate local 1 (pointer) dst_ptr */
6243 mono_mb_add_local (mb
, m_class_get_this_arg (klass
));
6245 /* initialize src_ptr to point to the start of object data */
6246 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6247 mono_mb_emit_stloc (mb
, 0);
6249 /* initialize dst_ptr */
6250 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6251 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6252 mono_mb_emit_stloc (mb
, 1);
6254 emit_struct_conv (mb
, klass
, TRUE
);
6257 mono_mb_emit_byte (mb
, CEE_RET
);
6261 emit_create_string_hack_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
6264 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6265 for (i
= 1; i
<= csig
->param_count
; i
++)
6266 mono_mb_emit_ldarg (mb
, i
);
6267 mono_mb_emit_managed_call (mb
, res
, NULL
);
6268 mono_mb_emit_byte (mb
, CEE_RET
);
6271 /* How the arguments of an icall should be wrapped */
6273 /* Don't wrap at all, pass the argument as is */
6274 ICALL_HANDLES_WRAP_NONE
,
6275 /* Wrap the argument in an object handle, pass the handle to the icall */
6276 ICALL_HANDLES_WRAP_OBJ
,
6277 /* Wrap the argument in an object handle, pass the handle to the icall,
6278 write the value out from the handle when the icall returns */
6279 ICALL_HANDLES_WRAP_OBJ_INOUT
,
6280 /* Initialized an object handle to null, pass to the icalls,
6281 write the value out from the handle when the icall returns */
6282 ICALL_HANDLES_WRAP_OBJ_OUT
,
6283 /* Wrap the argument (a valuetype reference) in a handle to pin its
6284 enclosing object, but pass the raw reference to the icall. This is
6285 also how we pass byref generic parameter arguments to generic method
6286 icalls (eg, System.Array:GetGenericValueImpl<T>(int idx, T out value)) */
6287 ICALL_HANDLES_WRAP_VALUETYPE_REF
,
6291 IcallHandlesWrap wrap
;
6292 // If wrap is OBJ_OUT or OBJ_INOUT this is >= 0 and holds the referenced managed object,
6293 // in case the actual parameter refers to a native frame.
6294 // Otherwise it is -1.
6296 } IcallHandlesLocal
;
6299 * Describes how to wrap the given parameter.
6302 static IcallHandlesWrap
6303 signature_param_uses_handles (MonoMethodSignature
*sig
, MonoMethodSignature
*generic_sig
, int param
)
6305 /* If there is a generic parameter that isn't passed byref, we don't
6306 * know how to pass it to an icall that expects some arguments to be
6307 * wrapped in handles: if the actual argument type is a reference type
6308 * we'd need to wrap it in a handle, otherwise we'd want to pass it as is.
6310 /* FIXME: There is one icall that will some day cause us trouble here:
6311 * System.Threading.Interlocked:CompareExchange<T> (ref T location, T
6312 * new, T old) where T:class. What will save us is that 'T:class'
6313 * constraint. We should eventually relax the assertion, below, to
6314 * allow generic parameters that are constrained to be reference types.
6316 g_assert (!generic_sig
|| !mono_type_is_generic_parameter (generic_sig
->params
[param
]));
6318 /* If the parameter in the generic version of the method signature is a
6319 * byref type variable T&, pass the corresponding argument by pinning
6320 * the memory and passing the raw pointer to the icall. Note that we
6321 * do this even if the actual instantiation is a byref reference type
6322 * like string& since the C code for the icall has to work uniformly
6323 * for both valuetypes and reference types.
6325 if (generic_sig
&& mono_type_is_byref (generic_sig
->params
[param
]) &&
6326 (generic_sig
->params
[param
]->type
== MONO_TYPE_VAR
|| generic_sig
->params
[param
]->type
== MONO_TYPE_MVAR
))
6327 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
6329 if (MONO_TYPE_IS_REFERENCE (sig
->params
[param
])) {
6330 if (mono_signature_param_is_out (sig
, param
))
6331 return ICALL_HANDLES_WRAP_OBJ_OUT
;
6332 else if (mono_type_is_byref (sig
->params
[param
]))
6333 return ICALL_HANDLES_WRAP_OBJ_INOUT
;
6335 return ICALL_HANDLES_WRAP_OBJ
;
6336 } else if (mono_type_is_byref (sig
->params
[param
]))
6337 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
6339 return ICALL_HANDLES_WRAP_NONE
;
6343 emit_native_icall_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*piinfo
)
6346 MonoMethodSignature
*call_sig
= csig
;
6347 gboolean uses_handles
= FALSE
;
6348 gboolean foreign_icall
= FALSE
;
6349 IcallHandlesLocal
*handles_locals
= NULL
;
6350 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
6351 gboolean need_gc_safe
= FALSE
;
6352 GCSafeTransitionBuilder gc_safe_transition_builder
;
6354 (void) mono_lookup_internal_call_full (method
, FALSE
, &uses_handles
, &foreign_icall
);
6356 if (G_UNLIKELY (foreign_icall
)) {
6357 /* FIXME: we only want the transitions for hybrid suspend. Q: What to do about AOT? */
6358 need_gc_safe
= gc_safe_transition_builder_init (&gc_safe_transition_builder
, mb
, FALSE
);
6361 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder
);
6366 * Add a null check since public icalls can be called with 'call' which
6367 * does no such check.
6369 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6370 const int pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6371 mono_mb_emit_exception (mb
, "NullReferenceException", NULL
);
6372 mono_mb_patch_branch (mb
, pos
);
6376 MonoMethodSignature
*generic_sig
= NULL
;
6378 if (method
->is_inflated
) {
6380 MonoMethod
*generic_method
= ((MonoMethodInflated
*)method
)->declaring
;
6381 generic_sig
= mono_method_signature_checked (generic_method
, error
);
6382 mono_error_assert_ok (error
);
6385 // Add a MonoError argument (due to a fragile test external/coreclr/tests/src/CoreMangLib/cti/system/weakreference/weakreferenceisaliveb.exe),
6386 // vs. on the native side.
6387 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
6388 call_sig
= mono_metadata_signature_alloc (get_method_image (method
), csig
->param_count
+ 1);
6389 call_sig
->param_count
= csig
->param_count
+ 1;
6390 call_sig
->ret
= csig
->ret
;
6391 call_sig
->pinvoke
= csig
->pinvoke
;
6393 /* TODO support adding wrappers to non-static struct methods */
6394 g_assert (!sig
->hasthis
|| !m_class_is_valuetype (mono_method_get_class (method
)));
6396 /* Add MonoError* param */
6397 MonoClass
* const error_class
= mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
6398 int const error_var
= mono_mb_add_local (mb
, m_class_get_byval_arg (error_class
));
6399 call_sig
->params
[csig
->param_count
] = mono_class_get_byref_type (error_class
);
6401 handles_locals
= g_new0 (IcallHandlesLocal
, csig
->param_count
);
6403 for (int i
= 0; i
< csig
->param_count
; ++i
) {
6404 // Determine which args need to be wrapped in handles and adjust icall signature.
6405 // Here, a handle is a pointer to a volatile local in a managed frame -- which is sufficient and efficient.
6406 const IcallHandlesWrap w
= signature_param_uses_handles (csig
, generic_sig
, i
);
6407 handles_locals
[i
].wrap
= w
;
6411 case ICALL_HANDLES_WRAP_OBJ
:
6412 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6413 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6414 call_sig
->params
[i
] = mono_class_get_byref_type (mono_class_from_mono_type_internal (csig
->params
[i
]));
6416 case ICALL_HANDLES_WRAP_NONE
:
6417 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6418 call_sig
->params
[i
] = csig
->params
[i
];
6421 g_assert_not_reached ();
6424 // Add a local var to hold the references for each out arg.
6426 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6427 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6428 // FIXME better type
6429 local
= mono_mb_add_local (mb
, mono_get_object_type ());
6431 if (!mb
->volatile_locals
) {
6432 gpointer mem
= mono_image_alloc0 (get_method_image (method
), mono_bitset_alloc_size (csig
->param_count
+ 1, 0));
6433 mb
->volatile_locals
= mono_bitset_mem_new (mem
, csig
->param_count
+ 1, 0);
6435 mono_bitset_set (mb
->volatile_locals
, local
);
6437 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6438 case ICALL_HANDLES_WRAP_OBJ
:
6439 if (!mb
->volatile_args
) {
6440 gpointer mem
= mono_image_alloc0 (get_method_image (method
), mono_bitset_alloc_size (csig
->param_count
+ 1, 0));
6441 mb
->volatile_args
= mono_bitset_mem_new (mem
, csig
->param_count
+ 1, 0);
6443 mono_bitset_set (mb
->volatile_args
, i
);
6445 case ICALL_HANDLES_WRAP_NONE
:
6448 g_assert_not_reached ();
6450 handles_locals
[i
].handle
= local
;
6452 // Load each argument. References into the managed heap get wrapped in handles.
6453 // Handles here are just pointers to managed volatile locals.
6455 case ICALL_HANDLES_WRAP_NONE
:
6456 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6458 mono_mb_emit_ldarg (mb
, i
);
6460 case ICALL_HANDLES_WRAP_OBJ
:
6462 mono_mb_emit_ldarg_addr (mb
, i
);
6464 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6465 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6466 // If parameter guaranteeably referred to a managed frame,
6467 // then could just be passthrough and volatile. Since
6468 // that cannot be guaranteed, use a managed volatile local intermediate.
6472 // localI = *argI_raw
6474 if (w
== ICALL_HANDLES_WRAP_OBJ_OUT
) {
6475 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6477 mono_mb_emit_ldarg (mb
, i
);
6478 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6480 mono_mb_emit_stloc (mb
, local
);
6481 mono_mb_emit_ldloc_addr (mb
, local
);
6484 g_assert_not_reached ();
6487 mono_mb_emit_ldloc_addr (mb
, error_var
);
6489 for (int i
= 0; i
< csig
->param_count
; i
++)
6490 mono_mb_emit_ldarg (mb
, i
);
6494 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder
, &piinfo
->method
, aot
);
6497 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6498 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
6499 mono_mb_emit_calli (mb
, call_sig
);
6501 g_assert (piinfo
->addr
);
6502 mono_mb_emit_native_call (mb
, call_sig
, piinfo
->addr
);
6506 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder
);
6508 // Copy back ObjOut and ObjInOut from locals through parameters.
6509 if (mb
->volatile_locals
) {
6510 g_assert (handles_locals
);
6511 for (int i
= 0; i
< csig
->param_count
; i
++) {
6512 const int local
= handles_locals
[i
].handle
;
6514 // *argI_raw = localI
6515 mono_mb_emit_ldarg (mb
, i
);
6516 mono_mb_emit_ldloc (mb
, local
);
6517 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6521 g_free (handles_locals
);
6524 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder
);
6526 if (check_exceptions
)
6527 emit_thread_interrupt_checkpoint (mb
);
6528 mono_mb_emit_byte (mb
, CEE_RET
);
6532 mb_emit_exception_ilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
6534 mono_mb_emit_exception_full (mb
, exc_nspace
, exc_name
, msg
);
6538 mb_emit_exception_for_error_ilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
6540 mono_mb_emit_exception_for_error (mb
, (MonoError
*)error
);
6544 emit_vtfixup_ftnptr_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
6546 for (int i
= 0; i
< param_count
; i
++)
6547 mono_mb_emit_ldarg (mb
, i
);
6549 if (type
& VTFIXUP_TYPE_CALL_MOST_DERIVED
)
6550 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
6552 mono_mb_emit_op (mb
, CEE_CALL
, method
);
6553 mono_mb_emit_byte (mb
, CEE_RET
);
6557 emit_icall_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
6559 MonoMethodSignature
*const sig
= callinfo
->sig
;
6562 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6564 for (int i
= 0; i
< sig
->param_count
; i
++)
6565 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
6567 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6568 mono_mb_emit_byte (mb
, CEE_MONO_JIT_ICALL_ADDR
);
6569 mono_mb_emit_i4 (mb
, mono_jit_icall_info_index (callinfo
));
6570 mono_mb_emit_calli (mb
, csig2
);
6571 if (check_exceptions
)
6572 emit_thread_interrupt_checkpoint (mb
);
6573 mono_mb_emit_byte (mb
, CEE_RET
);
6577 emit_return_ilgen (MonoMethodBuilder
*mb
)
6579 mono_mb_emit_byte (mb
, CEE_RET
);
6583 mono_marshal_ilgen_init (void)
6585 MonoMarshalCallbacks cb
;
6586 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6587 cb
.emit_marshal_array
= emit_marshal_array_ilgen
;
6588 cb
.emit_marshal_boolean
= emit_marshal_boolean_ilgen
;
6589 cb
.emit_marshal_ptr
= emit_marshal_ptr_ilgen
;
6590 cb
.emit_marshal_char
= emit_marshal_char_ilgen
;
6591 cb
.emit_marshal_scalar
= emit_marshal_scalar_ilgen
;
6592 cb
.emit_marshal_custom
= emit_marshal_custom_ilgen
;
6593 cb
.emit_marshal_asany
= emit_marshal_asany_ilgen
;
6594 cb
.emit_marshal_vtype
= emit_marshal_vtype_ilgen
;
6595 cb
.emit_marshal_string
= emit_marshal_string_ilgen
;
6596 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_ilgen
;
6597 cb
.emit_marshal_handleref
= emit_marshal_handleref_ilgen
;
6598 cb
.emit_marshal_object
= emit_marshal_object_ilgen
;
6599 cb
.emit_marshal_variant
= emit_marshal_variant_ilgen
;
6600 cb
.emit_castclass
= emit_castclass_ilgen
;
6601 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_ilgen
;
6602 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_ilgen
;
6603 cb
.emit_isinst
= emit_isinst_ilgen
;
6604 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_ilgen
;
6605 cb
.emit_stelemref
= emit_stelemref_ilgen
;
6606 cb
.emit_array_address
= emit_array_address_ilgen
;
6607 cb
.emit_native_wrapper
= emit_native_wrapper_ilgen
;
6608 cb
.emit_managed_wrapper
= emit_managed_wrapper_ilgen
;
6609 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_ilgen
;
6610 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_ilgen
;
6611 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_ilgen
;
6612 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_ilgen
;
6613 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_ilgen
;
6614 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_ilgen
;
6615 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_ilgen
;
6616 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_ilgen
;
6617 cb
.emit_generic_array_helper
= emit_generic_array_helper_ilgen
;
6618 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_ilgen
;
6619 cb
.emit_create_string_hack
= emit_create_string_hack_ilgen
;
6620 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_ilgen
;
6621 cb
.emit_icall_wrapper
= emit_icall_wrapper_ilgen
;
6622 cb
.emit_return
= emit_return_ilgen
;
6623 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_ilgen
;
6624 cb
.mb_skip_visibility
= mb_skip_visibility_ilgen
;
6625 cb
.mb_set_dynamic
= mb_set_dynamic_ilgen
;
6626 cb
.mb_emit_exception
= mb_emit_exception_ilgen
;
6627 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_ilgen
;
6628 cb
.mb_emit_byte
= mb_emit_byte_ilgen
;
6629 mono_install_marshal_callbacks (&cb
);