3 * Copyright 2018 Microsoft
4 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include "metadata/method-builder-ilgen.h"
12 #include "metadata/method-builder-ilgen-internals.h"
16 #include "metadata/marshal.h"
17 #include "metadata/marshal-internals.h"
18 #include "metadata/marshal-ilgen.h"
19 #include "metadata/tabledefs.h"
20 #include "metadata/exception.h"
21 #include "metadata/appdomain.h"
22 #include "mono/metadata/abi-details.h"
23 #include "mono/metadata/class-abi-details.h"
24 #include "mono/metadata/class-init.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/class-internals.h"
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/domain-internals.h"
31 #include "mono/metadata/gc-internals.h"
32 #include "mono/metadata/threads-types.h"
33 #include "mono/metadata/string-icalls.h"
34 #include "mono/metadata/attrdefs.h"
35 #include "mono/metadata/cominterop.h"
36 #include "mono/metadata/remoting.h"
37 #include "mono/metadata/reflection-internals.h"
38 #include "mono/metadata/threadpool.h"
39 #include "mono/metadata/handle.h"
40 #include "mono/metadata/custom-attrs-internals.h"
41 #include "mono/metadata/icall-internals.h"
42 #include "mono/utils/mono-counters.h"
43 #include "mono/utils/mono-tls.h"
44 #include "mono/utils/mono-memory-model.h"
45 #include "mono/utils/atomic.h"
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/mono-threads-coop.h>
48 #include <mono/utils/mono-error-internals.h>
51 #include "icall-decl.h"
53 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
57 #include "mono/cil/opcode.def"
63 is_in (const MonoType
*t
)
65 const guint32 attrs
= t
->attrs
;
66 return (attrs
& PARAM_ATTRIBUTE_IN
) || !(attrs
& PARAM_ATTRIBUTE_OUT
);
70 is_out (const MonoType
*t
)
72 const guint32 attrs
= t
->attrs
;
73 return (attrs
& PARAM_ATTRIBUTE_OUT
) || !(attrs
& PARAM_ATTRIBUTE_IN
);
76 static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute
, "System.Runtime.CompilerServices", "FixedBufferAttribute");
77 static GENERATE_GET_CLASS_WITH_CACHE (date_time
, "System", "DateTime");
78 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler
, "System.Runtime.InteropServices", "ICustomMarshaler");
79 static GENERATE_TRY_GET_CLASS_WITH_CACHE (marshal
, "System.Runtime.InteropServices", "Marshal");
81 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
82 static MonoMethod
*sh_dangerous_add_ref
;
83 static MonoMethod
*sh_dangerous_release
;
86 get_method_nofail (MonoClass
*klass
, const char *method_name
, int num_params
, int flags
)
90 method
= mono_class_get_method_from_name_checked (klass
, method_name
, num_params
, flags
, error
);
91 mono_error_assert_ok (error
);
92 g_assertf (method
, "Could not lookup method %s in %s", method_name
, m_class_get_name (klass
));
97 init_safe_handle (void)
99 sh_dangerous_add_ref
= get_method_nofail (
100 mono_class_try_get_safehandle_class (), "DangerousAddRef", 1, 0);
101 sh_dangerous_release
= get_method_nofail (
102 mono_class_try_get_safehandle_class (), "DangerousRelease", 0, 0);
106 get_method_image (MonoMethod
*method
)
108 return m_class_get_image (method
->klass
);
112 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
);
115 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
, int offset_of_first_child_field
, MonoMarshalNative string_encoding
);
119 * \param mb the MethodBuilder
122 * Creates a copy of the string \p s that can be referenced from the IL of \c mb.
124 * \returns a pointer to the new string which is owned by the method builder
127 mono_mb_strdup (MonoMethodBuilder
*mb
, const char *s
)
131 res
= mono_image_strdup (get_method_image (mb
->method
), s
);
140 * mono_mb_emit_exception_marshal_directive:
142 * This function assumes ownership of MSG, which should be malloc-ed.
145 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder
*mb
, char *msg
)
147 char *s
= mono_mb_strdup (mb
, msg
);
149 mono_mb_emit_exception_full (mb
, "System.Runtime.InteropServices", "MarshalDirectiveException", s
);
153 offset_of_first_nonstatic_field (MonoClass
*klass
)
156 int fcount
= mono_class_get_field_count (klass
);
157 mono_class_setup_fields (klass
);
158 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
159 for (i
= 0; i
< fcount
; i
++) {
160 if (!(klass_fields
[i
].type
->attrs
& FIELD_ATTRIBUTE_STATIC
) && !mono_field_is_deleted (&klass_fields
[i
]))
161 return klass_fields
[i
].offset
- MONO_ABI_SIZEOF (MonoObject
);
168 get_fixed_buffer_attr (MonoClassField
*field
, MonoType
**out_etype
, int *out_len
)
171 MonoCustomAttrInfo
*cinfo
;
172 MonoCustomAttrEntry
*attr
;
175 cinfo
= mono_custom_attrs_from_field_checked (field
->parent
, field
, error
);
180 for (aindex
= 0; aindex
< cinfo
->num_attrs
; ++aindex
) {
181 MonoClass
*ctor_class
= cinfo
->attrs
[aindex
].ctor
->klass
;
182 if (mono_class_has_parent (ctor_class
, mono_class_get_fixed_buffer_attribute_class ())) {
183 attr
= &cinfo
->attrs
[aindex
];
189 gpointer
*typed_args
, *named_args
;
190 CattrNamedArg
*arginfo
;
193 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults
.corlib
, attr
->ctor
, attr
->data
, attr
->data_size
,
194 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
197 *out_etype
= (MonoType
*)typed_args
[0];
198 *out_len
= *(gint32
*)typed_args
[1];
199 g_free (typed_args
[1]);
204 if (cinfo
&& !cinfo
->cached
)
205 mono_custom_attrs_free (cinfo
);
210 emit_fixed_buf_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoType
*etype
, int len
, gboolean to_object
, int *out_usize
)
212 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
213 MonoClass
*eklass
= mono_class_from_mono_type_internal (etype
);
216 esize
= mono_class_native_size (eklass
, NULL
);
218 MonoMarshalNative string_encoding
= m_class_is_unicode (klass
) ? MONO_NATIVE_LPWSTR
: MONO_NATIVE_LPSTR
;
219 int usize
= mono_class_value_size (eklass
, NULL
);
220 int msize
= mono_class_value_size (eklass
, NULL
);
222 //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), em_class_is_blittable (klass), string_encoding);
224 if (m_class_is_blittable (eklass
)) {
225 /* copy the elements */
226 mono_mb_emit_ldloc (mb
, 1);
227 mono_mb_emit_ldloc (mb
, 0);
228 mono_mb_emit_icon (mb
, len
* esize
);
229 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
230 mono_mb_emit_byte (mb
, CEE_CPBLK
);
233 guint32 label2
, label3
;
235 /* Emit marshalling loop */
236 MonoType
*int_type
= mono_get_int_type ();
237 index_var
= mono_mb_add_local (mb
, int_type
);
238 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
239 mono_mb_emit_stloc (mb
, index_var
);
242 label2
= mono_mb_get_label (mb
);
243 mono_mb_emit_ldloc (mb
, index_var
);
244 mono_mb_emit_icon (mb
, len
);
245 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
247 /* src/dst is already set */
249 /* Do the conversion */
250 MonoTypeEnum t
= etype
->type
;
256 case MONO_TYPE_BOOLEAN
:
265 mono_mb_emit_ldloc (mb
, 1);
266 mono_mb_emit_ldloc (mb
, 0);
267 if (t
== MONO_TYPE_CHAR
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
269 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
270 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
272 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
273 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
277 mono_mb_emit_byte (mb
, mono_type_to_ldind (etype
));
278 mono_mb_emit_byte (mb
, mono_type_to_stind (etype
));
282 g_assert_not_reached ();
287 mono_mb_emit_add_to_local (mb
, 0, usize
);
288 mono_mb_emit_add_to_local (mb
, 1, msize
);
290 mono_mb_emit_add_to_local (mb
, 0, msize
);
291 mono_mb_emit_add_to_local (mb
, 1, usize
);
295 mono_mb_emit_add_to_local (mb
, index_var
, 1);
297 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
299 mono_mb_patch_branch (mb
, label3
);
302 *out_usize
= usize
* len
;
306 emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
309 case MONO_MARSHAL_CONV_BOOL_I4
:
310 mono_mb_emit_ldloc (mb
, 1);
311 mono_mb_emit_ldloc (mb
, 0);
312 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
313 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
314 mono_mb_emit_byte (mb
, 3);
315 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
316 mono_mb_emit_byte (mb
, CEE_BR_S
);
317 mono_mb_emit_byte (mb
, 1);
318 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
319 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
321 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
322 mono_mb_emit_ldloc (mb
, 1);
323 mono_mb_emit_ldloc (mb
, 0);
324 mono_mb_emit_byte (mb
, CEE_LDIND_I2
);
325 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
326 mono_mb_emit_byte (mb
, 3);
327 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
328 mono_mb_emit_byte (mb
, CEE_BR_S
);
329 mono_mb_emit_byte (mb
, 1);
330 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
331 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
333 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
334 MonoClass
*eklass
= NULL
;
337 if (type
->type
== MONO_TYPE_SZARRAY
) {
338 eklass
= type
->data
.klass
;
340 g_assert_not_reached ();
343 esize
= mono_class_native_size (eklass
, NULL
);
345 /* create a new array */
346 mono_mb_emit_ldloc (mb
, 1);
347 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
348 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
349 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
351 if (m_class_is_blittable (eklass
)) {
352 /* copy the elements */
353 mono_mb_emit_ldloc (mb
, 1);
354 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
355 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
356 mono_mb_emit_byte (mb
, CEE_ADD
);
357 mono_mb_emit_ldloc (mb
, 0);
358 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
359 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
360 mono_mb_emit_byte (mb
, CEE_CPBLK
);
363 int array_var
, src_var
, dst_var
, index_var
;
364 guint32 label2
, label3
;
366 MonoType
*int_type
= mono_get_int_type ();
367 array_var
= mono_mb_add_local (mb
, mono_get_object_type ());
368 src_var
= mono_mb_add_local (mb
, int_type
);
369 dst_var
= mono_mb_add_local (mb
, int_type
);
372 mono_mb_emit_ldloc (mb
, 1);
373 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
374 mono_mb_emit_stloc (mb
, array_var
);
376 /* save the old src pointer */
377 mono_mb_emit_ldloc (mb
, 0);
378 mono_mb_emit_stloc (mb
, src_var
);
379 /* save the old dst pointer */
380 mono_mb_emit_ldloc (mb
, 1);
381 mono_mb_emit_stloc (mb
, dst_var
);
383 /* Emit marshalling loop */
384 index_var
= mono_mb_add_local (mb
, int_type
);
385 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
386 mono_mb_emit_stloc (mb
, index_var
);
389 label2
= mono_mb_get_label (mb
);
390 mono_mb_emit_ldloc (mb
, index_var
);
391 mono_mb_emit_ldloc (mb
, array_var
);
392 mono_mb_emit_byte (mb
, CEE_LDLEN
);
393 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
395 /* src is already set */
398 mono_mb_emit_ldloc (mb
, array_var
);
399 mono_mb_emit_ldloc (mb
, index_var
);
400 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
401 mono_mb_emit_stloc (mb
, 1);
403 /* Do the conversion */
404 emit_struct_conv (mb
, eklass
, TRUE
);
407 mono_mb_emit_add_to_local (mb
, index_var
, 1);
409 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
411 mono_mb_patch_branch (mb
, label3
);
413 /* restore the old src pointer */
414 mono_mb_emit_ldloc (mb
, src_var
);
415 mono_mb_emit_stloc (mb
, 0);
416 /* restore the old dst pointer */
417 mono_mb_emit_ldloc (mb
, dst_var
);
418 mono_mb_emit_stloc (mb
, 1);
422 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
423 MonoClass
*eclass
= mono_defaults
.char_class
;
425 /* create a new array */
426 mono_mb_emit_ldloc (mb
, 1);
427 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
428 mono_mb_emit_op (mb
, CEE_NEWARR
, eclass
);
429 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
431 mono_mb_emit_ldloc (mb
, 1);
432 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
433 mono_mb_emit_ldloc (mb
, 0);
434 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
435 mono_mb_emit_icall (mb
, mono_byvalarray_to_byte_array
);
438 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
439 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
440 mono_mb_emit_ldloc (mb
, 1);
441 mono_mb_emit_ldloc (mb
, 0);
442 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
443 mono_mb_emit_icall (mb
, mono_string_from_byvalstr
);
445 mono_mb_emit_ldloc (mb
, 1);
446 mono_mb_emit_ldloc (mb
, 0);
447 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
449 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
451 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
452 if (mspec
&& mspec
->native
== MONO_NATIVE_BYVALTSTR
&& mspec
->data
.array_data
.num_elem
) {
453 mono_mb_emit_ldloc (mb
, 1);
454 mono_mb_emit_ldloc (mb
, 0);
455 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
456 mono_mb_emit_icall (mb
, mono_string_from_byvalwstr
);
458 mono_mb_emit_ldloc (mb
, 1);
459 mono_mb_emit_ldloc (mb
, 0);
460 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
462 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
464 case MONO_MARSHAL_CONV_STR_LPTSTR
:
465 mono_mb_emit_ldloc (mb
, 1);
466 mono_mb_emit_ldloc (mb
, 0);
467 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
469 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
471 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
473 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
476 // In Mono historically LPSTR was treated as a UTF8STR
477 case MONO_MARSHAL_CONV_STR_LPSTR
:
478 case MONO_MARSHAL_CONV_STR_UTF8STR
:
479 mono_mb_emit_ldloc (mb
, 1);
480 mono_mb_emit_ldloc (mb
, 0);
481 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
482 mono_mb_emit_icall (mb
, ves_icall_string_new_wrapper
);
483 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
485 case MONO_MARSHAL_CONV_STR_LPWSTR
:
486 mono_mb_emit_ldloc (mb
, 1);
487 mono_mb_emit_ldloc (mb
, 0);
488 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
489 mono_mb_emit_icall (mb
, ves_icall_mono_string_from_utf16
);
490 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
492 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
493 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
494 int src_var
, dst_var
;
496 MonoType
*int_type
= mono_get_int_type ();
497 src_var
= mono_mb_add_local (mb
, int_type
);
498 dst_var
= mono_mb_add_local (mb
, int_type
);
500 /* *dst = new object */
501 mono_mb_emit_ldloc (mb
, 1);
502 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
503 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
504 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
506 /* save the old src pointer */
507 mono_mb_emit_ldloc (mb
, 0);
508 mono_mb_emit_stloc (mb
, src_var
);
509 /* save the old dst pointer */
510 mono_mb_emit_ldloc (mb
, 1);
511 mono_mb_emit_stloc (mb
, dst_var
);
513 /* dst = pointer to newly created object data */
514 mono_mb_emit_ldloc (mb
, 1);
515 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
516 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
517 mono_mb_emit_byte (mb
, CEE_ADD
);
518 mono_mb_emit_stloc (mb
, 1);
520 emit_struct_conv (mb
, klass
, TRUE
);
522 /* restore the old src pointer */
523 mono_mb_emit_ldloc (mb
, src_var
);
524 mono_mb_emit_stloc (mb
, 0);
525 /* restore the old dst pointer */
526 mono_mb_emit_ldloc (mb
, dst_var
);
527 mono_mb_emit_stloc (mb
, 1);
530 case MONO_MARSHAL_CONV_DEL_FTN
: {
531 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
533 mono_mb_emit_ldloc (mb
, 1);
534 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
535 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
536 mono_mb_emit_ldloc (mb
, 0);
537 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
538 mono_mb_emit_icall (mb
, mono_ftnptr_to_delegate
);
539 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
542 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
: {
543 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
)));
544 mono_mb_emit_exception_marshal_directive (mb
, msg
);
549 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
550 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
551 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
552 mono_cominterop_emit_ptr_to_object_conv (mb
, type
, conv
, mspec
);
554 #endif /* DISABLE_COM */
556 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
558 * Passing SafeHandles as ref does not allow the unmanaged code
559 * to change the SafeHandle value. If the value is changed,
560 * we should issue a diagnostic exception (NotSupportedException)
561 * that informs the user that changes to handles in unmanaged code
564 * Since we currently have no access to the original
565 * SafeHandle that was used during the marshalling,
566 * for now we just ignore this, and ignore/discard any
567 * changes that might have happened to the handle.
572 case MONO_MARSHAL_CONV_HANDLEREF
: {
574 * Passing HandleRefs in a struct that is ref()ed does not
575 * copy the values back to the HandleRef
580 case MONO_MARSHAL_CONV_STR_BSTR
:
581 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
582 case MONO_MARSHAL_CONV_STR_TBSTR
:
583 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
585 char *msg
= g_strdup_printf ("marshaling conversion %d not implemented", conv
);
587 mono_mb_emit_exception_marshal_directive (mb
, msg
);
593 static MonoJitICallId
594 conv_to_icall (MonoMarshalConv conv
, int *ind_store_type
)
596 // FIXME This or its caller might be a good place to inline some
597 // of the wrapper logic. In particular, to produce
598 // volatile stack-based handles. Being data-driven,
603 ind_store_type
= &dummy
;
604 *ind_store_type
= CEE_STIND_I
;
606 case MONO_MARSHAL_CONV_STR_LPWSTR
:
607 return MONO_JIT_ICALL_mono_marshal_string_to_utf16
;
608 case MONO_MARSHAL_CONV_LPWSTR_STR
:
609 *ind_store_type
= CEE_STIND_REF
;
610 return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16
;
611 case MONO_MARSHAL_CONV_LPTSTR_STR
:
612 *ind_store_type
= CEE_STIND_REF
;
613 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
614 case MONO_MARSHAL_CONV_UTF8STR_STR
:
615 case MONO_MARSHAL_CONV_LPSTR_STR
:
616 *ind_store_type
= CEE_STIND_REF
;
617 return MONO_JIT_ICALL_ves_icall_string_new_wrapper
;
618 case MONO_MARSHAL_CONV_STR_LPTSTR
:
620 return MONO_JIT_ICALL_mono_marshal_string_to_utf16
;
622 return MONO_JIT_ICALL_mono_string_to_utf8str
;
624 // In Mono historically LPSTR was treated as a UTF8STR
625 case MONO_MARSHAL_CONV_STR_UTF8STR
:
626 case MONO_MARSHAL_CONV_STR_LPSTR
:
627 return MONO_JIT_ICALL_mono_string_to_utf8str
;
628 case MONO_MARSHAL_CONV_STR_BSTR
:
629 return MONO_JIT_ICALL_mono_string_to_bstr
;
630 case MONO_MARSHAL_CONV_BSTR_STR
:
631 *ind_store_type
= CEE_STIND_REF
;
632 return MONO_JIT_ICALL_mono_string_from_bstr_icall
;
633 case MONO_MARSHAL_CONV_STR_TBSTR
:
634 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
635 return MONO_JIT_ICALL_mono_string_to_ansibstr
;
636 case MONO_MARSHAL_CONV_SB_UTF8STR
:
637 case MONO_MARSHAL_CONV_SB_LPSTR
:
638 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
639 case MONO_MARSHAL_CONV_SB_LPTSTR
:
641 return MONO_JIT_ICALL_mono_string_builder_to_utf16
;
643 return MONO_JIT_ICALL_mono_string_builder_to_utf8
;
645 case MONO_MARSHAL_CONV_SB_LPWSTR
:
646 return MONO_JIT_ICALL_mono_string_builder_to_utf16
;
647 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
648 return MONO_JIT_ICALL_mono_array_to_savearray
;
649 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
650 return MONO_JIT_ICALL_mono_array_to_lparray
;
651 case MONO_MARSHAL_FREE_LPARRAY
:
652 return MONO_JIT_ICALL_mono_free_lparray
;
653 case MONO_MARSHAL_CONV_DEL_FTN
:
654 return MONO_JIT_ICALL_mono_delegate_to_ftnptr
;
655 case MONO_MARSHAL_CONV_FTN_DEL
:
656 *ind_store_type
= CEE_STIND_REF
;
657 return MONO_JIT_ICALL_mono_ftnptr_to_delegate
;
658 case MONO_MARSHAL_CONV_UTF8STR_SB
:
659 case MONO_MARSHAL_CONV_LPSTR_SB
:
660 *ind_store_type
= CEE_STIND_REF
;
661 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
662 case MONO_MARSHAL_CONV_LPTSTR_SB
:
663 *ind_store_type
= CEE_STIND_REF
;
665 return MONO_JIT_ICALL_mono_string_utf16_to_builder
;
667 return MONO_JIT_ICALL_mono_string_utf8_to_builder
;
669 case MONO_MARSHAL_CONV_LPWSTR_SB
:
670 *ind_store_type
= CEE_STIND_REF
;
671 return MONO_JIT_ICALL_mono_string_utf16_to_builder
;
672 case MONO_MARSHAL_FREE_ARRAY
:
673 return MONO_JIT_ICALL_mono_marshal_free_array
;
674 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
675 return MONO_JIT_ICALL_mono_string_to_byvalstr
;
676 case MONO_MARSHAL_CONV_STR_BYVALWSTR
:
677 return MONO_JIT_ICALL_mono_string_to_byvalwstr
;
679 g_assert_not_reached ();
682 return MONO_JIT_ICALL_ZeroIsReserved
;
686 emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
692 case MONO_MARSHAL_CONV_BOOL_I4
:
693 mono_mb_emit_ldloc (mb
, 1);
694 mono_mb_emit_ldloc (mb
, 0);
695 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
696 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
698 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL
:
699 mono_mb_emit_ldloc (mb
, 1);
700 mono_mb_emit_ldloc (mb
, 0);
701 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
702 mono_mb_emit_byte (mb
, CEE_NEG
);
703 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
705 // In Mono historically LPSTR was treated as a UTF8STR
706 case MONO_MARSHAL_CONV_STR_UTF8STR
:
707 case MONO_MARSHAL_CONV_STR_LPWSTR
:
708 case MONO_MARSHAL_CONV_STR_LPSTR
:
709 case MONO_MARSHAL_CONV_STR_LPTSTR
:
710 case MONO_MARSHAL_CONV_STR_BSTR
:
711 case MONO_MARSHAL_CONV_STR_ANSIBSTR
:
712 case MONO_MARSHAL_CONV_STR_TBSTR
: {
715 /* free space if free == true */
716 mono_mb_emit_ldloc (mb
, 2);
717 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
718 mono_mb_emit_ldloc (mb
, 1);
719 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
720 mono_mb_emit_icall (mb
, g_free
); // aka monoeg_g_free
721 mono_mb_patch_short_branch (mb
, pos
);
723 mono_mb_emit_ldloc (mb
, 1);
724 mono_mb_emit_ldloc (mb
, 0);
725 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
726 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
727 mono_mb_emit_byte (mb
, stind_op
);
730 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY
:
731 case MONO_MARSHAL_CONV_ARRAY_LPARRAY
:
732 case MONO_MARSHAL_CONV_DEL_FTN
:
733 mono_mb_emit_ldloc (mb
, 1);
734 mono_mb_emit_ldloc (mb
, 0);
735 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
736 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
737 mono_mb_emit_byte (mb
, stind_op
);
739 case MONO_MARSHAL_CONV_STR_BYVALSTR
:
740 case MONO_MARSHAL_CONV_STR_BYVALWSTR
: {
743 mono_mb_emit_ldloc (mb
, 1); /* dst */
744 mono_mb_emit_ldloc (mb
, 0);
745 mono_mb_emit_byte (mb
, CEE_LDIND_REF
); /* src String */
746 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
747 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
750 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY
: {
751 MonoClass
*eklass
= NULL
;
754 if (type
->type
== MONO_TYPE_SZARRAY
) {
755 eklass
= type
->data
.klass
;
756 } else if (type
->type
== MONO_TYPE_ARRAY
) {
757 eklass
= type
->data
.array
->eklass
;
758 g_assert(m_class_is_blittable (eklass
));
760 g_assert_not_reached ();
763 if (m_class_is_valuetype (eklass
))
764 esize
= mono_class_native_size (eklass
, NULL
);
766 esize
= TARGET_SIZEOF_VOID_P
;
768 mono_mb_emit_ldloc (mb
, 0);
769 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
770 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
772 if (m_class_is_blittable (eklass
)) {
773 mono_mb_emit_ldloc (mb
, 1);
774 mono_mb_emit_ldloc (mb
, 0);
775 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
776 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
777 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
* esize
);
778 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
779 mono_mb_emit_byte (mb
, CEE_CPBLK
);
781 int array_var
, src_var
, dst_var
, index_var
;
782 guint32 label2
, label3
;
784 MonoType
*int_type
= mono_get_int_type ();
785 MonoType
*object_type
= mono_get_object_type ();
786 array_var
= mono_mb_add_local (mb
, object_type
);
787 src_var
= mono_mb_add_local (mb
, int_type
);
788 dst_var
= mono_mb_add_local (mb
, int_type
);
791 mono_mb_emit_ldloc (mb
, 0);
792 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
793 mono_mb_emit_stloc (mb
, array_var
);
795 /* save the old src pointer */
796 mono_mb_emit_ldloc (mb
, 0);
797 mono_mb_emit_stloc (mb
, src_var
);
798 /* save the old dst pointer */
799 mono_mb_emit_ldloc (mb
, 1);
800 mono_mb_emit_stloc (mb
, dst_var
);
802 /* Emit marshalling loop */
803 index_var
= mono_mb_add_local (mb
, int_type
);
804 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
805 mono_mb_emit_stloc (mb
, index_var
);
808 label2
= mono_mb_get_label (mb
);
809 mono_mb_emit_ldloc (mb
, index_var
);
810 mono_mb_emit_ldloc (mb
, array_var
);
811 mono_mb_emit_byte (mb
, CEE_LDLEN
);
812 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
815 mono_mb_emit_ldloc (mb
, array_var
);
816 mono_mb_emit_ldloc (mb
, index_var
);
817 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
818 mono_mb_emit_stloc (mb
, 0);
820 /* dst is already set */
822 /* Do the conversion */
823 emit_struct_conv (mb
, eklass
, FALSE
);
826 mono_mb_emit_add_to_local (mb
, index_var
, 1);
828 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
830 mono_mb_patch_branch (mb
, label3
);
832 /* restore the old src pointer */
833 mono_mb_emit_ldloc (mb
, src_var
);
834 mono_mb_emit_stloc (mb
, 0);
835 /* restore the old dst pointer */
836 mono_mb_emit_ldloc (mb
, dst_var
);
837 mono_mb_emit_stloc (mb
, 1);
840 mono_mb_patch_branch (mb
, pos
);
843 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY
: {
844 mono_mb_emit_ldloc (mb
, 0);
845 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
846 pos
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
848 mono_mb_emit_ldloc (mb
, 1);
849 mono_mb_emit_ldloc (mb
, 0);
850 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
851 mono_mb_emit_icon (mb
, mspec
->data
.array_data
.num_elem
);
852 mono_mb_emit_icall (mb
, mono_array_to_byte_byvalarray
);
853 mono_mb_patch_short_branch (mb
, pos
);
856 case MONO_MARSHAL_CONV_OBJECT_STRUCT
: {
857 int src_var
, dst_var
;
859 MonoType
*int_type
= mono_get_int_type ();
860 src_var
= mono_mb_add_local (mb
, int_type
);
861 dst_var
= mono_mb_add_local (mb
, int_type
);
863 mono_mb_emit_ldloc (mb
, 0);
864 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
865 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
867 /* save the old src pointer */
868 mono_mb_emit_ldloc (mb
, 0);
869 mono_mb_emit_stloc (mb
, src_var
);
870 /* save the old dst pointer */
871 mono_mb_emit_ldloc (mb
, 1);
872 mono_mb_emit_stloc (mb
, dst_var
);
874 /* src = pointer to object data */
875 mono_mb_emit_ldloc (mb
, 0);
876 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
877 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
878 mono_mb_emit_byte (mb
, CEE_ADD
);
879 mono_mb_emit_stloc (mb
, 0);
881 emit_struct_conv (mb
, mono_class_from_mono_type_internal (type
), FALSE
);
883 /* restore the old src pointer */
884 mono_mb_emit_ldloc (mb
, src_var
);
885 mono_mb_emit_stloc (mb
, 0);
886 /* restore the old dst pointer */
887 mono_mb_emit_ldloc (mb
, dst_var
);
888 mono_mb_emit_stloc (mb
, 1);
890 mono_mb_patch_branch (mb
, pos
);
895 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
896 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
897 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
898 mono_cominterop_emit_object_to_ptr_conv (mb
, type
, conv
, mspec
);
900 #endif /* DISABLE_COM */
902 case MONO_MARSHAL_CONV_SAFEHANDLE
: {
905 mono_mb_emit_ldloc (mb
, 0);
906 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
907 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
908 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
909 mono_mb_patch_branch (mb
, pos
);
911 /* Pull the handle field from SafeHandle */
912 mono_mb_emit_ldloc (mb
, 1);
913 mono_mb_emit_ldloc (mb
, 0);
914 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
915 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
916 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
917 mono_mb_emit_byte (mb
, CEE_STIND_I
);
921 case MONO_MARSHAL_CONV_HANDLEREF
: {
922 mono_mb_emit_ldloc (mb
, 1);
923 mono_mb_emit_ldloc (mb
, 0);
924 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
925 mono_mb_emit_byte (mb
, CEE_ADD
);
926 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
927 mono_mb_emit_byte (mb
, CEE_STIND_I
);
932 g_error ("marshalling conversion %d not implemented", conv
);
939 emit_struct_conv_full (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
,
940 int offset_of_first_child_field
, MonoMarshalNative string_encoding
)
942 MonoMarshalType
*info
;
945 if (m_class_get_parent (klass
))
946 emit_struct_conv_full (mb
, m_class_get_parent (klass
), to_object
, offset_of_first_nonstatic_field (klass
), string_encoding
);
948 info
= mono_marshal_load_type_info (klass
);
950 if (info
->native_size
== 0)
953 if (m_class_is_blittable (klass
)) {
954 int usize
= mono_class_value_size (klass
, NULL
);
955 g_assert (usize
== info
->native_size
);
956 mono_mb_emit_ldloc (mb
, 1);
957 mono_mb_emit_ldloc (mb
, 0);
958 mono_mb_emit_icon (mb
, usize
);
959 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
960 mono_mb_emit_byte (mb
, CEE_CPBLK
);
963 mono_mb_emit_add_to_local (mb
, 0, usize
);
964 mono_mb_emit_add_to_local (mb
, 1, offset_of_first_child_field
);
966 mono_mb_emit_add_to_local (mb
, 0, offset_of_first_child_field
);
967 mono_mb_emit_add_to_local (mb
, 1, usize
);
972 if (klass
!= mono_class_try_get_safehandle_class ()) {
973 if (mono_class_is_auto_layout (klass
)) {
974 char *msg
= g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
975 mono_type_full_name (m_class_get_byval_arg (klass
)));
976 mono_mb_emit_exception_marshal_directive (mb
, msg
);
981 for (i
= 0; i
< info
->num_fields
; i
++) {
982 MonoMarshalNative ntype
;
983 MonoMarshalConv conv
;
984 MonoType
*ftype
= info
->fields
[i
].field
->type
;
987 gboolean last_field
= i
< (info
->num_fields
-1) ? 0 : 1;
989 if (ftype
->attrs
& FIELD_ATTRIBUTE_STATIC
)
992 ntype
= (MonoMarshalNative
)mono_type_to_unmanaged (ftype
, info
->fields
[i
].mspec
, TRUE
, m_class_is_unicode (klass
), &conv
);
995 msize
= m_class_get_instance_size (klass
) - info
->fields
[i
].field
->offset
;
996 usize
= info
->native_size
- info
->fields
[i
].offset
;
998 msize
= info
->fields
[i
+ 1].field
->offset
- info
->fields
[i
].field
->offset
;
999 usize
= info
->fields
[i
+ 1].offset
- info
->fields
[i
].offset
;
1002 if (klass
!= mono_class_try_get_safehandle_class ()){
1004 * FIXME: Should really check for usize==0 and msize>0, but we apply
1005 * the layout to the managed structure as well.
1008 if (mono_class_is_explicit_layout (klass
) && (usize
== 0)) {
1009 if (MONO_TYPE_IS_REFERENCE (info
->fields
[i
].field
->type
) ||
1010 ((!last_field
&& MONO_TYPE_IS_REFERENCE (info
->fields
[i
+ 1].field
->type
))))
1011 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
1012 "reference field at the same offset as another field.",
1013 mono_type_full_name (m_class_get_byval_arg (klass
)));
1018 case MONO_MARSHAL_CONV_NONE
: {
1021 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
1022 g_assert (!ftype
->byref
);
1023 if (ftype
->type
== MONO_TYPE_I
|| ftype
->type
== MONO_TYPE_U
) {
1024 mono_mb_emit_ldloc (mb
, 1);
1025 mono_mb_emit_ldloc (mb
, 0);
1026 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1027 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1038 case MONO_TYPE_BOOLEAN
:
1041 case MONO_TYPE_CHAR
:
1047 mono_mb_emit_ldloc (mb
, 1);
1048 mono_mb_emit_ldloc (mb
, 0);
1049 if (t
== MONO_TYPE_CHAR
&& ntype
== MONO_NATIVE_U1
&& string_encoding
!= MONO_NATIVE_LPWSTR
) {
1051 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
1052 mono_mb_emit_byte (mb
, CEE_STIND_I2
);
1054 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
1055 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
1058 mono_mb_emit_byte (mb
, mono_type_to_ldind (ftype
));
1059 mono_mb_emit_byte (mb
, mono_type_to_stind (ftype
));
1062 case MONO_TYPE_GENERICINST
:
1063 if (!mono_type_generic_inst_is_valuetype (ftype
)) {
1064 char *msg
= g_strdup_printf ("Generic type %s cannot be marshaled as field in a struct.",
1065 mono_type_full_name (ftype
));
1066 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1070 case MONO_TYPE_VALUETYPE
: {
1071 int src_var
, dst_var
;
1075 if (t
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (ftype
->data
.klass
)) {
1076 ftype
= mono_class_enum_basetype_internal (ftype
->data
.klass
);
1080 MonoType
*int_type
= mono_get_int_type ();
1081 src_var
= mono_mb_add_local (mb
, int_type
);
1082 dst_var
= mono_mb_add_local (mb
, int_type
);
1084 /* save the old src pointer */
1085 mono_mb_emit_ldloc (mb
, 0);
1086 mono_mb_emit_stloc (mb
, src_var
);
1087 /* save the old dst pointer */
1088 mono_mb_emit_ldloc (mb
, 1);
1089 mono_mb_emit_stloc (mb
, dst_var
);
1091 if (get_fixed_buffer_attr (info
->fields
[i
].field
, &etype
, &len
)) {
1092 emit_fixed_buf_conv (mb
, ftype
, etype
, len
, to_object
, &usize
);
1094 emit_struct_conv (mb
, mono_class_from_mono_type_internal (ftype
), to_object
);
1097 /* restore the old src pointer */
1098 mono_mb_emit_ldloc (mb
, src_var
);
1099 mono_mb_emit_stloc (mb
, 0);
1100 /* restore the old dst pointer */
1101 mono_mb_emit_ldloc (mb
, dst_var
);
1102 mono_mb_emit_stloc (mb
, 1);
1105 case MONO_TYPE_OBJECT
: {
1108 static MonoMethod
*variant_clear
= NULL
;
1109 static MonoMethod
*get_object_for_native_variant
= NULL
;
1112 variant_clear
= get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
1113 if (!get_object_for_native_variant
)
1114 get_object_for_native_variant
= get_method_nofail (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0);
1115 mono_mb_emit_ldloc (mb
, 1);
1116 mono_mb_emit_ldloc (mb
, 0);
1117 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
1118 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1120 mono_mb_emit_ldloc (mb
, 0);
1121 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
1124 static MonoMethod
*get_native_variant_for_object
= NULL
;
1126 if (!get_native_variant_for_object
)
1127 get_native_variant_for_object
= get_method_nofail (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0);
1129 mono_mb_emit_ldloc (mb
, 0);
1130 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
1131 mono_mb_emit_ldloc (mb
, 1);
1132 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
1135 char *msg
= g_strdup_printf ("COM support was disabled at compilation time.");
1136 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1142 g_warning ("marshaling type %02x not implemented", ftype
->type
);
1143 g_assert_not_reached ();
1148 int src_var
, dst_var
;
1150 MonoType
*int_type
= mono_get_int_type ();
1151 src_var
= mono_mb_add_local (mb
, int_type
);
1152 dst_var
= mono_mb_add_local (mb
, int_type
);
1154 /* save the old src pointer */
1155 mono_mb_emit_ldloc (mb
, 0);
1156 mono_mb_emit_stloc (mb
, src_var
);
1157 /* save the old dst pointer */
1158 mono_mb_emit_ldloc (mb
, 1);
1159 mono_mb_emit_stloc (mb
, dst_var
);
1162 emit_ptr_to_object_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1164 emit_object_to_ptr_conv (mb
, ftype
, conv
, info
->fields
[i
].mspec
);
1166 /* restore the old src pointer */
1167 mono_mb_emit_ldloc (mb
, src_var
);
1168 mono_mb_emit_stloc (mb
, 0);
1169 /* restore the old dst pointer */
1170 mono_mb_emit_ldloc (mb
, dst_var
);
1171 mono_mb_emit_stloc (mb
, 1);
1176 mono_mb_emit_add_to_local (mb
, 0, usize
);
1177 mono_mb_emit_add_to_local (mb
, 1, msize
);
1179 mono_mb_emit_add_to_local (mb
, 0, msize
);
1180 mono_mb_emit_add_to_local (mb
, 1, usize
);
1186 emit_struct_conv (MonoMethodBuilder
*mb
, MonoClass
*klass
, gboolean to_object
)
1188 emit_struct_conv_full (mb
, klass
, to_object
, 0, (MonoMarshalNative
)-1);
1192 emit_struct_free (MonoMethodBuilder
*mb
, MonoClass
*klass
, int struct_var
)
1194 /* Call DestroyStructure */
1195 /* FIXME: Only do this if needed */
1196 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1197 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
1198 mono_mb_emit_ldloc (mb
, struct_var
);
1199 mono_mb_emit_icall (mb
, mono_struct_delete_old
);
1203 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder
*mb
, MonoJitICallId checkpoint_icall_id
)
1205 int pos_noabort
, pos_noex
;
1207 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1208 mono_mb_emit_byte (mb
, CEE_MONO_LDPTR_INT_REQ_FLAG
);
1209 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
1210 pos_noabort
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1212 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1213 mono_mb_emit_byte (mb
, CEE_MONO_NOT_TAKEN
);
1215 mono_mb_emit_icall_id (mb
, checkpoint_icall_id
);
1216 /* Throw the exception returned by the checkpoint function, if any */
1217 mono_mb_emit_byte (mb
, CEE_DUP
);
1218 pos_noex
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1220 mono_mb_emit_byte (mb
, CEE_DUP
);
1221 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoException
, caught_in_unmanaged
));
1222 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
1223 mono_mb_emit_byte (mb
, CEE_STIND_I4
);
1225 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1226 mono_mb_emit_byte (mb
, CEE_MONO_RETHROW
);
1228 mono_mb_patch_branch (mb
, pos_noex
);
1229 mono_mb_emit_byte (mb
, CEE_POP
);
1231 mono_mb_patch_branch (mb
, pos_noabort
);
1235 emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1237 // FIXME Put a boolean in MonoMethodBuilder instead.
1238 if (strstr (mb
->name
, "mono_thread_interruption_checkpoint"))
1241 emit_thread_interrupt_checkpoint_call (mb
, MONO_JIT_ICALL_mono_thread_interruption_checkpoint
);
1245 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1247 emit_thread_interrupt_checkpoint_call (mb
, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise
);
1251 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1253 emit_thread_interrupt_checkpoint (mb
);
1257 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder
*mb
)
1259 emit_thread_force_interrupt_checkpoint (mb
);
1263 mono_mb_emit_save_args (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, gboolean save_this
)
1265 int i
, params_var
, tmp_var
;
1267 MonoType
*int_type
= mono_get_int_type ();
1268 /* allocate local (pointer) *params[] */
1269 params_var
= mono_mb_add_local (mb
, int_type
);
1270 /* allocate local (pointer) tmp */
1271 tmp_var
= mono_mb_add_local (mb
, int_type
);
1273 /* alloate space on stack to store an array of pointers to the arguments */
1274 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* (sig
->param_count
+ 1));
1275 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1276 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
1277 mono_mb_emit_stloc (mb
, params_var
);
1280 mono_mb_emit_ldloc (mb
, params_var
);
1281 mono_mb_emit_stloc (mb
, tmp_var
);
1283 if (save_this
&& sig
->hasthis
) {
1284 mono_mb_emit_ldloc (mb
, tmp_var
);
1285 mono_mb_emit_ldarg_addr (mb
, 0);
1286 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1287 /* tmp = tmp + sizeof (gpointer) */
1288 if (sig
->param_count
)
1289 mono_mb_emit_add_to_local (mb
, tmp_var
, TARGET_SIZEOF_VOID_P
);
1293 for (i
= 0; i
< sig
->param_count
; i
++) {
1294 mono_mb_emit_ldloc (mb
, tmp_var
);
1295 mono_mb_emit_ldarg_addr (mb
, i
+ sig
->hasthis
);
1296 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1297 /* tmp = tmp + sizeof (gpointer) */
1298 if (i
< (sig
->param_count
- 1))
1299 mono_mb_emit_add_to_local (mb
, tmp_var
, TARGET_SIZEOF_VOID_P
);
1307 mono_mb_emit_restore_result (MonoMethodBuilder
*mb
, MonoType
*return_type
)
1309 MonoType
*t
= mono_type_get_underlying_type (return_type
);
1310 MonoType
*int_type
= mono_get_int_type ();
1312 if (return_type
->byref
)
1313 return_type
= int_type
;
1316 case MONO_TYPE_VOID
:
1317 g_assert_not_reached ();
1320 case MONO_TYPE_STRING
:
1321 case MONO_TYPE_CLASS
:
1322 case MONO_TYPE_OBJECT
:
1323 case MONO_TYPE_ARRAY
:
1324 case MONO_TYPE_SZARRAY
:
1328 case MONO_TYPE_BOOLEAN
:
1331 case MONO_TYPE_CHAR
:
1341 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type_internal (return_type
));
1342 mono_mb_emit_byte (mb
, mono_type_to_ldind (return_type
));
1344 case MONO_TYPE_GENERICINST
:
1345 if (!mono_type_generic_inst_is_valuetype (t
))
1348 case MONO_TYPE_VALUETYPE
: {
1349 MonoClass
*klass
= mono_class_from_mono_type_internal (return_type
);
1350 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
1351 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
1355 case MONO_TYPE_MVAR
: {
1356 MonoClass
*klass
= mono_class_from_mono_type_internal (return_type
);
1357 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, klass
);
1361 g_warning ("type 0x%x not handled", return_type
->type
);
1362 g_assert_not_reached ();
1365 mono_mb_emit_byte (mb
, CEE_RET
);
1371 * Emit the call to the wrapper method from a runtime invoke wrapper.
1374 emit_invoke_call (MonoMethodBuilder
*mb
, MonoMethod
*method
,
1375 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
1377 gboolean virtual_
, gboolean need_direct_wrapper
)
1379 static MonoString
*string_dummy
= NULL
;
1381 int *tmp_nullable_locals
;
1382 gboolean void_ret
= FALSE
;
1383 gboolean string_ctor
= method
&& method
->string_ctor
;
1385 /* to make it work with our special string constructors */
1386 if (!string_dummy
) {
1389 // FIXME Allow for static construction of MonoString.
1391 SETUP_ICALL_FUNCTION
;
1394 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy
, MONO_ROOT_SOURCE_MARSHAL
, NULL
, "Marshal Dummy String");
1396 MonoStringHandle string_dummy_handle
= mono_string_new_utf8_len (mono_get_root_domain (), "dummy", 5, error
);
1397 string_dummy
= MONO_HANDLE_RAW (string_dummy_handle
);
1398 mono_error_assert_ok (error
);
1404 g_assert (sig
->hasthis
);
1405 g_assert (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
);
1410 if (mono_gc_is_moving ()) {
1411 mono_mb_emit_ptr (mb
, &string_dummy
);
1412 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1414 mono_mb_emit_ptr (mb
, string_dummy
);
1417 mono_mb_emit_ldarg (mb
, 0);
1421 tmp_nullable_locals
= g_new0 (int, sig
->param_count
);
1423 for (i
= 0; i
< sig
->param_count
; i
++) {
1424 MonoType
*t
= sig
->params
[i
];
1427 mono_mb_emit_ldarg (mb
, 1);
1429 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1430 mono_mb_emit_byte (mb
, CEE_ADD
);
1434 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1435 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
1436 * So to make this work we unbox it to a local variablee and push a reference to that.
1438 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
1439 tmp_nullable_locals
[i
] = mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_from_mono_type_internal (t
)));
1441 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type_internal (t
));
1442 mono_mb_emit_stloc (mb
, tmp_nullable_locals
[i
]);
1443 mono_mb_emit_ldloc_addr (mb
, tmp_nullable_locals
[i
]);
1448 type
= sig
->params
[i
]->type
;
1452 case MONO_TYPE_BOOLEAN
:
1456 case MONO_TYPE_CHAR
:
1465 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1466 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1468 case MONO_TYPE_STRING
:
1469 case MONO_TYPE_CLASS
:
1470 case MONO_TYPE_ARRAY
:
1472 case MONO_TYPE_SZARRAY
:
1473 case MONO_TYPE_OBJECT
:
1474 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1476 case MONO_TYPE_GENERICINST
:
1477 if (!mono_type_generic_inst_is_valuetype (sig
->params
[i
])) {
1478 mono_mb_emit_byte (mb
, mono_type_to_ldind (sig
->params
[i
]));
1482 t
= m_class_get_byval_arg (t
->data
.generic_class
->container_class
);
1485 case MONO_TYPE_VALUETYPE
:
1486 if (type
== MONO_TYPE_VALUETYPE
&& m_class_is_enumtype (t
->data
.klass
)) {
1487 type
= mono_class_enum_basetype_internal (t
->data
.klass
)->type
;
1490 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1491 if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig
->params
[i
]))) {
1492 /* Need to convert a boxed vtype to an mp to a Nullable struct */
1493 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1494 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1496 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (sig
->params
[i
]));
1500 g_assert_not_reached ();
1505 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
1506 } else if (need_direct_wrapper
) {
1507 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1509 mono_mb_emit_ldarg (mb
, 3);
1510 mono_mb_emit_calli (mb
, callsig
);
1513 if (sig
->ret
->byref
) {
1514 /* perform indirect load and return by value */
1515 #ifdef ENABLE_NETCORE
1517 mono_mb_emit_byte (mb
, CEE_DUP
);
1518 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
1519 mono_mb_emit_exception_full (mb
, "Mono", "NullByRefReturnException", NULL
);
1520 mono_mb_patch_branch (mb
, pos
);
1524 MonoType
* ret_byval
= m_class_get_byval_arg (mono_class_from_mono_type_internal (sig
->ret
));
1525 g_assert (!ret_byval
->byref
);
1526 // TODO: Handle null references
1527 ldind_op
= mono_type_to_ldind (ret_byval
);
1528 /* taken from similar code in mini-generic-sharing.c
1529 * we need to use mono_mb_emit_op to add method data when loading
1530 * a structure since method-to-ir needs this data for wrapper methods */
1531 if (ldind_op
== CEE_LDOBJ
)
1532 mono_mb_emit_op (mb
, CEE_LDOBJ
, mono_class_from_mono_type_internal (ret_byval
));
1534 mono_mb_emit_byte (mb
, ldind_op
);
1537 switch (sig
->ret
->type
) {
1538 case MONO_TYPE_VOID
:
1542 case MONO_TYPE_BOOLEAN
:
1543 case MONO_TYPE_CHAR
:
1556 case MONO_TYPE_VALUETYPE
:
1557 case MONO_TYPE_TYPEDBYREF
:
1558 case MONO_TYPE_GENERICINST
:
1559 /* box value types */
1560 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (sig
->ret
));
1562 case MONO_TYPE_STRING
:
1563 case MONO_TYPE_CLASS
:
1564 case MONO_TYPE_ARRAY
:
1565 case MONO_TYPE_SZARRAY
:
1566 case MONO_TYPE_OBJECT
:
1570 /* The result is an IntPtr */
1571 mono_mb_emit_op (mb
, CEE_BOX
, mono_defaults
.int_class
);
1574 g_assert_not_reached ();
1578 mono_mb_emit_stloc (mb
, loc_res
);
1580 /* Convert back nullable-byref arguments */
1581 for (i
= 0; i
< sig
->param_count
; i
++) {
1582 MonoType
*t
= sig
->params
[i
];
1585 * Box the result and put it back into the array, the caller will have
1586 * to obtain it from there.
1588 if (t
->byref
&& t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type_internal (t
))) {
1589 mono_mb_emit_ldarg (mb
, 1);
1590 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
* i
);
1591 mono_mb_emit_byte (mb
, CEE_ADD
);
1593 mono_mb_emit_ldloc (mb
, tmp_nullable_locals
[i
]);
1594 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (t
));
1596 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1600 g_free (tmp_nullable_locals
);
1604 emit_runtime_invoke_body_ilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoImage
*image
, MonoMethod
*method
,
1605 MonoMethodSignature
*sig
, MonoMethodSignature
*callsig
,
1606 gboolean virtual_
, gboolean need_direct_wrapper
)
1609 MonoExceptionClause
*clause
;
1610 int loc_res
, loc_exc
;
1612 mono_mb_set_param_names (mb
, param_names
);
1614 /* The wrapper looks like this:
1620 * } catch (Exception e) {
1628 MonoType
*object_type
= mono_get_object_type ();
1629 /* allocate local 0 (object) tmp */
1630 loc_res
= mono_mb_add_local (mb
, object_type
);
1631 /* allocate local 1 (object) exc */
1632 loc_exc
= mono_mb_add_local (mb
, object_type
);
1634 /* *exc is assumed to be initialized to NULL by the caller */
1636 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1637 labels
[0] = mono_mb_emit_branch (mb
, CEE_BRFALSE
);
1642 labels
[1] = mono_mb_get_label (mb
);
1643 emit_thread_force_interrupt_checkpoint (mb
);
1644 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
1646 labels
[2] = mono_mb_emit_branch (mb
, CEE_LEAVE
);
1648 /* Add a try clause around the call */
1649 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
1650 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
1651 clause
->data
.catch_class
= mono_defaults
.exception_class
;
1652 clause
->try_offset
= labels
[1];
1653 clause
->try_len
= mono_mb_get_label (mb
) - labels
[1];
1655 clause
->handler_offset
= mono_mb_get_label (mb
);
1658 mono_mb_emit_stloc (mb
, loc_exc
);
1659 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1660 mono_mb_emit_ldloc (mb
, loc_exc
);
1661 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1663 mono_mb_emit_branch (mb
, CEE_LEAVE
);
1665 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
1667 mono_mb_set_clauses (mb
, 1, clause
);
1669 mono_mb_patch_branch (mb
, labels
[2]);
1670 mono_mb_emit_ldloc (mb
, loc_res
);
1671 mono_mb_emit_byte (mb
, CEE_RET
);
1676 mono_mb_patch_branch (mb
, labels
[0]);
1677 emit_thread_force_interrupt_checkpoint (mb
);
1678 emit_invoke_call (mb
, method
, sig
, callsig
, loc_res
, virtual_
, need_direct_wrapper
);
1680 mono_mb_emit_ldloc (mb
, 0);
1681 mono_mb_emit_byte (mb
, CEE_RET
);
1685 emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder
*mb
)
1688 MonoExceptionClause
*clause
;
1690 MonoType
*object_type
= mono_get_object_type ();
1691 /* allocate local 0 (object) tmp */
1692 mono_mb_add_local (mb
, object_type
);
1693 /* allocate local 1 (object) exc */
1694 mono_mb_add_local (mb
, object_type
);
1696 /* cond set *exc to null */
1697 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1698 mono_mb_emit_byte (mb
, CEE_BRFALSE_S
);
1699 mono_mb_emit_byte (mb
, 3);
1700 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1701 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1702 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1704 emit_thread_force_interrupt_checkpoint (mb
);
1706 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1707 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
1708 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1709 mono_mb_emit_byte (mb
, CEE_MONO_DYN_CALL
);
1711 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
1713 clause
= (MonoExceptionClause
*)mono_image_alloc0 (mono_defaults
.corlib
, sizeof (MonoExceptionClause
));
1714 clause
->flags
= MONO_EXCEPTION_CLAUSE_FILTER
;
1715 clause
->try_len
= mono_mb_get_label (mb
);
1718 clause
->data
.filter_offset
= mono_mb_get_label (mb
);
1720 mono_mb_emit_byte (mb
, CEE_POP
);
1721 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1722 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1723 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1724 mono_mb_emit_byte (mb
, CEE_CGT_UN
);
1725 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
1726 mono_mb_emit_byte (mb
, CEE_ENDFILTER
);
1728 clause
->handler_offset
= mono_mb_get_label (mb
);
1731 /* store exception */
1732 mono_mb_emit_stloc (mb
, 1);
1734 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
1735 mono_mb_emit_ldloc (mb
, 1);
1736 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1738 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1739 mono_mb_emit_stloc (mb
, 0);
1741 mono_mb_emit_branch (mb
, CEE_LEAVE
);
1743 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
1745 mono_mb_set_clauses (mb
, 1, clause
);
1748 mono_mb_patch_branch (mb
, pos
);
1749 //mono_mb_emit_ldloc (mb, 0);
1750 mono_mb_emit_byte (mb
, CEE_RET
);
1754 mono_mb_emit_auto_layout_exception (MonoMethodBuilder
*mb
, MonoClass
*klass
)
1756 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
));
1757 mono_mb_emit_exception_marshal_directive (mb
, msg
);
1760 typedef struct EmitGCSafeTransitionBuilder
{
1761 MonoMethodBuilder
*mb
;
1762 gboolean func_param
;
1763 int coop_gc_stack_dummy
;
1766 int coop_cominterop_fnptr
;
1768 } GCSafeTransitionBuilder
;
1771 gc_safe_transition_builder_init (GCSafeTransitionBuilder
*builder
, MonoMethodBuilder
*mb
, gboolean func_param
)
1774 builder
->func_param
= func_param
;
1775 builder
->coop_gc_stack_dummy
= -1;
1776 builder
->coop_gc_var
= -1;
1778 builder
->coop_cominterop_fnptr
= -1;
1780 #if defined (TARGET_WASM)
1788 * adds locals for the gc safe transition to the method builder.
1791 gc_safe_transition_builder_add_locals (GCSafeTransitionBuilder
*builder
)
1793 MonoType
*int_type
= mono_get_int_type();
1794 /* local 4, dummy local used to get a stack address for suspend funcs */
1795 builder
->coop_gc_stack_dummy
= mono_mb_add_local (builder
->mb
, int_type
);
1796 /* local 5, the local to be used when calling the suspend funcs */
1797 builder
->coop_gc_var
= mono_mb_add_local (builder
->mb
, int_type
);
1799 if (!builder
->func_param
&& MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
)) {
1800 builder
->coop_cominterop_fnptr
= mono_mb_add_local (builder
->mb
, int_type
);
1807 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1811 gc_safe_transition_builder_emit_enter (GCSafeTransitionBuilder
*builder
, MonoMethod
*method
, gboolean aot
)
1814 // Perform an extra, early lookup of the function address, so any exceptions
1815 // potentially resulting from the lookup occur before entering blocking mode.
1816 if (!builder
->func_param
&& !MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
) && aot
) {
1817 mono_mb_emit_byte (builder
->mb
, MONO_CUSTOM_PREFIX
);
1818 mono_mb_emit_op (builder
->mb
, CEE_MONO_ICALL_ADDR
, method
);
1819 mono_mb_emit_byte (builder
->mb
, CEE_POP
); // Result not needed yet
1823 if (!builder
->func_param
&& MONO_CLASS_IS_IMPORT (builder
->mb
->method
->klass
)) {
1824 mono_mb_emit_cominterop_get_function_pointer (builder
->mb
, method
);
1825 mono_mb_emit_stloc (builder
->mb
, builder
->coop_cominterop_fnptr
);
1829 mono_mb_emit_ldloc_addr (builder
->mb
, builder
->coop_gc_stack_dummy
);
1830 mono_mb_emit_icall (builder
->mb
, mono_threads_enter_gc_safe_region_unbalanced
);
1831 mono_mb_emit_stloc (builder
->mb
, builder
->coop_gc_var
);
1836 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1840 gc_safe_transition_builder_emit_exit (GCSafeTransitionBuilder
*builder
)
1842 mono_mb_emit_ldloc (builder
->mb
, builder
->coop_gc_var
);
1843 mono_mb_emit_ldloc_addr (builder
->mb
, builder
->coop_gc_stack_dummy
);
1844 mono_mb_emit_icall (builder
->mb
, mono_threads_exit_gc_safe_region_unbalanced
);
1848 gc_safe_transition_builder_cleanup (GCSafeTransitionBuilder
*builder
)
1851 builder
->coop_gc_stack_dummy
= -1;
1852 builder
->coop_gc_var
= -1;
1854 builder
->coop_cominterop_fnptr
= -1;
1859 * emit_native_wrapper_ilgen:
1860 * \param image the image to use for looking up custom marshallers
1861 * \param sig The signature of the native function
1862 * \param piinfo Marshalling information
1863 * \param mspecs Marshalling information
1864 * \param aot whenever the created method will be compiled by the AOT compiler
1865 * \param method if non-NULL, the pinvoke method to call
1866 * \param check_exceptions Whenever to check for pending exceptions after the native call
1867 * \param func_param the function to call is passed as a boxed IntPtr as the first parameter
1869 * generates IL code for the pinvoke wrapper, the generated code calls \p func .
1872 emit_native_wrapper_ilgen (MonoImage
*image
, MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethodPInvoke
*piinfo
, MonoMarshalSpec
**mspecs
, gpointer func
, gboolean aot
, gboolean check_exceptions
, gboolean func_param
)
1874 EmitMarshalContext m
;
1875 MonoMethodSignature
*csig
;
1877 int i
, argnum
, *tmp_locals
;
1878 int type
, param_shift
= 0;
1879 gboolean need_gc_safe
= FALSE
;
1880 GCSafeTransitionBuilder gc_safe_transition_builder
;
1882 memset (&m
, 0, sizeof (m
));
1887 need_gc_safe
= gc_safe_transition_builder_init (&gc_safe_transition_builder
, mb
, func_param
);
1889 /* we copy the signature, so that we can set pinvoke to 0 */
1891 /* The function address is passed as the first argument */
1892 g_assert (!sig
->hasthis
);
1895 csig
= mono_metadata_signature_dup_full (get_method_image (mb
->method
), sig
);
1903 MonoType
*int_type
= mono_get_int_type ();
1904 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
1905 /* we allocate local for use with emit_struct_conv() */
1906 /* allocate local 0 (pointer) src_ptr */
1907 mono_mb_add_local (mb
, int_type
);
1908 /* allocate local 1 (pointer) dst_ptr */
1909 mono_mb_add_local (mb
, int_type
);
1910 /* allocate local 2 (boolean) delete_old */
1911 mono_mb_add_local (mb
, boolean_type
);
1913 /* delete_old = FALSE */
1914 mono_mb_emit_icon (mb
, 0);
1915 mono_mb_emit_stloc (mb
, 2);
1917 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
1918 /* allocate local 3 to store the return value */
1919 mono_mb_add_local (mb
, sig
->ret
);
1923 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder
);
1927 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1929 * ret = method (...);
1931 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1938 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
1939 m
.vtaddr_var
= mono_mb_add_local (mb
, int_type
);
1941 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
1942 /* Return type custom marshaling */
1944 * Since we can't determine the return type of the unmanaged function,
1945 * we assume it returns a pointer, and pass that pointer to
1946 * MarshalNativeToManaged.
1948 csig
->ret
= int_type
;
1951 /* we first do all conversions */
1952 tmp_locals
= g_newa (int, sig
->param_count
);
1953 m
.orig_conv_args
= g_newa (int, sig
->param_count
+ 1);
1955 for (i
= 0; i
< sig
->param_count
; i
++) {
1956 tmp_locals
[i
] = mono_emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_CONV_IN
);
1959 // In coop mode need to register blocking state during native call
1961 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder
, &piinfo
->method
, aot
);
1963 /* push all arguments */
1966 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1968 for (i
= 0; i
< sig
->param_count
; i
++) {
1969 mono_emit_marshal (&m
, i
+ param_shift
, sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_PUSH
);
1972 /* call the native method */
1974 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
1975 mono_mb_emit_op (mb
, CEE_UNBOX
, mono_defaults
.int_class
);
1976 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1977 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1978 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1979 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
1981 mono_mb_emit_calli (mb
, csig
);
1982 } else if (MONO_CLASS_IS_IMPORT (mb
->method
->klass
)) {
1984 mono_mb_emit_ldloc (mb
, gc_safe_transition_builder
.coop_cominterop_fnptr
);
1985 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1986 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1987 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
1989 mono_mb_emit_cominterop_call_function_pointer (mb
, csig
);
1991 g_assert_not_reached ();
1995 /* Reuse the ICALL_ADDR opcode for pinvokes too */
1996 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
1997 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
1998 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
1999 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2000 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
2002 mono_mb_emit_calli (mb
, csig
);
2004 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR
) {
2005 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2006 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LAST_ERROR
);
2008 mono_mb_emit_native_call (mb
, csig
, func
);
2012 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
2013 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
2014 mono_class_init_internal (klass
);
2015 if (!(mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
))) {
2016 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
2017 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
2018 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
2019 mono_mb_emit_stloc (mb
, m
.vtaddr_var
);
2023 /* Unblock before converting the result, since that can involve calls into the runtime */
2025 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder
);
2027 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder
);
2029 /* convert the result */
2030 if (!sig
->ret
->byref
) {
2031 MonoMarshalSpec
*spec
= mspecs
[0];
2032 type
= sig
->ret
->type
;
2034 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
2035 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2039 case MONO_TYPE_VOID
:
2041 case MONO_TYPE_VALUETYPE
:
2042 klass
= sig
->ret
->data
.klass
;
2043 if (m_class_is_enumtype (klass
)) {
2044 type
= mono_class_enum_basetype_internal (sig
->ret
->data
.klass
)->type
;
2047 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2061 case MONO_TYPE_FNPTR
:
2062 case MONO_TYPE_STRING
:
2063 case MONO_TYPE_CLASS
:
2064 case MONO_TYPE_OBJECT
:
2065 case MONO_TYPE_BOOLEAN
:
2066 case MONO_TYPE_ARRAY
:
2067 case MONO_TYPE_SZARRAY
:
2068 case MONO_TYPE_CHAR
:
2070 case MONO_TYPE_GENERICINST
:
2071 mono_emit_marshal (&m
, 0, sig
->ret
, spec
, 0, NULL
, MARSHAL_ACTION_CONV_RESULT
);
2073 case MONO_TYPE_TYPEDBYREF
:
2075 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
2076 g_assert_not_reached ();
2080 mono_mb_emit_stloc (mb
, 3);
2084 * Need to call this after converting the result since MONO_VTADDR needs
2085 * to be adjacent to the call instruction.
2087 if (check_exceptions
)
2088 emit_thread_interrupt_checkpoint (mb
);
2090 /* we need to convert byref arguments back and free string arrays */
2091 for (i
= 0; i
< sig
->param_count
; i
++) {
2092 MonoType
*t
= sig
->params
[i
];
2093 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
2095 argnum
= i
+ param_shift
;
2097 if (spec
&& ((spec
->native
== MONO_NATIVE_CUSTOM
) || (spec
->native
== MONO_NATIVE_ASANY
))) {
2098 mono_emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
2103 case MONO_TYPE_STRING
:
2104 case MONO_TYPE_VALUETYPE
:
2105 case MONO_TYPE_CLASS
:
2106 case MONO_TYPE_OBJECT
:
2107 case MONO_TYPE_SZARRAY
:
2108 case MONO_TYPE_BOOLEAN
:
2109 mono_emit_marshal (&m
, argnum
, t
, spec
, tmp_locals
[i
], NULL
, MARSHAL_ACTION_CONV_OUT
);
2116 if (!MONO_TYPE_IS_VOID(sig
->ret
))
2117 mono_mb_emit_ldloc (mb
, 3);
2119 mono_mb_emit_byte (mb
, CEE_RET
);
2123 * The code directly following this is the cache hit, value positive branch
2125 * This function takes a new method builder with 0 locals and adds two locals
2126 * to create multiple out-branches and the fall through state of having the object
2127 * on the stack after a cache miss
2130 generate_check_cache (int obj_arg_position
, int class_arg_position
, int cache_arg_position
, // In-parameters
2131 int *null_obj
, int *cache_hit_neg
, int *cache_hit_pos
, // Out-parameters
2132 MonoMethodBuilder
*mb
)
2136 MonoType
*int_type
= mono_get_int_type ();
2137 /* allocate local 0 (pointer) obj_vtable */
2138 mono_mb_add_local (mb
, int_type
);
2139 /* allocate local 1 (pointer) cached_vtable */
2140 mono_mb_add_local (mb
, int_type
);
2143 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2144 *null_obj
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2146 /*obj_vtable = obj->vtable;*/
2147 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2148 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2149 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2150 mono_mb_emit_stloc (mb
, 0);
2152 /* cached_vtable = *cache*/
2153 mono_mb_emit_ldarg (mb
, cache_arg_position
);
2154 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2155 mono_mb_emit_stloc (mb
, 1);
2157 mono_mb_emit_ldloc (mb
, 1);
2158 mono_mb_emit_byte (mb
, CEE_LDC_I4
);
2159 mono_mb_emit_i4 (mb
, ~0x1);
2160 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2161 mono_mb_emit_byte (mb
, CEE_AND
);
2162 mono_mb_emit_ldloc (mb
, 0);
2163 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
2164 cache_miss_pos
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
2166 /*return (cached_vtable & 0x1) ? NULL : obj;*/
2167 mono_mb_emit_ldloc (mb
, 1);
2168 mono_mb_emit_byte(mb
, CEE_LDC_I4_1
);
2169 mono_mb_emit_byte (mb
, CEE_CONV_U
);
2170 mono_mb_emit_byte (mb
, CEE_AND
);
2171 *cache_hit_neg
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
2172 *cache_hit_pos
= mono_mb_emit_branch (mb
, CEE_BR
);
2175 mono_mb_patch_branch (mb
, cache_miss_pos
);
2178 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2179 mono_mb_emit_ldarg (mb
, class_arg_position
);
2180 mono_mb_emit_ldarg (mb
, cache_arg_position
);
2181 mono_mb_emit_icall (mb
, mono_marshal_isinst_with_cache
);
2185 emit_castclass_ilgen (MonoMethodBuilder
*mb
)
2187 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
, invalid_cast_pos
;
2188 const int obj_arg_position
= TYPECHECK_OBJECT_ARG_POS
;
2189 const int class_arg_position
= TYPECHECK_CLASS_ARG_POS
;
2190 const int cache_arg_position
= TYPECHECK_CACHE_ARG_POS
;
2192 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
2193 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
2194 invalid_cast_pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2197 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
2198 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2199 mono_mb_emit_byte (mb
, CEE_RET
);
2202 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
2203 mono_mb_patch_branch (mb
, invalid_cast_pos
);
2204 mono_mb_emit_exception (mb
, "InvalidCastException", NULL
);
2207 mono_mb_patch_branch (mb
, return_null_pos
);
2208 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2209 mono_mb_emit_byte (mb
, CEE_RET
);
2213 emit_isinst_ilgen (MonoMethodBuilder
*mb
)
2215 int return_null_pos
, positive_cache_hit_pos
, negative_cache_hit_pos
;
2216 const int obj_arg_position
= TYPECHECK_OBJECT_ARG_POS
;
2217 const int class_arg_position
= TYPECHECK_CLASS_ARG_POS
;
2218 const int cache_arg_position
= TYPECHECK_CACHE_ARG_POS
;
2220 generate_check_cache (obj_arg_position
, class_arg_position
, cache_arg_position
,
2221 &return_null_pos
, &negative_cache_hit_pos
, &positive_cache_hit_pos
, mb
);
2222 // Return the object gotten via the slow path.
2223 mono_mb_emit_byte (mb
, CEE_RET
);
2226 mono_mb_patch_branch (mb
, negative_cache_hit_pos
);
2227 mono_mb_patch_branch (mb
, return_null_pos
);
2228 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2229 mono_mb_emit_byte (mb
, CEE_RET
);
2232 mono_mb_patch_branch (mb
, positive_cache_hit_pos
);
2233 mono_mb_emit_ldarg (mb
, obj_arg_position
);
2234 mono_mb_emit_byte (mb
, CEE_RET
);
2238 load_array_element_address (MonoMethodBuilder
*mb
)
2240 mono_mb_emit_ldarg (mb
, 0);
2241 mono_mb_emit_ldarg (mb
, 1);
2242 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
2246 load_array_class (MonoMethodBuilder
*mb
, int aklass
)
2248 mono_mb_emit_ldarg (mb
, 0);
2249 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2250 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2251 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
2252 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2253 mono_mb_emit_ldflda (mb
, m_class_offsetof_element_class ());
2254 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2255 mono_mb_emit_stloc (mb
, aklass
);
2259 load_value_class (MonoMethodBuilder
*mb
, int vklass
)
2261 mono_mb_emit_ldarg (mb
, 2);
2262 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
2263 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2264 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
2265 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2266 mono_mb_emit_stloc (mb
, vklass
);
2270 emit_marshal_array_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2271 MonoMarshalSpec
*spec
,
2272 int conv_arg
, MonoType
**conv_arg_type
,
2273 MarshalAction action
)
2275 MonoMethodBuilder
*mb
= m
->mb
;
2276 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
2277 gboolean need_convert
, need_free
;
2278 MonoMarshalNative encoding
;
2280 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
2281 MonoType
*int_type
= mono_get_int_type ();
2282 MonoType
*object_type
= mono_get_object_type ();
2284 MonoClass
*eklass
= m_class_get_element_class (klass
);
2287 case MARSHAL_ACTION_CONV_IN
:
2288 *conv_arg_type
= object_type
;
2289 conv_arg
= mono_mb_add_local (mb
, object_type
);
2291 if (m_class_is_blittable (eklass
)) {
2292 mono_mb_emit_ldarg (mb
, argnum
);
2294 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2295 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY
, NULL
));
2296 mono_mb_emit_stloc (mb
, conv_arg
);
2298 guint32 label1
, label2
, label3
;
2299 int index_var
, src_var
, dest_ptr
, esize
;
2300 MonoMarshalConv conv
;
2301 gboolean is_string
= FALSE
;
2303 dest_ptr
= mono_mb_add_local (mb
, int_type
);
2305 if (eklass
== mono_defaults
.string_class
) {
2307 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2309 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2311 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
2314 conv
= MONO_MARSHAL_CONV_INVALID
;
2316 if (is_string
&& conv
== MONO_MARSHAL_CONV_INVALID
) {
2317 char *msg
= g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding
);
2318 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2322 src_var
= mono_mb_add_local (mb
, object_type
);
2323 mono_mb_emit_ldarg (mb
, argnum
);
2325 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2326 mono_mb_emit_stloc (mb
, src_var
);
2329 mono_mb_emit_ldloc (mb
, src_var
);
2330 mono_mb_emit_stloc (mb
, conv_arg
);
2331 mono_mb_emit_ldloc (mb
, src_var
);
2332 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2335 esize
= TARGET_SIZEOF_VOID_P
;
2336 else if (eklass
== mono_defaults
.char_class
) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
2337 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2339 esize
= mono_class_native_size (eklass
, NULL
);
2341 /* allocate space for the native struct and store the address */
2342 mono_mb_emit_icon (mb
, esize
);
2343 mono_mb_emit_ldloc (mb
, src_var
);
2344 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2346 if (eklass
== mono_defaults
.string_class
) {
2347 /* Make the array bigger for the terminating null */
2348 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
2349 mono_mb_emit_byte (mb
, CEE_ADD
);
2351 mono_mb_emit_byte (mb
, CEE_MUL
);
2352 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2353 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
2354 mono_mb_emit_stloc (mb
, conv_arg
);
2356 mono_mb_emit_ldloc (mb
, conv_arg
);
2357 mono_mb_emit_stloc (mb
, dest_ptr
);
2359 /* Emit marshalling loop */
2360 index_var
= mono_mb_add_local (mb
, int_type
);
2361 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2362 mono_mb_emit_stloc (mb
, index_var
);
2363 label2
= mono_mb_get_label (mb
);
2364 mono_mb_emit_ldloc (mb
, index_var
);
2365 mono_mb_emit_ldloc (mb
, src_var
);
2366 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2367 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2369 /* Emit marshalling code */
2373 mono_mb_emit_ldloc (mb
, dest_ptr
);
2374 mono_mb_emit_ldloc (mb
, src_var
);
2375 mono_mb_emit_ldloc (mb
, index_var
);
2376 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2377 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2378 mono_mb_emit_byte (mb
, stind_op
);
2380 /* set the src_ptr */
2381 mono_mb_emit_ldloc (mb
, src_var
);
2382 mono_mb_emit_ldloc (mb
, index_var
);
2383 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2384 mono_mb_emit_stloc (mb
, 0);
2387 mono_mb_emit_ldloc (mb
, dest_ptr
);
2388 mono_mb_emit_stloc (mb
, 1);
2390 /* emit valuetype conversion code */
2391 emit_struct_conv_full (mb
, eklass
, FALSE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
2394 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2395 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
2397 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2399 mono_mb_patch_branch (mb
, label3
);
2401 if (eklass
== mono_defaults
.string_class
) {
2402 /* Null terminate */
2403 mono_mb_emit_ldloc (mb
, dest_ptr
);
2404 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2405 mono_mb_emit_byte (mb
, CEE_STIND_I
);
2408 mono_mb_patch_branch (mb
, label1
);
2413 case MARSHAL_ACTION_CONV_OUT
:
2414 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
2415 need_convert
= ((eklass
== mono_defaults
.char_class
) && (encoding
== MONO_NATIVE_LPWSTR
)) || (eklass
== mono_class_try_get_stringbuilder_class ()) || (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
2416 need_free
= mono_marshal_need_free (m_class_get_byval_arg (eklass
), m
->piinfo
, spec
);
2418 if ((t
->attrs
& PARAM_ATTRIBUTE_OUT
) && spec
&& spec
->native
== MONO_NATIVE_LPARRAY
&& spec
->data
.array_data
.param_num
!= -1) {
2419 int param_num
= spec
->data
.array_data
.param_num
;
2420 MonoType
*param_type
;
2422 param_type
= m
->sig
->params
[param_num
];
2424 if (param_type
->byref
&& param_type
->type
!= MONO_TYPE_I4
) {
2425 char *msg
= g_strdup ("Not implemented.");
2426 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2431 mono_mb_emit_ldarg (mb
, argnum
);
2433 /* Create the managed array */
2434 mono_mb_emit_ldarg (mb
, param_num
);
2435 if (m
->sig
->params
[param_num
]->byref
)
2436 // FIXME: Support other types
2437 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
2438 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
2439 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
2440 /* Store into argument */
2441 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
2445 if (need_convert
|| need_free
) {
2446 /* FIXME: Optimize blittable case */
2447 guint32 label1
, label2
, label3
;
2448 int index_var
, src_ptr
, loc
, esize
;
2450 if ((eklass
== mono_class_try_get_stringbuilder_class ()) || (eklass
== mono_defaults
.string_class
))
2451 esize
= TARGET_SIZEOF_VOID_P
;
2452 else if (eklass
== mono_defaults
.char_class
)
2453 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2455 esize
= mono_class_native_size (eklass
, NULL
);
2456 src_ptr
= mono_mb_add_local (mb
, int_type
);
2457 loc
= mono_mb_add_local (mb
, int_type
);
2460 mono_mb_emit_ldarg (mb
, argnum
);
2462 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2463 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2465 mono_mb_emit_ldloc (mb
, conv_arg
);
2466 mono_mb_emit_stloc (mb
, src_ptr
);
2468 /* Emit marshalling loop */
2469 index_var
= mono_mb_add_local (mb
, int_type
);
2470 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2471 mono_mb_emit_stloc (mb
, index_var
);
2472 label2
= mono_mb_get_label (mb
);
2473 mono_mb_emit_ldloc (mb
, index_var
);
2474 mono_mb_emit_ldarg (mb
, argnum
);
2476 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2477 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2478 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2480 /* Emit marshalling code */
2482 if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2483 gboolean need_free2
;
2484 MonoMarshalConv conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free2
);
2486 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2489 mono_mb_emit_ldarg (mb
, argnum
);
2491 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2492 mono_mb_emit_ldloc (mb
, index_var
);
2493 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2496 mono_mb_emit_ldloc (mb
, src_ptr
);
2497 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2499 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
2503 mono_mb_emit_ldloc (mb
, src_ptr
);
2504 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2506 mono_mb_emit_icall (mb
, mono_marshal_free
);
2509 else if (eklass
== mono_defaults
.string_class
) {
2512 mono_mb_emit_ldloc (mb
, src_ptr
);
2513 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2515 mono_mb_emit_icall (mb
, mono_marshal_free
);
2520 /* set the src_ptr */
2521 mono_mb_emit_ldloc (mb
, src_ptr
);
2522 mono_mb_emit_stloc (mb
, 0);
2525 mono_mb_emit_ldarg (mb
, argnum
);
2527 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2528 mono_mb_emit_ldloc (mb
, index_var
);
2529 mono_mb_emit_op (mb
, CEE_LDELEMA
, eklass
);
2530 mono_mb_emit_stloc (mb
, 1);
2532 /* emit valuetype conversion code */
2533 emit_struct_conv_full (mb
, eklass
, TRUE
, 0, eklass
== mono_defaults
.char_class
? encoding
: (MonoMarshalNative
)-1);
2537 mono_mb_emit_ldloc (mb
, src_ptr
);
2538 mono_mb_emit_stloc (mb
, loc
);
2540 emit_struct_free (mb
, eklass
, loc
);
2544 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2545 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
2547 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2549 mono_mb_patch_branch (mb
, label1
);
2550 mono_mb_patch_branch (mb
, label3
);
2553 if (m_class_is_blittable (eklass
)) {
2554 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
2556 mono_mb_emit_ldarg (mb
, argnum
);
2558 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
2559 mono_mb_emit_ldloc (mb
, conv_arg
);
2560 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY
, NULL
));
2565 case MARSHAL_ACTION_PUSH
:
2567 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
2569 mono_mb_emit_ldloc (mb
, conv_arg
);
2572 case MARSHAL_ACTION_CONV_RESULT
:
2573 /* fixme: we need conversions here */
2574 mono_mb_emit_stloc (mb
, 3);
2577 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
2578 guint32 label1
, label2
, label3
;
2579 int index_var
, src_ptr
, esize
, param_num
, num_elem
;
2580 MonoMarshalConv conv
;
2581 gboolean is_string
= FALSE
;
2583 conv_arg
= mono_mb_add_local (mb
, object_type
);
2584 *conv_arg_type
= int_type
;
2587 char *msg
= g_strdup ("Byref array marshalling to managed code is not implemented.");
2588 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2592 char *msg
= g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
2593 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2597 switch (spec
->native
) {
2598 case MONO_NATIVE_LPARRAY
:
2600 case MONO_NATIVE_SAFEARRAY
:
2602 if (spec
->data
.safearray_data
.elem_type
!= MONO_VARIANT_VARIANT
) {
2603 char *msg
= g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented.");
2604 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2607 return mono_cominterop_emit_marshal_safearray (m
, argnum
, t
, spec
, conv_arg
, conv_arg_type
, action
);
2610 char *msg
= g_strdup ("Unsupported array type marshalling to managed code.");
2611 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2616 /* FIXME: t is from the method which is wrapped, not the delegate type */
2617 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
2619 param_num
= spec
->data
.array_data
.param_num
;
2620 num_elem
= spec
->data
.array_data
.num_elem
;
2621 if (spec
->data
.array_data
.elem_mult
== 0)
2622 /* param_num is not specified */
2625 if (param_num
== -1) {
2626 if (num_elem
<= 0) {
2627 char *msg
= g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
2628 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2633 /* FIXME: Optimize blittable case */
2635 if (eklass
== mono_defaults
.string_class
) {
2637 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
2639 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2641 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
2644 conv
= MONO_MARSHAL_CONV_INVALID
;
2646 mono_marshal_load_type_info (eklass
);
2649 esize
= TARGET_SIZEOF_VOID_P
;
2651 esize
= mono_class_native_size (eklass
, NULL
);
2652 src_ptr
= mono_mb_add_local (mb
, int_type
);
2654 mono_mb_emit_byte (mb
, CEE_LDNULL
);
2655 mono_mb_emit_stloc (mb
, conv_arg
);
2657 /* Check param index */
2658 if (param_num
!= -1) {
2659 if (param_num
>= m
->sig
->param_count
) {
2660 char *msg
= g_strdup ("Array size control parameter index is out of range.");
2661 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2664 switch (m
->sig
->params
[param_num
]->type
) {
2677 char *msg
= g_strdup ("Array size control parameter must be an integral type.");
2678 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2685 mono_mb_emit_ldarg (mb
, argnum
);
2686 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2688 mono_mb_emit_ldarg (mb
, argnum
);
2689 mono_mb_emit_stloc (mb
, src_ptr
);
2691 /* Create managed array */
2693 * The LPArray marshalling spec says that sometimes param_num starts
2694 * from 1, sometimes it starts from 0. But MS seems to allways start
2698 if (param_num
== -1) {
2699 mono_mb_emit_icon (mb
, num_elem
);
2701 mono_mb_emit_ldarg (mb
, param_num
);
2703 mono_mb_emit_icon (mb
, num_elem
);
2704 mono_mb_emit_byte (mb
, CEE_ADD
);
2706 mono_mb_emit_byte (mb
, CEE_CONV_OVF_I
);
2709 mono_mb_emit_op (mb
, CEE_NEWARR
, eklass
);
2710 mono_mb_emit_stloc (mb
, conv_arg
);
2712 if (m_class_is_blittable (eklass
)) {
2713 mono_mb_emit_ldloc (mb
, conv_arg
);
2714 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2715 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
2716 mono_mb_emit_byte (mb
, CEE_ADD
);
2717 mono_mb_emit_ldarg (mb
, argnum
);
2718 mono_mb_emit_ldloc (mb
, conv_arg
);
2719 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2720 mono_mb_emit_icon (mb
, esize
);
2721 mono_mb_emit_byte (mb
, CEE_MUL
);
2722 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2723 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2724 mono_mb_patch_branch (mb
, label1
);
2728 /* Emit marshalling loop */
2729 index_var
= mono_mb_add_local (mb
, int_type
);
2730 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2731 mono_mb_emit_stloc (mb
, index_var
);
2732 label2
= mono_mb_get_label (mb
);
2733 mono_mb_emit_ldloc (mb
, index_var
);
2734 mono_mb_emit_ldloc (mb
, conv_arg
);
2735 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2736 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2738 /* Emit marshalling code */
2740 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2742 mono_mb_emit_ldloc (mb
, conv_arg
);
2743 mono_mb_emit_ldloc (mb
, index_var
);
2745 mono_mb_emit_ldloc (mb
, src_ptr
);
2746 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
2748 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
2749 mono_mb_emit_byte (mb
, CEE_STELEM_REF
);
2752 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2753 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2757 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2758 mono_mb_emit_add_to_local (mb
, src_ptr
, esize
);
2760 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2762 mono_mb_patch_branch (mb
, label1
);
2763 mono_mb_patch_branch (mb
, label3
);
2767 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
2768 guint32 label1
, label2
, label3
;
2769 int index_var
, dest_ptr
, esize
, param_num
, num_elem
;
2770 MonoMarshalConv conv
;
2771 gboolean is_string
= FALSE
;
2774 /* Already handled in CONV_IN */
2777 /* These are already checked in CONV_IN */
2778 g_assert (!t
->byref
);
2779 g_assert (spec
->native
== MONO_NATIVE_LPARRAY
);
2780 g_assert (t
->attrs
& PARAM_ATTRIBUTE_OUT
);
2782 param_num
= spec
->data
.array_data
.param_num
;
2783 num_elem
= spec
->data
.array_data
.num_elem
;
2785 if (spec
->data
.array_data
.elem_mult
== 0)
2786 /* param_num is not specified */
2789 if (param_num
== -1) {
2790 if (num_elem
<= 0) {
2791 g_assert_not_reached ();
2795 /* FIXME: Optimize blittable case */
2797 if (eklass
== mono_defaults
.string_class
) {
2799 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2801 else if (eklass
== mono_class_try_get_stringbuilder_class ()) {
2803 conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
2806 conv
= MONO_MARSHAL_CONV_INVALID
;
2808 mono_marshal_load_type_info (eklass
);
2811 esize
= TARGET_SIZEOF_VOID_P
;
2813 esize
= mono_class_native_size (eklass
, NULL
);
2815 dest_ptr
= mono_mb_add_local (mb
, int_type
);
2818 mono_mb_emit_ldloc (mb
, conv_arg
);
2819 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2821 mono_mb_emit_ldarg (mb
, argnum
);
2822 mono_mb_emit_stloc (mb
, dest_ptr
);
2824 if (m_class_is_blittable (eklass
)) {
2826 mono_mb_emit_ldarg (mb
, argnum
);
2828 mono_mb_emit_ldloc (mb
, conv_arg
);
2829 mono_mb_emit_byte (mb
, CEE_CONV_I
);
2830 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
2831 mono_mb_emit_byte (mb
, CEE_ADD
);
2833 mono_mb_emit_ldloc (mb
, conv_arg
);
2834 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2835 mono_mb_emit_icon (mb
, esize
);
2836 mono_mb_emit_byte (mb
, CEE_MUL
);
2837 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
2838 mono_mb_emit_byte (mb
, CEE_CPBLK
);
2842 /* Emit marshalling loop */
2843 index_var
= mono_mb_add_local (mb
, int_type
);
2844 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2845 mono_mb_emit_stloc (mb
, index_var
);
2846 label2
= mono_mb_get_label (mb
);
2847 mono_mb_emit_ldloc (mb
, index_var
);
2848 mono_mb_emit_ldloc (mb
, conv_arg
);
2849 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2850 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2852 /* Emit marshalling code */
2855 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2858 mono_mb_emit_ldloc (mb
, dest_ptr
);
2861 mono_mb_emit_ldloc (mb
, conv_arg
);
2862 mono_mb_emit_ldloc (mb
, index_var
);
2864 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2866 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2867 mono_mb_emit_byte (mb
, stind_op
);
2870 char *msg
= g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2871 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2875 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2876 mono_mb_emit_add_to_local (mb
, dest_ptr
, esize
);
2878 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2880 mono_mb_patch_branch (mb
, label1
);
2881 mono_mb_patch_branch (mb
, label3
);
2885 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
2886 guint32 label1
, label2
, label3
;
2887 int index_var
, src
, dest
, esize
;
2888 MonoMarshalConv conv
= MONO_MARSHAL_CONV_INVALID
;
2889 gboolean is_string
= FALSE
;
2891 g_assert (!t
->byref
);
2893 mono_marshal_load_type_info (eklass
);
2895 if (eklass
== mono_defaults
.string_class
) {
2897 conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
2900 g_assert_not_reached ();
2904 esize
= TARGET_SIZEOF_VOID_P
;
2905 else if (eklass
== mono_defaults
.char_class
)
2906 esize
= mono_pinvoke_is_unicode (m
->piinfo
) ? 2 : 1;
2908 esize
= mono_class_native_size (eklass
, NULL
);
2910 src
= mono_mb_add_local (mb
, object_type
);
2911 dest
= mono_mb_add_local (mb
, int_type
);
2913 mono_mb_emit_stloc (mb
, src
);
2914 mono_mb_emit_ldloc (mb
, src
);
2915 mono_mb_emit_stloc (mb
, 3);
2917 /* Check for null */
2918 mono_mb_emit_ldloc (mb
, src
);
2919 label1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2921 /* Allocate native array */
2922 mono_mb_emit_icon (mb
, esize
);
2923 mono_mb_emit_ldloc (mb
, src
);
2924 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2926 if (eklass
== mono_defaults
.string_class
) {
2927 /* Make the array bigger for the terminating null */
2928 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
2929 mono_mb_emit_byte (mb
, CEE_ADD
);
2931 mono_mb_emit_byte (mb
, CEE_MUL
);
2932 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
2933 mono_mb_emit_stloc (mb
, dest
);
2934 mono_mb_emit_ldloc (mb
, dest
);
2935 mono_mb_emit_stloc (mb
, 3);
2937 /* Emit marshalling loop */
2938 index_var
= mono_mb_add_local (mb
, int_type
);
2939 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
2940 mono_mb_emit_stloc (mb
, index_var
);
2941 label2
= mono_mb_get_label (mb
);
2942 mono_mb_emit_ldloc (mb
, index_var
);
2943 mono_mb_emit_ldloc (mb
, src
);
2944 mono_mb_emit_byte (mb
, CEE_LDLEN
);
2945 label3
= mono_mb_emit_branch (mb
, CEE_BGE
);
2947 /* Emit marshalling code */
2950 g_assert (conv
!= MONO_MARSHAL_CONV_INVALID
);
2953 mono_mb_emit_ldloc (mb
, dest
);
2956 mono_mb_emit_ldloc (mb
, src
);
2957 mono_mb_emit_ldloc (mb
, index_var
);
2959 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
2961 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
2962 mono_mb_emit_byte (mb
, stind_op
);
2965 char *msg
= g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
2966 mono_mb_emit_exception_marshal_directive (mb
, msg
);
2970 mono_mb_emit_add_to_local (mb
, index_var
, 1);
2971 mono_mb_emit_add_to_local (mb
, dest
, esize
);
2973 mono_mb_emit_branch_label (mb
, CEE_BR
, label2
);
2975 mono_mb_patch_branch (mb
, label3
);
2976 mono_mb_patch_branch (mb
, label1
);
2980 g_assert_not_reached ();
2986 emit_marshal_boolean_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2987 MonoMarshalSpec
*spec
,
2988 int conv_arg
, MonoType
**conv_arg_type
,
2989 MarshalAction action
)
2991 MonoMethodBuilder
*mb
= m
->mb
;
2992 MonoType
*int_type
= mono_get_int_type ();
2993 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
2996 case MARSHAL_ACTION_CONV_IN
: {
2997 MonoType
*local_type
;
2999 guint8 ldc_op
= CEE_LDC_I4_1
;
3001 local_type
= mono_marshal_boolean_conv_in_get_local_type (spec
, &ldc_op
);
3003 *conv_arg_type
= int_type
;
3005 *conv_arg_type
= local_type
;
3006 conv_arg
= mono_mb_add_local (mb
, local_type
);
3008 mono_mb_emit_ldarg (mb
, argnum
);
3010 mono_mb_emit_byte (mb
, CEE_LDIND_I1
);
3011 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3012 mono_mb_emit_byte (mb
, ldc_op
);
3013 mono_mb_emit_stloc (mb
, conv_arg
);
3014 mono_mb_patch_branch (mb
, label_false
);
3019 case MARSHAL_ACTION_CONV_OUT
:
3021 int label_false
, label_end
;
3025 mono_mb_emit_ldarg (mb
, argnum
);
3026 mono_mb_emit_ldloc (mb
, conv_arg
);
3028 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3029 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3031 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
3032 mono_mb_patch_branch (mb
, label_false
);
3033 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3034 mono_mb_patch_branch (mb
, label_end
);
3036 mono_mb_emit_byte (mb
, CEE_STIND_I1
);
3040 case MARSHAL_ACTION_PUSH
:
3042 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
3044 mono_mb_emit_ldloc (mb
, conv_arg
);
3046 mono_mb_emit_ldarg (mb
, argnum
);
3049 case MARSHAL_ACTION_CONV_RESULT
:
3050 /* maybe we need to make sure that it fits within 8 bits */
3051 mono_mb_emit_stloc (mb
, 3);
3054 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3055 MonoClass
* conv_arg_class
= mono_defaults
.int32_class
;
3056 guint8 ldop
= CEE_LDIND_I4
;
3057 int label_null
, label_false
;
3059 conv_arg_class
= mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec
, &ldop
);
3060 conv_arg
= mono_mb_add_local (mb
, boolean_type
);
3063 *conv_arg_type
= m_class_get_this_arg (conv_arg_class
);
3065 *conv_arg_type
= m_class_get_byval_arg (conv_arg_class
);
3068 mono_mb_emit_ldarg (mb
, argnum
);
3072 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3073 mono_mb_emit_ldarg (mb
, argnum
);
3074 mono_mb_emit_byte (mb
, ldop
);
3078 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3079 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3080 mono_mb_emit_stloc (mb
, conv_arg
);
3081 mono_mb_patch_branch (mb
, label_false
);
3084 mono_mb_patch_branch (mb
, label_null
);
3088 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
3089 guint8 stop
= CEE_STIND_I4
;
3090 guint8 ldc_op
= CEE_LDC_I4_1
;
3091 int label_null
,label_false
, label_end
;
3096 switch (spec
->native
) {
3097 case MONO_NATIVE_I1
:
3098 case MONO_NATIVE_U1
:
3099 stop
= CEE_STIND_I1
;
3101 case MONO_NATIVE_VARIANTBOOL
:
3102 stop
= CEE_STIND_I2
;
3103 ldc_op
= CEE_LDC_I4_M1
;
3111 mono_mb_emit_ldarg (mb
, argnum
);
3112 label_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3114 mono_mb_emit_ldarg (mb
, argnum
);
3115 mono_mb_emit_ldloc (mb
, conv_arg
);
3117 label_false
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3118 mono_mb_emit_byte (mb
, ldc_op
);
3119 label_end
= mono_mb_emit_branch (mb
, CEE_BR
);
3121 mono_mb_patch_branch (mb
, label_false
);
3122 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3123 mono_mb_patch_branch (mb
, label_end
);
3125 mono_mb_emit_byte (mb
, stop
);
3126 mono_mb_patch_branch (mb
, label_null
);
3131 g_assert_not_reached ();
3137 emit_marshal_ptr_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3138 MonoMarshalSpec
*spec
, int conv_arg
,
3139 MonoType
**conv_arg_type
, MarshalAction action
)
3141 MonoMethodBuilder
*mb
= m
->mb
;
3144 case MARSHAL_ACTION_CONV_IN
:
3145 /* MS seems to allow this in some cases, ie. bxc #158 */
3147 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) {
3148 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
3149 mono_mb_emit_exception_marshal_directive (m->mb, msg);
3154 case MARSHAL_ACTION_PUSH
:
3155 mono_mb_emit_ldarg (mb
, argnum
);
3158 case MARSHAL_ACTION_CONV_RESULT
:
3159 /* no conversions necessary */
3160 mono_mb_emit_stloc (mb
, 3);
3170 emit_marshal_char_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3171 MonoMarshalSpec
*spec
, int conv_arg
,
3172 MonoType
**conv_arg_type
, MarshalAction action
)
3174 MonoMethodBuilder
*mb
= m
->mb
;
3177 case MARSHAL_ACTION_PUSH
:
3178 /* fixme: dont know how to marshal that. We cant simply
3179 * convert it to a one byte UTF8 character, because an
3180 * unicode character may need more that one byte in UTF8 */
3181 mono_mb_emit_ldarg (mb
, argnum
);
3184 case MARSHAL_ACTION_CONV_RESULT
:
3185 /* fixme: we need conversions here */
3186 mono_mb_emit_stloc (mb
, 3);
3196 emit_marshal_scalar_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3197 MonoMarshalSpec
*spec
, int conv_arg
,
3198 MonoType
**conv_arg_type
, MarshalAction action
)
3200 MonoMethodBuilder
*mb
= m
->mb
;
3203 case MARSHAL_ACTION_PUSH
:
3204 mono_mb_emit_ldarg (mb
, argnum
);
3207 case MARSHAL_ACTION_CONV_RESULT
:
3208 /* no conversions necessary */
3209 mono_mb_emit_stloc (mb
, 3);
3219 emit_virtual_stelemref_ilgen (MonoMethodBuilder
*mb
, const char **param_names
, MonoStelemrefKind kind
)
3221 guint32 b1
, b2
, b3
, b4
;
3222 int aklass
, vklass
, vtable
, uiid
;
3223 int array_slot_addr
;
3225 mono_mb_set_param_names (mb
, param_names
);
3226 MonoType
*int_type
= mono_get_int_type ();
3227 MonoType
*int32_type
= m_class_get_byval_arg (mono_defaults
.int32_class
);
3228 MonoType
*object_type_byref
= m_class_get_this_arg (mono_defaults
.object_class
);
3230 /*For now simply call plain old stelemref*/
3232 case STELEMREF_OBJECT
:
3233 /* ldelema (implicit bound check) */
3234 load_array_element_address (mb
);
3236 mono_mb_emit_ldarg (mb
, 2);
3237 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3238 mono_mb_emit_byte (mb
, CEE_RET
);
3241 case STELEMREF_COMPLEX
: {
3244 <ldelema (bound check)>
3247 if (!mono_object_isinst (value, aklass))
3251 *array_slot_addr = value;
3254 throw new ArrayTypeMismatchException ();
3257 aklass
= mono_mb_add_local (mb
, int_type
);
3258 vklass
= mono_mb_add_local (mb
, int_type
);
3259 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3263 /*Use this to debug/record stores that are going thru the slow path*/
3264 MonoMethodSignature
*csig
;
3265 csig
= mono_metadata_signature_alloc (mono_defaults
.corlib
, 3);
3266 csig
->ret
= mono_get_void_type ();
3267 csig
->params
[0] = object_type
;
3268 csig
->params
[1] = int_type
; /* this is a natural sized int */
3269 csig
->params
[2] = object_type
;
3270 mono_mb_emit_ldarg (mb
, 0);
3271 mono_mb_emit_ldarg (mb
, 1);
3272 mono_mb_emit_ldarg (mb
, 2);
3273 mono_mb_emit_native_call (mb
, csig
, record_slot_vstore
);
3277 /* ldelema (implicit bound check) */
3278 load_array_element_address (mb
);
3279 mono_mb_emit_stloc (mb
, array_slot_addr
);
3281 /* if (!value) goto do_store */
3282 mono_mb_emit_ldarg (mb
, 2);
3283 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3285 /* aklass = array->vtable->klass->element_class */
3286 load_array_class (mb
, aklass
);
3287 /* vklass = value->vtable->klass */
3288 load_value_class (mb
, vklass
);
3291 mono_mb_emit_ldloc (mb
, vklass
);
3292 mono_mb_emit_ldloc (mb
, aklass
);
3293 b_fast
= mono_mb_emit_branch (mb
, CEE_BEQ
);
3295 /*if (mono_object_isinst (value, aklass)) */
3296 mono_mb_emit_ldarg (mb
, 2);
3297 mono_mb_emit_ldloc (mb
, aklass
);
3298 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
3299 b2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3302 mono_mb_patch_branch (mb
, b1
);
3303 mono_mb_patch_branch (mb
, b_fast
);
3304 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3305 mono_mb_emit_ldarg (mb
, 2);
3306 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3307 mono_mb_emit_byte (mb
, CEE_RET
);
3310 mono_mb_patch_branch (mb
, b2
);
3312 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3315 case STELEMREF_SEALED_CLASS
:
3317 <ldelema (bound check)>
3321 aklass = array->vtable->m_class_get_element_class (klass);
3322 vklass = value->vtable->klass;
3324 if (vklass != aklass)
3328 *array_slot_addr = value;
3331 throw new ArrayTypeMismatchException ();
3333 aklass
= mono_mb_add_local (mb
, int_type
);
3334 vklass
= mono_mb_add_local (mb
, int_type
);
3335 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3337 /* ldelema (implicit bound check) */
3338 load_array_element_address (mb
);
3339 mono_mb_emit_stloc (mb
, array_slot_addr
);
3341 /* if (!value) goto do_store */
3342 mono_mb_emit_ldarg (mb
, 2);
3343 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3345 /* aklass = array->vtable->klass->element_class */
3346 load_array_class (mb
, aklass
);
3348 /* vklass = value->vtable->klass */
3349 load_value_class (mb
, vklass
);
3351 /*if (vklass != aklass) goto do_exception; */
3352 mono_mb_emit_ldloc (mb
, aklass
);
3353 mono_mb_emit_ldloc (mb
, vklass
);
3354 b2
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3357 mono_mb_patch_branch (mb
, b1
);
3358 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3359 mono_mb_emit_ldarg (mb
, 2);
3360 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3361 mono_mb_emit_byte (mb
, CEE_RET
);
3364 mono_mb_patch_branch (mb
, b2
);
3365 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3368 case STELEMREF_CLASS
: {
3371 <ldelema (bound check)>
3375 aklass = array->vtable->m_class_get_element_class (klass);
3376 vklass = value->vtable->klass;
3378 if (vklass->idepth < aklass->idepth)
3381 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3385 *array_slot_addr = value;
3389 throw new ArrayTypeMismatchException ();
3391 aklass
= mono_mb_add_local (mb
, int_type
);
3392 vklass
= mono_mb_add_local (mb
, int_type
);
3393 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3395 /* ldelema (implicit bound check) */
3396 load_array_element_address (mb
);
3397 mono_mb_emit_stloc (mb
, array_slot_addr
);
3399 /* if (!value) goto do_store */
3400 mono_mb_emit_ldarg (mb
, 2);
3401 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3403 /* aklass = array->vtable->klass->element_class */
3404 load_array_class (mb
, aklass
);
3406 /* vklass = value->vtable->klass */
3407 load_value_class (mb
, vklass
);
3409 /* if (vklass->idepth < aklass->idepth) goto failue */
3410 mono_mb_emit_ldloc (mb
, vklass
);
3411 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3412 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3414 mono_mb_emit_ldloc (mb
, aklass
);
3415 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3416 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3418 b3
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
3420 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3421 mono_mb_emit_ldloc (mb
, vklass
);
3422 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3423 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3425 mono_mb_emit_ldloc (mb
, aklass
);
3426 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3427 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3428 mono_mb_emit_icon (mb
, 1);
3429 mono_mb_emit_byte (mb
, CEE_SUB
);
3430 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3431 mono_mb_emit_byte (mb
, CEE_MUL
);
3432 mono_mb_emit_byte (mb
, CEE_ADD
);
3433 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3435 mono_mb_emit_ldloc (mb
, aklass
);
3436 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3439 mono_mb_patch_branch (mb
, b1
);
3440 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3441 mono_mb_emit_ldarg (mb
, 2);
3442 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3443 mono_mb_emit_byte (mb
, CEE_RET
);
3446 mono_mb_patch_branch (mb
, b3
);
3447 mono_mb_patch_branch (mb
, b4
);
3449 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3453 case STELEMREF_CLASS_SMALL_IDEPTH
:
3456 <ldelema (bound check)>
3460 aklass = array->vtable->m_class_get_element_class (klass);
3461 vklass = value->vtable->klass;
3463 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3467 *array_slot_addr = value;
3471 throw new ArrayTypeMismatchException ();
3473 aklass
= mono_mb_add_local (mb
, int_type
);
3474 vklass
= mono_mb_add_local (mb
, int_type
);
3475 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3477 /* ldelema (implicit bound check) */
3478 load_array_element_address (mb
);
3479 mono_mb_emit_stloc (mb
, array_slot_addr
);
3481 /* if (!value) goto do_store */
3482 mono_mb_emit_ldarg (mb
, 2);
3483 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3485 /* aklass = array->vtable->klass->element_class */
3486 load_array_class (mb
, aklass
);
3488 /* vklass = value->vtable->klass */
3489 load_value_class (mb
, vklass
);
3491 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3492 mono_mb_emit_ldloc (mb
, vklass
);
3493 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3494 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3496 mono_mb_emit_ldloc (mb
, aklass
);
3497 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3498 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3499 mono_mb_emit_icon (mb
, 1);
3500 mono_mb_emit_byte (mb
, CEE_SUB
);
3501 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3502 mono_mb_emit_byte (mb
, CEE_MUL
);
3503 mono_mb_emit_byte (mb
, CEE_ADD
);
3504 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3506 mono_mb_emit_ldloc (mb
, aklass
);
3507 b4
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3510 mono_mb_patch_branch (mb
, b1
);
3511 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3512 mono_mb_emit_ldarg (mb
, 2);
3513 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3514 mono_mb_emit_byte (mb
, CEE_RET
);
3517 mono_mb_patch_branch (mb
, b4
);
3519 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3522 case STELEMREF_INTERFACE
:
3529 klass = array->obj.vtable->klass->element_class;
3531 uiid = klass->interface_id;
3532 if (uiid > vt->max_interface_id)
3534 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
3537 mono_array_setref_internal (array, index, value);
3540 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
3542 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3543 aklass
= mono_mb_add_local (mb
, int_type
);
3544 vtable
= mono_mb_add_local (mb
, int_type
);
3545 uiid
= mono_mb_add_local (mb
, int32_type
);
3547 /* ldelema (implicit bound check) */
3548 load_array_element_address (mb
);
3549 mono_mb_emit_stloc (mb
, array_slot_addr
);
3551 /* if (!value) goto do_store */
3552 mono_mb_emit_ldarg (mb
, 2);
3553 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3555 /* klass = array->vtable->m_class_get_element_class (klass) */
3556 load_array_class (mb
, aklass
);
3558 /* vt = value->vtable */
3559 mono_mb_emit_ldarg (mb
, 2);
3560 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3561 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3562 mono_mb_emit_stloc (mb
, vtable
);
3564 /* uiid = klass->interface_id; */
3565 mono_mb_emit_ldloc (mb
, aklass
);
3566 mono_mb_emit_ldflda (mb
, m_class_offsetof_interface_id ());
3567 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
3568 mono_mb_emit_stloc (mb
, uiid
);
3570 /*if (uiid > vt->max_interface_id)*/
3571 mono_mb_emit_ldloc (mb
, uiid
);
3572 mono_mb_emit_ldloc (mb
, vtable
);
3573 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
3574 mono_mb_emit_byte (mb
, CEE_LDIND_U4
);
3575 b2
= mono_mb_emit_branch (mb
, CEE_BGT_UN
);
3577 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
3579 /*vt->interface_bitmap*/
3580 mono_mb_emit_ldloc (mb
, vtable
);
3581 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, interface_bitmap
));
3582 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3585 mono_mb_emit_ldloc (mb
, uiid
);
3586 mono_mb_emit_icon (mb
, 3);
3587 mono_mb_emit_byte (mb
, CEE_SHR_UN
);
3589 /*vt->interface_bitmap [(uiid) >> 3]*/
3590 mono_mb_emit_byte (mb
, CEE_ADD
); /*interface_bitmap is a guint8 array*/
3591 mono_mb_emit_byte (mb
, CEE_LDIND_U1
);
3593 /*(1 << ((uiid)&7)))*/
3594 mono_mb_emit_icon (mb
, 1);
3595 mono_mb_emit_ldloc (mb
, uiid
);
3596 mono_mb_emit_icon (mb
, 7);
3597 mono_mb_emit_byte (mb
, CEE_AND
);
3598 mono_mb_emit_byte (mb
, CEE_SHL
);
3600 /*bitwise and the whole thing*/
3601 mono_mb_emit_byte (mb
, CEE_AND
);
3602 b3
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3605 mono_mb_patch_branch (mb
, b1
);
3606 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3607 mono_mb_emit_ldarg (mb
, 2);
3608 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3609 mono_mb_emit_byte (mb
, CEE_RET
);
3612 mono_mb_patch_branch (mb
, b2
);
3613 mono_mb_patch_branch (mb
, b3
);
3614 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3618 mono_mb_emit_ldarg (mb
, 0);
3619 mono_mb_emit_ldarg (mb
, 1);
3620 mono_mb_emit_ldarg (mb
, 2);
3621 mono_mb_emit_managed_call (mb
, mono_marshal_get_stelemref (), NULL
);
3622 mono_mb_emit_byte (mb
, CEE_RET
);
3628 emit_stelemref_ilgen (MonoMethodBuilder
*mb
)
3630 guint32 b1
, b2
, b3
, b4
;
3633 int array_slot_addr
;
3635 MonoType
*int_type
= mono_get_int_type ();
3636 MonoType
*object_type_byref
= m_class_get_this_arg (mono_defaults
.object_class
);
3638 aklass
= mono_mb_add_local (mb
, int_type
);
3639 vklass
= mono_mb_add_local (mb
, int_type
);
3640 array_slot_addr
= mono_mb_add_local (mb
, object_type_byref
);
3644 <ldelema (bound check)>
3648 aklass = array->vtable->m_class_get_element_class (klass);
3649 vklass = value->vtable->klass;
3651 if (vklass->idepth < aklass->idepth)
3654 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3658 *array_slot_addr = value;
3662 if (mono_object_isinst (value, aklass))
3665 throw new ArrayTypeMismatchException ();
3668 /* ldelema (implicit bound check) */
3669 mono_mb_emit_ldarg (mb
, 0);
3670 mono_mb_emit_ldarg (mb
, 1);
3671 mono_mb_emit_op (mb
, CEE_LDELEMA
, mono_defaults
.object_class
);
3672 mono_mb_emit_stloc (mb
, array_slot_addr
);
3674 /* if (!value) goto do_store */
3675 mono_mb_emit_ldarg (mb
, 2);
3676 b1
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3678 /* aklass = array->vtable->klass->element_class */
3679 mono_mb_emit_ldarg (mb
, 0);
3680 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3681 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3682 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3683 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3684 mono_mb_emit_ldflda (mb
, m_class_offsetof_element_class ());
3685 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3686 mono_mb_emit_stloc (mb
, aklass
);
3688 /* vklass = value->vtable->klass */
3689 mono_mb_emit_ldarg (mb
, 2);
3690 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3691 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3692 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3693 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3694 mono_mb_emit_stloc (mb
, vklass
);
3696 /* if (vklass->idepth < aklass->idepth) goto failue */
3697 mono_mb_emit_ldloc (mb
, vklass
);
3698 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3699 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3701 mono_mb_emit_ldloc (mb
, aklass
);
3702 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3703 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3705 b2
= mono_mb_emit_branch (mb
, CEE_BLT_UN
);
3707 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3708 mono_mb_emit_ldloc (mb
, vklass
);
3709 mono_mb_emit_ldflda (mb
, m_class_offsetof_supertypes ());
3710 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3712 mono_mb_emit_ldloc (mb
, aklass
);
3713 mono_mb_emit_ldflda (mb
, m_class_offsetof_idepth ());
3714 mono_mb_emit_byte (mb
, CEE_LDIND_U2
);
3715 mono_mb_emit_icon (mb
, 1);
3716 mono_mb_emit_byte (mb
, CEE_SUB
);
3717 mono_mb_emit_icon (mb
, TARGET_SIZEOF_VOID_P
);
3718 mono_mb_emit_byte (mb
, CEE_MUL
);
3719 mono_mb_emit_byte (mb
, CEE_ADD
);
3720 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3722 mono_mb_emit_ldloc (mb
, aklass
);
3724 b3
= mono_mb_emit_branch (mb
, CEE_BNE_UN
);
3726 copy_pos
= mono_mb_get_label (mb
);
3728 mono_mb_patch_branch (mb
, b1
);
3729 mono_mb_emit_ldloc (mb
, array_slot_addr
);
3730 mono_mb_emit_ldarg (mb
, 2);
3731 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3733 mono_mb_emit_byte (mb
, CEE_RET
);
3736 mono_mb_patch_branch (mb
, b2
);
3737 mono_mb_patch_branch (mb
, b3
);
3739 mono_mb_emit_ldarg (mb
, 2);
3740 mono_mb_emit_ldloc (mb
, aklass
);
3741 mono_mb_emit_icall (mb
, mono_object_isinst_icall
);
3743 b4
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3744 mono_mb_patch_addr (mb
, b4
, copy_pos
- (b4
+ 4));
3745 mono_mb_emit_exception (mb
, "ArrayTypeMismatchException", NULL
);
3747 mono_mb_emit_byte (mb
, CEE_RET
);
3751 mb_emit_byte_ilgen (MonoMethodBuilder
*mb
, guint8 op
)
3753 mono_mb_emit_byte (mb
, op
);
3757 emit_array_address_ilgen (MonoMethodBuilder
*mb
, int rank
, int elem_size
)
3759 int i
, bounds
, ind
, realidx
;
3760 int branch_pos
, *branch_positions
;
3762 MonoType
*int_type
= mono_get_int_type ();
3763 MonoType
*int32_type
= mono_get_int32_type ();
3765 branch_positions
= g_new0 (int, rank
);
3767 bounds
= mono_mb_add_local (mb
, int_type
);
3768 ind
= mono_mb_add_local (mb
, int32_type
);
3769 realidx
= mono_mb_add_local (mb
, int32_type
);
3771 /* bounds = array->bounds; */
3772 mono_mb_emit_ldarg (mb
, 0);
3773 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
3774 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3775 mono_mb_emit_stloc (mb
, bounds
);
3777 /* ind is the overall element index, realidx is the partial index in a single dimension */
3778 /* ind = idx0 - bounds [0].lower_bound */
3779 mono_mb_emit_ldarg (mb
, 1);
3780 mono_mb_emit_ldloc (mb
, bounds
);
3781 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
3782 mono_mb_emit_byte (mb
, CEE_ADD
);
3783 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3784 mono_mb_emit_byte (mb
, CEE_SUB
);
3785 mono_mb_emit_stloc (mb
, ind
);
3786 /* if (ind >= bounds [0].length) goto exeception; */
3787 mono_mb_emit_ldloc (mb
, ind
);
3788 mono_mb_emit_ldloc (mb
, bounds
);
3789 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3790 mono_mb_emit_byte (mb
, CEE_ADD
);
3791 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3792 /* note that we use unsigned comparison */
3793 branch_pos
= mono_mb_emit_branch (mb
, CEE_BGE_UN
);
3795 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
3796 * We could also decide to ignore the passed elem_size and get it
3797 * from the array object, to reduce the number of methods we generate:
3798 * the additional cost is 3 memory loads and a non-immediate mul.
3800 for (i
= 1; i
< rank
; ++i
) {
3801 /* realidx = idxi - bounds [i].lower_bound */
3802 mono_mb_emit_ldarg (mb
, 1 + i
);
3803 mono_mb_emit_ldloc (mb
, bounds
);
3804 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, lower_bound
));
3805 mono_mb_emit_byte (mb
, CEE_ADD
);
3806 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3807 mono_mb_emit_byte (mb
, CEE_SUB
);
3808 mono_mb_emit_stloc (mb
, realidx
);
3809 /* if (realidx >= bounds [i].length) goto exeception; */
3810 mono_mb_emit_ldloc (mb
, realidx
);
3811 mono_mb_emit_ldloc (mb
, bounds
);
3812 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3813 mono_mb_emit_byte (mb
, CEE_ADD
);
3814 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3815 branch_positions
[i
] = mono_mb_emit_branch (mb
, CEE_BGE_UN
);
3816 /* ind = ind * bounds [i].length + realidx */
3817 mono_mb_emit_ldloc (mb
, ind
);
3818 mono_mb_emit_ldloc (mb
, bounds
);
3819 mono_mb_emit_icon (mb
, (i
* sizeof (MonoArrayBounds
)) + MONO_STRUCT_OFFSET (MonoArrayBounds
, length
));
3820 mono_mb_emit_byte (mb
, CEE_ADD
);
3821 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3822 mono_mb_emit_byte (mb
, CEE_MUL
);
3823 mono_mb_emit_ldloc (mb
, realidx
);
3824 mono_mb_emit_byte (mb
, CEE_ADD
);
3825 mono_mb_emit_stloc (mb
, ind
);
3828 /* return array->vector + ind * element_size */
3829 mono_mb_emit_ldarg (mb
, 0);
3830 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoArray
, vector
));
3831 mono_mb_emit_ldloc (mb
, ind
);
3833 mono_mb_emit_icon (mb
, elem_size
);
3835 /* Load arr->vtable->klass->sizes.element_class */
3836 mono_mb_emit_ldarg (mb
, 0);
3837 mono_mb_emit_byte (mb
, CEE_CONV_I
);
3838 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
3839 mono_mb_emit_byte (mb
, CEE_ADD
);
3840 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3841 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
3842 mono_mb_emit_byte (mb
, CEE_ADD
);
3843 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3844 /* sizes is an union, so this reads sizes.element_size */
3845 mono_mb_emit_icon (mb
, m_class_offsetof_sizes ());
3846 mono_mb_emit_byte (mb
, CEE_ADD
);
3847 mono_mb_emit_byte (mb
, CEE_LDIND_I4
);
3849 mono_mb_emit_byte (mb
, CEE_MUL
);
3850 mono_mb_emit_byte (mb
, CEE_ADD
);
3851 mono_mb_emit_byte (mb
, CEE_RET
);
3853 /* patch the branches to get here and throw */
3854 for (i
= 1; i
< rank
; ++i
) {
3855 mono_mb_patch_branch (mb
, branch_positions
[i
]);
3857 mono_mb_patch_branch (mb
, branch_pos
);
3858 /* throw exception */
3859 mono_mb_emit_exception (mb
, "IndexOutOfRangeException", NULL
);
3861 g_free (branch_positions
);
3865 emit_delegate_begin_invoke_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
3868 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3870 mono_mb_emit_ldarg (mb
, 0);
3871 mono_mb_emit_ldloc (mb
, params_var
);
3872 mono_mb_emit_icall (mb
, mono_delegate_begin_invoke
);
3873 mono_mb_emit_byte (mb
, CEE_RET
);
3877 emit_delegate_end_invoke_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
3880 params_var
= mono_mb_emit_save_args (mb
, sig
, FALSE
);
3882 mono_mb_emit_ldarg (mb
, 0);
3883 mono_mb_emit_ldloc (mb
, params_var
);
3884 mono_mb_emit_icall (mb
, mono_delegate_end_invoke
);
3886 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
3887 mono_mb_emit_byte (mb
, CEE_POP
);
3888 mono_mb_emit_byte (mb
, CEE_RET
);
3890 mono_mb_emit_restore_result (mb
, sig
->ret
);
3894 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
)
3896 int local_i
, local_len
, local_delegates
, local_d
, local_target
, local_res
;
3897 int pos0
, pos1
, pos2
;
3901 MonoType
*int32_type
= mono_get_int32_type ();
3902 MonoType
*object_type
= mono_get_object_type ();
3904 void_ret
= sig
->ret
->type
== MONO_TYPE_VOID
&& !method
->string_ctor
;
3906 /* allocate local 0 (object) */
3907 local_i
= mono_mb_add_local (mb
, int32_type
);
3908 local_len
= mono_mb_add_local (mb
, int32_type
);
3909 local_delegates
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_defaults
.array_class
));
3910 local_d
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_defaults
.multicastdelegate_class
));
3911 local_target
= mono_mb_add_local (mb
, object_type
);
3914 local_res
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_from_mono_type_internal (sig
->ret
)));
3916 g_assert (sig
->hasthis
);
3919 * {type: sig->ret} res;
3920 * if (delegates == null) {
3921 * return this.<target> ( args .. );
3923 * int i = 0, len = this.delegates.Length;
3925 * res = this.delegates [i].Invoke ( args .. );
3926 * } while (++i < len);
3931 /* this wrapper can be used in unmanaged-managed transitions */
3932 emit_thread_interrupt_checkpoint (mb
);
3934 /* delegates = this.delegates */
3935 mono_mb_emit_ldarg (mb
, 0);
3936 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoMulticastDelegate
, delegates
));
3937 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3938 mono_mb_emit_stloc (mb
, local_delegates
);
3940 /* if (delegates == null) */
3941 mono_mb_emit_ldloc (mb
, local_delegates
);
3942 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
3944 /* return target.<target_method|method_ptr> ( args .. ); */
3946 /* target = d.target; */
3947 mono_mb_emit_ldarg (mb
, 0);
3948 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, target
));
3949 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3950 mono_mb_emit_stloc (mb
, local_target
);
3952 /*static methods with bound first arg can have null target and still be bound*/
3953 if (!static_method_with_first_arg_bound
) {
3954 /* if target != null */
3955 mono_mb_emit_ldloc (mb
, local_target
);
3956 pos0
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
3958 /* then call this->method_ptr nonstatic */
3961 mono_mb_emit_exception_full (mb
, "System", "NotImplementedException", "");
3963 mono_mb_emit_ldloc (mb
, local_target
);
3964 for (i
= 0; i
< sig
->param_count
; ++i
)
3965 mono_mb_emit_ldarg (mb
, i
+ 1);
3966 mono_mb_emit_ldarg (mb
, 0);
3967 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
3968 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
3969 mono_mb_emit_ldarg (mb
, 0);
3970 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3971 mono_mb_emit_byte (mb
, CEE_MONO_LD_DELEGATE_METHOD_PTR
);
3972 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
3973 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, sig
);
3974 mono_mb_emit_byte (mb
, CEE_RET
);
3977 /* else [target == null] call this->method_ptr static */
3978 mono_mb_patch_branch (mb
, pos0
);
3982 if (!closed_over_null
) {
3983 /* if target_method is not really virtual, turn it into a direct call */
3984 if (!(target_method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || m_class_is_valuetype (target_class
)) {
3985 mono_mb_emit_ldarg (mb
, 1);
3986 for (i
= 1; i
< sig
->param_count
; ++i
)
3987 mono_mb_emit_ldarg (mb
, i
+ 1);
3988 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
3990 mono_mb_emit_ldarg (mb
, 1);
3991 mono_mb_emit_op (mb
, CEE_CASTCLASS
, target_class
);
3992 for (i
= 1; i
< sig
->param_count
; ++i
)
3993 mono_mb_emit_ldarg (mb
, i
+ 1);
3994 mono_mb_emit_op (mb
, CEE_CALLVIRT
, target_method
);
3997 mono_mb_emit_byte (mb
, CEE_LDNULL
);
3998 for (i
= 0; i
< sig
->param_count
; ++i
)
3999 mono_mb_emit_ldarg (mb
, i
+ 1);
4000 mono_mb_emit_op (mb
, CEE_CALL
, target_method
);
4003 if (static_method_with_first_arg_bound
) {
4004 mono_mb_emit_ldloc (mb
, local_target
);
4005 if (!MONO_TYPE_IS_REFERENCE (invoke_sig
->params
[0]))
4006 mono_mb_emit_op (mb
, CEE_UNBOX_ANY
, mono_class_from_mono_type_internal (invoke_sig
->params
[0]));
4008 for (i
= 0; i
< sig
->param_count
; ++i
)
4009 mono_mb_emit_ldarg (mb
, i
+ 1);
4010 mono_mb_emit_ldarg (mb
, 0);
4011 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoDelegate
, extra_arg
));
4012 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4013 mono_mb_emit_ldarg (mb
, 0);
4014 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4015 mono_mb_emit_byte (mb
, CEE_MONO_LD_DELEGATE_METHOD_PTR
);
4016 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4017 mono_mb_emit_op (mb
, CEE_MONO_CALLI_EXTRA_ARG
, invoke_sig
);
4020 mono_mb_emit_byte (mb
, CEE_RET
);
4022 /* else [delegates != null] */
4023 mono_mb_patch_branch (mb
, pos2
);
4025 /* len = delegates.Length; */
4026 mono_mb_emit_ldloc (mb
, local_delegates
);
4027 mono_mb_emit_byte (mb
, CEE_LDLEN
);
4028 mono_mb_emit_byte (mb
, CEE_CONV_I4
);
4029 mono_mb_emit_stloc (mb
, local_len
);
4032 mono_mb_emit_icon (mb
, 0);
4033 mono_mb_emit_stloc (mb
, local_i
);
4035 pos1
= mono_mb_get_label (mb
);
4037 /* d = delegates [i]; */
4038 mono_mb_emit_ldloc (mb
, local_delegates
);
4039 mono_mb_emit_ldloc (mb
, local_i
);
4040 mono_mb_emit_byte (mb
, CEE_LDELEM_REF
);
4041 mono_mb_emit_stloc (mb
, local_d
);
4043 /* res = d.Invoke ( args .. ); */
4044 mono_mb_emit_ldloc (mb
, local_d
);
4045 for (i
= 0; i
< sig
->param_count
; i
++)
4046 mono_mb_emit_ldarg (mb
, i
+ 1);
4048 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4051 mono_mb_emit_op (mb
, CEE_CALLVIRT
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
));
4052 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4055 mono_mb_emit_stloc (mb
, local_res
);
4058 mono_mb_emit_add_to_local (mb
, local_i
, 1);
4061 mono_mb_emit_ldloc (mb
, local_i
);
4062 mono_mb_emit_ldloc (mb
, local_len
);
4063 mono_mb_emit_branch_label (mb
, CEE_BLT
, pos1
);
4067 mono_mb_emit_ldloc (mb
, local_res
);
4068 mono_mb_emit_byte (mb
, CEE_RET
);
4072 mb_skip_visibility_ilgen (MonoMethodBuilder
*mb
)
4074 mb
->skip_visibility
= 1;
4078 mb_set_dynamic_ilgen (MonoMethodBuilder
*mb
)
4084 emit_synchronized_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoGenericContext
*ctx
, MonoGenericContainer
*container
, MonoMethod
*enter_method
, MonoMethod
*exit_method
, MonoMethod
*gettypefromhandle_method
)
4086 int i
, pos
, pos2
, this_local
, taken_local
, ret_local
= 0;
4087 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4088 MonoExceptionClause
*clause
;
4091 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4092 ret_local
= mono_mb_add_local (mb
, sig
->ret
);
4094 if (m_class_is_valuetype (method
->klass
) && !(method
->flags
& MONO_METHOD_ATTR_STATIC
)) {
4095 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4096 mono_class_set_type_load_failure (method
->klass
, "");
4097 /* This will throw the type load exception when the wrapper is compiled */
4098 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4099 mono_mb_emit_op (mb
, CEE_ISINST
, method
->klass
);
4100 mono_mb_emit_byte (mb
, CEE_POP
);
4102 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4103 mono_mb_emit_ldloc (mb
, ret_local
);
4104 mono_mb_emit_byte (mb
, CEE_RET
);
4109 MonoType
*object_type
= mono_get_object_type ();
4110 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
4112 this_local
= mono_mb_add_local (mb
, object_type
);
4113 taken_local
= mono_mb_add_local (mb
, boolean_type
);
4115 clause
= (MonoExceptionClause
*)mono_image_alloc0 (get_method_image (method
), sizeof (MonoExceptionClause
));
4116 clause
->flags
= MONO_EXCEPTION_CLAUSE_FINALLY
;
4118 /* Push this or the type object */
4119 if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
4120 /* We have special handling for this in the JIT */
4121 int index
= mono_mb_add_data (mb
, method
->klass
);
4122 mono_mb_add_data (mb
, mono_defaults
.typehandle_class
);
4123 mono_mb_emit_byte (mb
, CEE_LDTOKEN
);
4124 mono_mb_emit_i4 (mb
, index
);
4126 mono_mb_emit_managed_call (mb
, gettypefromhandle_method
, NULL
);
4129 mono_mb_emit_ldarg (mb
, 0);
4130 mono_mb_emit_stloc (mb
, this_local
);
4132 clause
->try_offset
= mono_mb_get_label (mb
);
4133 /* Call Monitor::Enter() */
4134 mono_mb_emit_ldloc (mb
, this_local
);
4135 mono_mb_emit_ldloc_addr (mb
, taken_local
);
4136 mono_mb_emit_managed_call (mb
, enter_method
, NULL
);
4138 /* Call the method */
4140 mono_mb_emit_ldarg (mb
, 0);
4141 for (i
= 0; i
< sig
->param_count
; i
++)
4142 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
4146 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
), NULL
);
4147 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4149 mono_mb_emit_managed_call (mb
, method
, NULL
);
4152 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4153 mono_mb_emit_stloc (mb
, ret_local
);
4155 pos
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4157 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
4158 clause
->handler_offset
= mono_mb_get_label (mb
);
4160 /* Call Monitor::Exit() if needed */
4161 mono_mb_emit_ldloc (mb
, taken_local
);
4162 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4163 mono_mb_emit_ldloc (mb
, this_local
);
4164 mono_mb_emit_managed_call (mb
, exit_method
, NULL
);
4165 mono_mb_patch_branch (mb
, pos2
);
4166 mono_mb_emit_byte (mb
, CEE_ENDFINALLY
);
4168 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4170 mono_mb_patch_branch (mb
, pos
);
4171 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4172 mono_mb_emit_ldloc (mb
, ret_local
);
4173 mono_mb_emit_byte (mb
, CEE_RET
);
4175 mono_mb_set_clauses (mb
, 1, clause
);
4179 emit_unbox_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
)
4181 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4183 mono_mb_emit_ldarg (mb
, 0);
4184 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
4185 mono_mb_emit_byte (mb
, CEE_ADD
);
4186 for (int i
= 0; i
< sig
->param_count
; ++i
)
4187 mono_mb_emit_ldarg (mb
, i
+ 1);
4188 mono_mb_emit_managed_call (mb
, method
, NULL
);
4189 mono_mb_emit_byte (mb
, CEE_RET
);
4193 emit_array_accessor_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*sig
, MonoGenericContext
*ctx
)
4195 MonoGenericContainer
*container
= NULL
;
4196 /* Call the method */
4198 mono_mb_emit_ldarg (mb
, 0);
4199 for (int i
= 0; i
< sig
->param_count
; i
++)
4200 mono_mb_emit_ldarg (mb
, i
+ (sig
->hasthis
== TRUE
));
4204 mono_mb_emit_managed_call (mb
, mono_class_inflate_generic_method_checked (method
, &container
->context
, error
), NULL
);
4205 g_assert (is_ok (error
)); /* FIXME don't swallow the error */
4207 mono_mb_emit_managed_call (mb
, method
, NULL
);
4209 mono_mb_emit_byte (mb
, CEE_RET
);
4213 emit_generic_array_helper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
4215 mono_mb_emit_ldarg (mb
, 0);
4216 for (int i
= 0; i
< csig
->param_count
; i
++)
4217 mono_mb_emit_ldarg (mb
, i
+ 1);
4218 mono_mb_emit_managed_call (mb
, method
, NULL
);
4219 mono_mb_emit_byte (mb
, CEE_RET
);
4223 emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
)
4225 MonoImage
*image
= get_method_image (method
);
4226 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
4227 int param_count
= sig
->param_count
+ sig
->hasthis
+ 1;
4228 int pos_leave
, coop_gc_var
= 0, coop_gc_stack_dummy
= 0;
4229 MonoExceptionClause
*clause
;
4230 MonoType
*object_type
= mono_get_object_type ();
4231 #if defined (TARGET_WASM)
4232 const gboolean do_blocking_transition
= FALSE
;
4234 const gboolean do_blocking_transition
= TRUE
;
4237 /* local 0 (temp for exception object) */
4238 mono_mb_add_local (mb
, object_type
);
4240 /* local 1 (temp for result) */
4241 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4242 mono_mb_add_local (mb
, sig
->ret
);
4244 if (do_blocking_transition
) {
4245 /* local 4, dummy local used to get a stack address for suspend funcs */
4246 coop_gc_stack_dummy
= mono_mb_add_local (mb
, mono_get_int_type ());
4247 /* local 5, the local to be used when calling the suspend funcs */
4248 coop_gc_var
= mono_mb_add_local (mb
, mono_get_int_type ());
4251 /* clear exception arg */
4252 mono_mb_emit_ldarg (mb
, param_count
- 1);
4253 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4254 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4256 if (do_blocking_transition
) {
4257 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
4258 mono_mb_emit_icall (mb
, mono_threads_enter_gc_unsafe_region_unbalanced
);
4259 mono_mb_emit_stloc (mb
, coop_gc_var
);
4263 clause
= (MonoExceptionClause
*)mono_image_alloc0 (image
, sizeof (MonoExceptionClause
));
4264 clause
->try_offset
= mono_mb_get_label (mb
);
4266 /* push method's args */
4267 for (int i
= 0; i
< param_count
- 1; i
++) {
4271 mono_mb_emit_ldarg (mb
, i
);
4273 /* get the byval type of the param */
4274 klass
= mono_class_from_mono_type_internal (csig
->params
[i
]);
4275 type
= m_class_get_byval_arg (klass
);
4277 /* unbox struct args */
4278 if (MONO_TYPE_ISSTRUCT (type
)) {
4279 mono_mb_emit_op (mb
, CEE_UNBOX
, klass
);
4281 /* byref args & and the "this" arg must remain a ptr.
4282 Otherwise make a copy of the value type */
4283 if (!(csig
->params
[i
]->byref
|| (i
== 0 && sig
->hasthis
)))
4284 mono_mb_emit_op (mb
, CEE_LDOBJ
, klass
);
4286 csig
->params
[i
] = object_type
;
4291 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
4292 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
4294 mono_mb_emit_op (mb
, CEE_CALL
, method
);
4296 /* save result at local 1 */
4297 if (!MONO_TYPE_IS_VOID (sig
->ret
))
4298 mono_mb_emit_stloc (mb
, 1);
4300 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
4303 clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
4304 clause
->try_len
= mono_mb_get_pos (mb
) - clause
->try_offset
;
4305 clause
->data
.catch_class
= mono_defaults
.object_class
;
4307 clause
->handler_offset
= mono_mb_get_label (mb
);
4309 /* store exception at local 0 */
4310 mono_mb_emit_stloc (mb
, 0);
4311 mono_mb_emit_ldarg (mb
, param_count
- 1);
4312 mono_mb_emit_ldloc (mb
, 0);
4313 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4314 mono_mb_emit_branch (mb
, CEE_LEAVE
);
4316 clause
->handler_len
= mono_mb_get_pos (mb
) - clause
->handler_offset
;
4318 mono_mb_set_clauses (mb
, 1, clause
);
4320 mono_mb_patch_branch (mb
, pos_leave
);
4323 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
4324 mono_mb_emit_ldloc (mb
, 1);
4326 /* box the return value */
4327 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
4328 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (sig
->ret
));
4331 if (do_blocking_transition
) {
4332 mono_mb_emit_ldloc (mb
, coop_gc_var
);
4333 mono_mb_emit_ldloc_addr (mb
, coop_gc_stack_dummy
);
4334 mono_mb_emit_icall (mb
, mono_threads_exit_gc_unsafe_region_unbalanced
);
4337 mono_mb_emit_byte (mb
, CEE_RET
);
4341 emit_marshal_custom_get_instance (MonoMethodBuilder
*mb
, MonoClass
*klass
, MonoMarshalSpec
*spec
)
4343 static MonoClass
*Marshal
= NULL
;
4344 static MonoMethod
*get_instance
;
4347 Marshal
= mono_class_try_get_marshal_class ();
4350 get_instance
= get_method_nofail (Marshal
, "GetCustomMarshalerInstance", 2, 0);
4351 g_assert (get_instance
);
4354 // HACK: We cannot use ldtoken in this type of wrapper.
4355 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4356 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
4357 mono_mb_emit_icall (mb
, mono_marshal_get_type_object
);
4358 mono_mb_emit_ldstr (mb
, g_strdup (spec
->data
.custom_data
.cookie
));
4360 mono_mb_emit_op (mb
, CEE_CALL
, get_instance
);
4364 emit_marshal_custom_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4365 MonoMarshalSpec
*spec
,
4366 int conv_arg
, MonoType
**conv_arg_type
,
4367 MarshalAction action
)
4372 static MonoClass
*ICustomMarshaler
= NULL
;
4373 static MonoMethod
*cleanup_native
, *cleanup_managed
;
4374 static MonoMethod
*marshal_managed_to_native
, *marshal_native_to_managed
;
4375 MonoMethodBuilder
*mb
= m
->mb
;
4379 MonoType
*int_type
= mono_get_int_type ();
4380 MonoType
*object_type
= mono_get_object_type ();
4382 if (!ICustomMarshaler
) {
4383 MonoClass
*klass
= mono_class_try_get_icustom_marshaler_class ();
4385 char *exception_msg
= g_strdup ("Current profile doesn't support ICustomMarshaler");
4386 /* Throw exception and emit compensation code if neccesary */
4388 case MARSHAL_ACTION_CONV_IN
:
4389 case MARSHAL_ACTION_CONV_RESULT
:
4390 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4391 if ((action
== MARSHAL_ACTION_CONV_RESULT
) || (action
== MARSHAL_ACTION_MANAGED_CONV_RESULT
))
4392 mono_mb_emit_byte (mb
, CEE_POP
);
4394 mono_mb_emit_exception_full (mb
, "System", "ApplicationException", exception_msg
);
4397 case MARSHAL_ACTION_PUSH
:
4398 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4406 cleanup_native
= get_method_nofail (klass
, "CleanUpNativeData", 1, 0);
4407 g_assert (cleanup_native
);
4408 cleanup_managed
= get_method_nofail (klass
, "CleanUpManagedData", 1, 0);
4409 g_assert (cleanup_managed
);
4410 marshal_managed_to_native
= get_method_nofail (klass
, "MarshalManagedToNative", 1, 0);
4411 g_assert (marshal_managed_to_native
);
4412 marshal_native_to_managed
= get_method_nofail (klass
, "MarshalNativeToManaged", 1, 0);
4413 g_assert (marshal_native_to_managed
);
4415 mono_memory_barrier ();
4416 ICustomMarshaler
= klass
;
4419 if (spec
->data
.custom_data
.image
)
4420 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, spec
->data
.custom_data
.image
, error
);
4422 mtype
= mono_reflection_type_from_name_checked (spec
->data
.custom_data
.custom_name
, m
->image
, error
);
4423 g_assert (mtype
!= NULL
);
4424 mono_error_assert_ok (error
);
4425 mklass
= mono_class_from_mono_type_internal (mtype
);
4426 g_assert (mklass
!= NULL
);
4429 case MARSHAL_ACTION_CONV_IN
:
4431 case MONO_TYPE_CLASS
:
4432 case MONO_TYPE_OBJECT
:
4433 case MONO_TYPE_STRING
:
4434 case MONO_TYPE_ARRAY
:
4435 case MONO_TYPE_SZARRAY
:
4436 case MONO_TYPE_VALUETYPE
:
4440 g_warning ("custom marshalling of type %x is currently not supported", t
->type
);
4441 g_assert_not_reached ();
4445 conv_arg
= mono_mb_add_local (mb
, int_type
);
4447 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4448 mono_mb_emit_stloc (mb
, conv_arg
);
4450 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4453 /* Minic MS.NET behavior */
4454 if (!t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
) && !(t
->attrs
& PARAM_ATTRIBUTE_IN
))
4457 /* Check for null */
4458 mono_mb_emit_ldarg (mb
, argnum
);
4460 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4461 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4463 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4465 mono_mb_emit_ldarg (mb
, argnum
);
4467 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
4469 if (t
->type
== MONO_TYPE_VALUETYPE
) {
4471 * Since we can't determine the type of the argument, we
4472 * will assume the unmanaged function takes a pointer.
4474 *conv_arg_type
= int_type
;
4476 mono_mb_emit_op (mb
, CEE_BOX
, mono_class_from_mono_type_internal (t
));
4479 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4480 mono_mb_emit_stloc (mb
, conv_arg
);
4482 mono_mb_patch_branch (mb
, pos2
);
4485 case MARSHAL_ACTION_CONV_OUT
:
4486 /* Check for null */
4487 mono_mb_emit_ldloc (mb
, conv_arg
);
4488 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4491 mono_mb_emit_ldarg (mb
, argnum
);
4493 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4495 mono_mb_emit_ldloc (mb
, conv_arg
);
4496 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4497 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
4498 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
4499 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4501 mono_mb_emit_ldloc (mb
, conv_arg
);
4502 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4504 /* We have nowhere to store the result */
4505 mono_mb_emit_byte (mb
, CEE_POP
);
4508 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4510 mono_mb_emit_ldloc (mb
, conv_arg
);
4512 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4514 mono_mb_patch_branch (mb
, pos2
);
4517 case MARSHAL_ACTION_PUSH
:
4519 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4521 mono_mb_emit_ldloc (mb
, conv_arg
);
4524 case MARSHAL_ACTION_CONV_RESULT
:
4525 loc1
= mono_mb_add_local (mb
, int_type
);
4527 mono_mb_emit_stloc (mb
, 3);
4529 mono_mb_emit_ldloc (mb
, 3);
4530 mono_mb_emit_stloc (mb
, loc1
);
4532 /* Check for null */
4533 mono_mb_emit_ldloc (mb
, 3);
4534 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4536 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4537 mono_mb_emit_byte (mb
, CEE_DUP
);
4539 mono_mb_emit_ldloc (mb
, 3);
4540 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4541 mono_mb_emit_stloc (mb
, 3);
4543 mono_mb_emit_ldloc (mb
, loc1
);
4544 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_native
);
4546 mono_mb_patch_branch (mb
, pos2
);
4549 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4550 conv_arg
= mono_mb_add_local (mb
, object_type
);
4552 mono_mb_emit_byte (mb
, CEE_LDNULL
);
4553 mono_mb_emit_stloc (mb
, conv_arg
);
4555 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4558 /* Check for null */
4559 mono_mb_emit_ldarg (mb
, argnum
);
4561 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4562 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4564 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4566 mono_mb_emit_ldarg (mb
, argnum
);
4568 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4570 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_native_to_managed
);
4571 mono_mb_emit_stloc (mb
, conv_arg
);
4573 mono_mb_patch_branch (mb
, pos2
);
4576 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4577 g_assert (!t
->byref
);
4579 loc1
= mono_mb_add_local (mb
, object_type
);
4581 mono_mb_emit_stloc (mb
, 3);
4583 mono_mb_emit_ldloc (mb
, 3);
4584 mono_mb_emit_stloc (mb
, loc1
);
4586 /* Check for null */
4587 mono_mb_emit_ldloc (mb
, 3);
4588 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4590 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4591 mono_mb_emit_byte (mb
, CEE_DUP
);
4593 mono_mb_emit_ldloc (mb
, 3);
4594 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4595 mono_mb_emit_stloc (mb
, 3);
4597 mono_mb_emit_ldloc (mb
, loc1
);
4598 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4600 mono_mb_patch_branch (mb
, pos2
);
4603 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4605 /* Check for null */
4606 mono_mb_emit_ldloc (mb
, conv_arg
);
4607 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4610 mono_mb_emit_ldarg (mb
, argnum
);
4612 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4614 mono_mb_emit_ldloc (mb
, conv_arg
);
4615 mono_mb_emit_op (mb
, CEE_CALLVIRT
, marshal_managed_to_native
);
4616 mono_mb_emit_byte (mb
, CEE_STIND_I
);
4619 /* Call CleanUpManagedData */
4620 emit_marshal_custom_get_instance (mb
, mklass
, spec
);
4622 mono_mb_emit_ldloc (mb
, conv_arg
);
4623 mono_mb_emit_op (mb
, CEE_CALLVIRT
, cleanup_managed
);
4625 mono_mb_patch_branch (mb
, pos2
);
4629 g_assert_not_reached ();
4635 emit_marshal_asany_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4636 MonoMarshalSpec
*spec
,
4637 int conv_arg
, MonoType
**conv_arg_type
,
4638 MarshalAction action
)
4640 MonoMethodBuilder
*mb
= m
->mb
;
4642 MonoType
*int_type
= mono_get_int_type ();
4644 case MARSHAL_ACTION_CONV_IN
: {
4645 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4647 g_assert (t
->type
== MONO_TYPE_OBJECT
);
4648 g_assert (!t
->byref
);
4650 conv_arg
= mono_mb_add_local (mb
, int_type
);
4651 mono_mb_emit_ldarg (mb
, argnum
);
4652 mono_mb_emit_icon (mb
, encoding
);
4653 mono_mb_emit_icon (mb
, t
->attrs
);
4654 mono_mb_emit_icall (mb
, mono_marshal_asany
);
4655 mono_mb_emit_stloc (mb
, conv_arg
);
4659 case MARSHAL_ACTION_PUSH
:
4660 mono_mb_emit_ldloc (mb
, conv_arg
);
4663 case MARSHAL_ACTION_CONV_OUT
: {
4664 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, NULL
);
4666 mono_mb_emit_ldarg (mb
, argnum
);
4667 mono_mb_emit_ldloc (mb
, conv_arg
);
4668 mono_mb_emit_icon (mb
, encoding
);
4669 mono_mb_emit_icon (mb
, t
->attrs
);
4670 mono_mb_emit_icall (mb
, mono_marshal_free_asany
);
4675 g_assert_not_reached ();
4681 emit_marshal_vtype_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4682 MonoMarshalSpec
*spec
,
4683 int conv_arg
, MonoType
**conv_arg_type
,
4684 MarshalAction action
)
4686 MonoMethodBuilder
*mb
= m
->mb
;
4687 MonoClass
*klass
, *date_time_class
;
4690 klass
= mono_class_from_mono_type_internal (t
);
4692 date_time_class
= mono_class_get_date_time_class ();
4694 MonoType
*int_type
= mono_get_int_type ();
4695 MonoType
*double_type
= m_class_get_byval_arg (mono_defaults
.double_class
);
4698 case MARSHAL_ACTION_CONV_IN
:
4699 if (klass
== date_time_class
) {
4700 /* Convert it to an OLE DATE type */
4701 static MonoMethod
*to_oadate
;
4704 to_oadate
= get_method_nofail (date_time_class
, "ToOADate", 0, 0);
4705 g_assert (to_oadate
);
4707 conv_arg
= mono_mb_add_local (mb
, double_type
);
4710 mono_mb_emit_ldarg (mb
, argnum
);
4711 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4714 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4716 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = double_type
;
4718 mono_mb_emit_ldarg_addr (mb
, argnum
);
4719 mono_mb_emit_managed_call (mb
, to_oadate
, NULL
);
4720 mono_mb_emit_stloc (mb
, conv_arg
);
4724 mono_mb_patch_branch (mb
, pos
);
4728 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4731 conv_arg
= mono_mb_add_local (mb
, int_type
);
4733 /* store the address of the source into local variable 0 */
4735 mono_mb_emit_ldarg (mb
, argnum
);
4737 mono_mb_emit_ldarg_addr (mb
, argnum
);
4739 mono_mb_emit_stloc (mb
, 0);
4741 /* allocate space for the native struct and
4742 * store the address into local variable 1 (dest) */
4743 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
4744 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
4745 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
4746 mono_mb_emit_stloc (mb
, conv_arg
);
4749 mono_mb_emit_ldloc (mb
, 0);
4750 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4753 if (!(t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4755 mono_mb_emit_ldloc (mb
, conv_arg
);
4756 mono_mb_emit_stloc (mb
, 1);
4758 /* emit valuetype conversion code */
4759 emit_struct_conv (mb
, klass
, FALSE
);
4763 mono_mb_patch_branch (mb
, pos
);
4766 case MARSHAL_ACTION_PUSH
:
4767 if (spec
&& spec
->native
== MONO_NATIVE_LPSTRUCT
) {
4769 g_assert (!t
->byref
);
4771 /* Have to change the signature since the vtype is passed byref */
4772 m
->csig
->params
[argnum
- m
->csig
->hasthis
] = int_type
;
4774 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4775 mono_mb_emit_ldarg_addr (mb
, argnum
);
4777 mono_mb_emit_ldloc (mb
, conv_arg
);
4781 if (klass
== date_time_class
) {
4783 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4785 mono_mb_emit_ldloc (mb
, conv_arg
);
4789 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4790 mono_mb_emit_ldarg (mb
, argnum
);
4793 mono_mb_emit_ldloc (mb
, conv_arg
);
4795 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
4796 mono_mb_emit_op (mb
, CEE_MONO_LDNATIVEOBJ
, klass
);
4800 case MARSHAL_ACTION_CONV_OUT
:
4801 if (klass
== date_time_class
) {
4802 /* Convert from an OLE DATE type */
4803 static MonoMethod
*from_oadate
;
4808 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4810 from_oadate
= get_method_nofail (date_time_class
, "FromOADate", 1, 0);
4811 g_assert (from_oadate
);
4813 mono_mb_emit_ldarg (mb
, argnum
);
4814 mono_mb_emit_ldloc (mb
, conv_arg
);
4815 mono_mb_emit_managed_call (mb
, from_oadate
, NULL
);
4816 mono_mb_emit_op (mb
, CEE_STOBJ
, date_time_class
);
4821 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4825 /* dst = argument */
4826 mono_mb_emit_ldarg (mb
, argnum
);
4827 mono_mb_emit_stloc (mb
, 1);
4829 mono_mb_emit_ldloc (mb
, 1);
4830 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4832 if (!((t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))) {
4833 /* src = tmp_locals [i] */
4834 mono_mb_emit_ldloc (mb
, conv_arg
);
4835 mono_mb_emit_stloc (mb
, 0);
4837 /* emit valuetype conversion code */
4838 emit_struct_conv (mb
, klass
, TRUE
);
4842 emit_struct_free (mb
, klass
, conv_arg
);
4845 mono_mb_patch_branch (mb
, pos
);
4848 case MARSHAL_ACTION_CONV_RESULT
:
4849 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
)) {
4850 mono_mb_emit_stloc (mb
, 3);
4854 /* load pointer to returned value type */
4855 g_assert (m
->vtaddr_var
);
4856 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
4857 /* store the address of the source into local variable 0 */
4858 mono_mb_emit_stloc (mb
, 0);
4860 mono_mb_emit_ldloc_addr (mb
, 3);
4861 mono_mb_emit_stloc (mb
, 1);
4863 /* emit valuetype conversion code */
4864 emit_struct_conv (mb
, klass
, TRUE
);
4867 case MARSHAL_ACTION_MANAGED_CONV_IN
:
4868 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4873 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
4875 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4879 mono_mb_emit_ldarg (mb
, argnum
);
4881 mono_mb_emit_ldarg_addr (mb
, argnum
);
4882 mono_mb_emit_stloc (mb
, 0);
4885 mono_mb_emit_ldloc (mb
, 0);
4886 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4889 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4890 mono_mb_emit_stloc (mb
, 1);
4892 /* emit valuetype conversion code */
4893 emit_struct_conv (mb
, klass
, TRUE
);
4896 mono_mb_patch_branch (mb
, pos
);
4899 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
4900 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
))
4902 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
) && !(t
->attrs
& PARAM_ATTRIBUTE_OUT
))
4905 /* Check for null */
4906 mono_mb_emit_ldarg (mb
, argnum
);
4907 pos2
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
4910 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
4911 mono_mb_emit_stloc (mb
, 0);
4914 mono_mb_emit_ldarg (mb
, argnum
);
4915 mono_mb_emit_stloc (mb
, 1);
4917 /* emit valuetype conversion code */
4918 emit_struct_conv (mb
, klass
, FALSE
);
4920 mono_mb_patch_branch (mb
, pos2
);
4923 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
4924 if (mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
) || m_class_is_enumtype (klass
)) {
4925 mono_mb_emit_stloc (mb
, 3);
4930 /* load pointer to returned value type */
4931 g_assert (m
->vtaddr_var
);
4932 mono_mb_emit_ldloc (mb
, m
->vtaddr_var
);
4934 /* store the address of the source into local variable 0 */
4935 mono_mb_emit_stloc (mb
, 0);
4936 /* allocate space for the native struct and
4937 * store the address into dst_ptr */
4938 m
->retobj_var
= mono_mb_add_local (mb
, int_type
);
4939 m
->retobj_class
= klass
;
4940 g_assert (m
->retobj_var
);
4941 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
4942 mono_mb_emit_byte (mb
, CEE_CONV_I
);
4943 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
4944 mono_mb_emit_stloc (mb
, 1);
4945 mono_mb_emit_ldloc (mb
, 1);
4946 mono_mb_emit_stloc (mb
, m
->retobj_var
);
4948 /* emit valuetype conversion code */
4949 emit_struct_conv (mb
, klass
, FALSE
);
4953 g_assert_not_reached ();
4959 emit_marshal_string_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
4960 MonoMarshalSpec
*spec
,
4961 int conv_arg
, MonoType
**conv_arg_type
,
4962 MarshalAction action
)
4964 MonoMethodBuilder
*mb
= m
->mb
;
4965 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
4966 MonoMarshalConv conv
= mono_marshal_get_string_to_ptr_conv (m
->piinfo
, spec
);
4969 MonoType
*int_type
= mono_get_int_type ();
4970 MonoType
*object_type
= mono_get_object_type ();
4972 case MARSHAL_ACTION_CONV_IN
:
4973 *conv_arg_type
= int_type
;
4974 conv_arg
= mono_mb_add_local (mb
, int_type
);
4977 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
4980 mono_mb_emit_ldarg (mb
, argnum
);
4981 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
4983 mono_mb_emit_ldarg (mb
, argnum
);
4986 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
4987 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
4988 mono_mb_emit_exception_marshal_directive (mb
, msg
);
4990 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
4992 mono_mb_emit_stloc (mb
, conv_arg
);
4996 case MARSHAL_ACTION_CONV_OUT
:
4997 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
4998 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
4999 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5000 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5004 if (encoding
== MONO_NATIVE_VBBYREFSTR
) {
5005 static MonoMethod
*m
;
5008 m
= get_method_nofail (mono_defaults
.string_class
, "get_Length", -1, 0);
5011 char *msg
= g_strdup ("VBByRefStr marshalling requires a ref parameter.");
5012 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5017 * Have to allocate a new string with the same length as the original, and
5018 * copy the contents of the buffer pointed to by CONV_ARG into it.
5020 g_assert (t
->byref
);
5021 mono_mb_emit_ldarg (mb
, argnum
);
5022 mono_mb_emit_ldloc (mb
, conv_arg
);
5023 mono_mb_emit_ldarg (mb
, argnum
);
5024 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5025 mono_mb_emit_managed_call (mb
, m
, NULL
);
5026 mono_mb_emit_icall (mb
, mono_string_new_len_wrapper
);
5027 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5028 } else if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5030 mono_mb_emit_ldarg (mb
, argnum
);
5031 mono_mb_emit_ldloc (mb
, conv_arg
);
5032 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
5033 mono_mb_emit_byte (mb
, stind_op
);
5038 mono_mb_emit_ldloc (mb
, conv_arg
);
5039 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5040 mono_mb_emit_icall (mb
, mono_free_bstr
);
5042 mono_mb_emit_icall (mb
, mono_marshal_free
);
5046 case MARSHAL_ACTION_PUSH
:
5047 if (t
->byref
&& encoding
!= MONO_NATIVE_VBBYREFSTR
)
5048 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5050 mono_mb_emit_ldloc (mb
, conv_arg
);
5053 case MARSHAL_ACTION_CONV_RESULT
:
5054 mono_mb_emit_stloc (mb
, 0);
5056 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5057 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5058 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5059 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5063 mono_mb_emit_ldloc (mb
, 0);
5064 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5065 mono_mb_emit_stloc (mb
, 3);
5067 /* free the string */
5068 mono_mb_emit_ldloc (mb
, 0);
5069 if (conv
== MONO_MARSHAL_CONV_BSTR_STR
)
5070 mono_mb_emit_icall (mb
, mono_free_bstr
);
5072 mono_mb_emit_icall (mb
, mono_marshal_free
);
5075 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5076 conv_arg
= mono_mb_add_local (mb
, object_type
);
5078 *conv_arg_type
= int_type
;
5081 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5085 conv
= mono_marshal_get_ptr_to_string_conv (m
->piinfo
, spec
, &need_free
);
5086 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5087 char *msg
= g_strdup_printf ("string marshalling conversion %d not implemented", encoding
);
5088 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5092 mono_mb_emit_ldarg (mb
, argnum
);
5094 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5095 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5096 mono_mb_emit_stloc (mb
, conv_arg
);
5099 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5103 mono_mb_emit_ldarg (mb
, argnum
);
5104 mono_mb_emit_ldloc (mb
, conv_arg
);
5105 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, &stind_op
));
5106 mono_mb_emit_byte (mb
, stind_op
);
5111 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5112 if (conv_to_icall (conv
, NULL
) == MONO_JIT_ICALL_mono_marshal_string_to_utf16
)
5113 /* We need to make a copy so the caller is able to free it */
5114 mono_mb_emit_icall (mb
, mono_marshal_string_to_utf16_copy
);
5116 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5117 mono_mb_emit_stloc (mb
, 3);
5121 g_assert_not_reached ();
5128 emit_marshal_safehandle_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5129 MonoMarshalSpec
*spec
, int conv_arg
,
5130 MonoType
**conv_arg_type
, MarshalAction action
)
5132 MonoMethodBuilder
*mb
= m
->mb
;
5133 MonoType
*int_type
= mono_get_int_type ();
5134 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
5137 case MARSHAL_ACTION_CONV_IN
: {
5138 int dar_release_slot
, pos
;
5140 conv_arg
= mono_mb_add_local (mb
, int_type
);
5141 *conv_arg_type
= int_type
;
5143 if (!sh_dangerous_add_ref
)
5144 init_safe_handle ();
5146 mono_mb_emit_ldarg (mb
, argnum
);
5147 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5148 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5150 mono_mb_patch_branch (mb
, pos
);
5152 /* Create local to hold the ref parameter to DangerousAddRef */
5153 dar_release_slot
= mono_mb_add_local (mb
, boolean_type
);
5155 /* set release = false; */
5156 mono_mb_emit_icon (mb
, 0);
5157 mono_mb_emit_stloc (mb
, dar_release_slot
);
5160 int old_handle_value_slot
= mono_mb_add_local (mb
, int_type
);
5163 mono_mb_emit_icon (mb
, 0);
5164 mono_mb_emit_stloc (mb
, conv_arg
);
5166 /* safehandle.DangerousAddRef (ref release) */
5167 mono_mb_emit_ldarg (mb
, argnum
);
5168 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5169 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5170 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5172 /* Pull the handle field from SafeHandle */
5173 mono_mb_emit_ldarg (mb
, argnum
);
5174 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5175 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5176 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5177 mono_mb_emit_byte (mb
, CEE_DUP
);
5178 mono_mb_emit_stloc (mb
, conv_arg
);
5179 mono_mb_emit_stloc (mb
, old_handle_value_slot
);
5182 /* safehandle.DangerousAddRef (ref release) */
5183 mono_mb_emit_ldarg (mb
, argnum
);
5184 mono_mb_emit_ldloc_addr (mb
, dar_release_slot
);
5185 mono_mb_emit_managed_call (mb
, sh_dangerous_add_ref
, NULL
);
5187 /* Pull the handle field from SafeHandle */
5188 mono_mb_emit_ldarg (mb
, argnum
);
5189 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5190 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5191 mono_mb_emit_stloc (mb
, conv_arg
);
5197 case MARSHAL_ACTION_PUSH
:
5199 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5201 mono_mb_emit_ldloc (mb
, conv_arg
);
5204 case MARSHAL_ACTION_CONV_OUT
: {
5205 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5206 int dar_release_slot
= conv_arg
+ 1;
5209 if (!sh_dangerous_release
)
5210 init_safe_handle ();
5213 /* If there was SafeHandle on input we have to release the reference to it */
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_byte (mb
, CEE_LDIND_I
);
5219 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5220 mono_mb_patch_branch (mb
, label_next
);
5224 ERROR_DECL (local_error
);
5228 * If the SafeHandle was marshalled on input we can skip the marshalling on
5229 * output if the handle value is identical.
5232 int old_handle_value_slot
= dar_release_slot
+ 1;
5233 mono_mb_emit_ldloc (mb
, old_handle_value_slot
);
5234 mono_mb_emit_ldloc (mb
, conv_arg
);
5235 label_next
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5239 * Create an empty SafeHandle (of correct derived type).
5241 * FIXME: If an out-of-memory situation or exception happens here we will
5242 * leak the handle. We should move the allocation of the SafeHandle to the
5243 * input marshalling code to prevent that.
5245 ctor
= mono_class_get_method_from_name_checked (t
->data
.klass
, ".ctor", 0, 0, local_error
);
5246 if (ctor
== NULL
|| !is_ok (local_error
)){
5247 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5248 mono_error_cleanup (local_error
);
5252 /* refval = new SafeHandleDerived ()*/
5253 mono_mb_emit_ldarg (mb
, argnum
);
5254 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5255 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5257 /* refval.handle = returned_handle */
5258 mono_mb_emit_ldarg (mb
, argnum
);
5259 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
5260 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5261 mono_mb_emit_ldloc (mb
, conv_arg
);
5262 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5265 mono_mb_patch_branch (mb
, label_next
);
5269 mono_mb_emit_ldloc (mb
, dar_release_slot
);
5270 label_next
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5271 mono_mb_emit_ldarg (mb
, argnum
);
5272 mono_mb_emit_managed_call (mb
, sh_dangerous_release
, NULL
);
5273 mono_mb_patch_branch (mb
, label_next
);
5278 case MARSHAL_ACTION_CONV_RESULT
: {
5280 MonoMethod
*ctor
= NULL
;
5281 int intptr_handle_slot
;
5283 if (mono_class_is_abstract (t
->data
.klass
)) {
5284 mono_mb_emit_byte (mb
, CEE_POP
);
5285 mono_mb_emit_exception_marshal_directive (mb
, g_strdup ("Returned SafeHandles should not be abstract"));
5289 ctor
= mono_class_get_method_from_name_checked (t
->data
.klass
, ".ctor", 0, 0, error
);
5290 if (ctor
== NULL
|| !is_ok (error
)){
5291 mono_error_cleanup (error
);
5292 mono_mb_emit_byte (mb
, CEE_POP
);
5293 mono_mb_emit_exception (mb
, "MissingMethodException", "paramterless constructor required");
5296 /* Store the IntPtr results into a local */
5297 intptr_handle_slot
= mono_mb_add_local (mb
, int_type
);
5298 mono_mb_emit_stloc (mb
, intptr_handle_slot
);
5300 /* Create return value */
5301 mono_mb_emit_op (mb
, CEE_NEWOBJ
, ctor
);
5302 mono_mb_emit_stloc (mb
, 3);
5304 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5305 mono_mb_emit_ldloc (mb
, 3);
5306 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoSafeHandle
, handle
));
5307 mono_mb_emit_ldloc (mb
, intptr_handle_slot
);
5308 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5312 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5313 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5316 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5317 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5320 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5321 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5324 printf ("Unhandled case for MarshalAction: %d\n", action
);
5331 emit_marshal_handleref_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5332 MonoMarshalSpec
*spec
, int conv_arg
,
5333 MonoType
**conv_arg_type
, MarshalAction action
)
5335 MonoMethodBuilder
*mb
= m
->mb
;
5337 MonoType
*int_type
= mono_get_int_type ();
5339 case MARSHAL_ACTION_CONV_IN
: {
5340 conv_arg
= mono_mb_add_local (mb
, int_type
);
5341 *conv_arg_type
= int_type
;
5344 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5345 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5348 mono_mb_emit_ldarg_addr (mb
, argnum
);
5349 mono_mb_emit_icon (mb
, MONO_STRUCT_OFFSET (MonoHandleRef
, handle
));
5350 mono_mb_emit_byte (mb
, CEE_ADD
);
5351 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5352 mono_mb_emit_stloc (mb
, conv_arg
);
5356 case MARSHAL_ACTION_PUSH
:
5357 mono_mb_emit_ldloc (mb
, conv_arg
);
5360 case MARSHAL_ACTION_CONV_OUT
: {
5361 /* no resource release required */
5365 case MARSHAL_ACTION_CONV_RESULT
: {
5366 char *msg
= g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5367 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5371 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5372 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5375 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5376 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5379 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5380 fprintf (stderr
, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5383 fprintf (stderr
, "Unhandled case for MarshalAction: %d\n", action
);
5390 emit_marshal_object_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5391 MonoMarshalSpec
*spec
,
5392 int conv_arg
, MonoType
**conv_arg_type
,
5393 MarshalAction action
)
5395 MonoMethodBuilder
*mb
= m
->mb
;
5396 MonoClass
*klass
= mono_class_from_mono_type_internal (t
);
5399 MonoType
*int_type
= mono_get_int_type ();
5401 case MARSHAL_ACTION_CONV_IN
:
5402 *conv_arg_type
= int_type
;
5403 conv_arg
= mono_mb_add_local (mb
, int_type
);
5405 m
->orig_conv_args
[argnum
] = 0;
5407 if (mono_class_from_mono_type_internal (t
) == mono_defaults
.object_class
) {
5408 char *msg
= g_strdup_printf ("Marshalling of type object is not implemented");
5409 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5413 if (m_class_is_delegate (klass
)) {
5415 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5416 char *msg
= g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5417 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5419 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5420 mono_mb_emit_stloc (mb
, conv_arg
);
5422 mono_mb_emit_ldarg (mb
, argnum
);
5423 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5424 mono_mb_emit_stloc (mb
, conv_arg
);
5426 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5427 MonoMarshalNative encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5428 MonoMarshalConv conv
= mono_marshal_get_stringbuilder_to_ptr_conv (m
->piinfo
, spec
);
5432 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5433 char *msg
= g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5434 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5440 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && (t
->attrs
& PARAM_ATTRIBUTE_OUT
))
5443 if (conv
== MONO_MARSHAL_CONV_INVALID
) {
5444 char *msg
= g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding
);
5445 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5449 mono_mb_emit_ldarg (mb
, argnum
);
5451 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5453 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5454 mono_mb_emit_stloc (mb
, conv_arg
);
5455 } else if (m_class_is_blittable (klass
)) {
5456 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5457 mono_mb_emit_stloc (mb
, conv_arg
);
5459 mono_mb_emit_ldarg (mb
, argnum
);
5460 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5462 mono_mb_emit_ldarg (mb
, argnum
);
5463 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5464 mono_mb_emit_stloc (mb
, conv_arg
);
5466 mono_mb_patch_branch (mb
, pos
);
5469 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5470 mono_mb_emit_stloc (mb
, conv_arg
);
5473 /* we dont need any conversions for out parameters */
5474 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5477 mono_mb_emit_ldarg (mb
, argnum
);
5478 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5481 mono_mb_emit_ldarg (mb
, argnum
);
5482 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5483 mono_mb_emit_byte (mb
, CEE_MONO_OBJADDR
);
5486 /* store the address of the source into local variable 0 */
5487 mono_mb_emit_stloc (mb
, 0);
5488 mono_mb_emit_ldloc (mb
, 0);
5489 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5491 /* allocate space for the native struct and store the address */
5492 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5493 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
5494 mono_mb_emit_byte (mb
, CEE_LOCALLOC
);
5495 mono_mb_emit_stloc (mb
, conv_arg
);
5498 /* Need to store the original buffer so we can free it later */
5499 m
->orig_conv_args
[argnum
] = mono_mb_add_local (mb
, int_type
);
5500 mono_mb_emit_ldloc (mb
, conv_arg
);
5501 mono_mb_emit_stloc (mb
, m
->orig_conv_args
[argnum
]);
5504 /* set the src_ptr */
5505 mono_mb_emit_ldloc (mb
, 0);
5506 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5507 mono_mb_emit_stloc (mb
, 0);
5510 mono_mb_emit_ldloc (mb
, conv_arg
);
5511 mono_mb_emit_stloc (mb
, 1);
5513 /* emit valuetype conversion code */
5514 emit_struct_conv (mb
, klass
, FALSE
);
5516 mono_mb_patch_branch (mb
, pos
);
5520 case MARSHAL_ACTION_CONV_OUT
:
5521 if (klass
== mono_class_try_get_stringbuilder_class ()) {
5523 MonoMarshalNative encoding
;
5524 MonoMarshalConv conv
;
5526 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5527 conv
= mono_marshal_get_ptr_to_stringbuilder_conv (m
->piinfo
, spec
, &need_free
);
5529 g_assert (encoding
!= -1);
5532 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5536 mono_mb_emit_ldarg (mb
, argnum
);
5537 mono_mb_emit_ldloc (mb
, conv_arg
);
5540 case MONO_NATIVE_LPWSTR
:
5541 mono_mb_emit_icall (mb
, mono_string_utf16_to_builder2
);
5543 case MONO_NATIVE_LPSTR
:
5544 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5546 case MONO_NATIVE_UTF8STR
:
5547 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5550 g_assert_not_reached ();
5553 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5554 } else if (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
)) {
5555 mono_mb_emit_ldarg (mb
, argnum
);
5556 mono_mb_emit_ldloc (mb
, conv_arg
);
5558 mono_mb_emit_icall_id (mb
, conv_to_icall (conv
, NULL
));
5562 mono_mb_emit_ldloc (mb
, conv_arg
);
5563 mono_mb_emit_icall (mb
, mono_marshal_free
);
5568 if (m_class_is_delegate (klass
)) {
5570 mono_mb_emit_ldarg (mb
, argnum
);
5571 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5572 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5573 mono_mb_emit_ldloc (mb
, conv_arg
);
5574 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5575 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5580 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5581 /* allocate a new object */
5582 mono_mb_emit_ldarg (mb
, argnum
);
5583 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5584 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5585 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5588 /* dst = *argument */
5589 mono_mb_emit_ldarg (mb
, argnum
);
5592 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5594 mono_mb_emit_stloc (mb
, 1);
5596 mono_mb_emit_ldloc (mb
, 1);
5597 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5599 if (t
->byref
|| (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5600 mono_mb_emit_ldloc (mb
, 1);
5601 mono_mb_emit_icon (mb
, MONO_ABI_SIZEOF (MonoObject
));
5602 mono_mb_emit_byte (mb
, CEE_ADD
);
5603 mono_mb_emit_stloc (mb
, 1);
5605 /* src = tmp_locals [i] */
5606 mono_mb_emit_ldloc (mb
, conv_arg
);
5607 mono_mb_emit_stloc (mb
, 0);
5609 /* emit valuetype conversion code */
5610 emit_struct_conv (mb
, klass
, TRUE
);
5612 /* Free the structure returned by the native code */
5613 emit_struct_free (mb
, klass
, conv_arg
);
5615 if (m
->orig_conv_args
[argnum
]) {
5617 * If the native function changed the pointer, then free
5618 * the original structure plus the new pointer.
5620 mono_mb_emit_ldloc (mb
, m
->orig_conv_args
[argnum
]);
5621 mono_mb_emit_ldloc (mb
, conv_arg
);
5622 pos2
= mono_mb_emit_branch (mb
, CEE_BEQ
);
5624 if (!(t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
5625 g_assert (m
->orig_conv_args
[argnum
]);
5627 emit_struct_free (mb
, klass
, m
->orig_conv_args
[argnum
]);
5630 mono_mb_emit_ldloc (mb
, conv_arg
);
5631 mono_mb_emit_icall (mb
, mono_marshal_free
);
5633 mono_mb_patch_branch (mb
, pos2
);
5637 /* Free the original structure passed to native code */
5638 emit_struct_free (mb
, klass
, conv_arg
);
5640 mono_mb_patch_branch (mb
, pos
);
5643 case MARSHAL_ACTION_PUSH
:
5645 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5647 mono_mb_emit_ldloc (mb
, conv_arg
);
5650 case MARSHAL_ACTION_CONV_RESULT
:
5651 if (m_class_is_delegate (klass
)) {
5652 g_assert (!t
->byref
);
5653 mono_mb_emit_stloc (mb
, 0);
5654 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5655 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5656 mono_mb_emit_ldloc (mb
, 0);
5657 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5658 mono_mb_emit_stloc (mb
, 3);
5659 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5661 char *msg
= g_strdup_printf ("Return marshalling of stringbuilders is not implemented.");
5662 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5665 mono_mb_emit_stloc (mb
, 0);
5667 /* Make a copy since emit_conv modifies local 0 */
5668 loc
= mono_mb_add_local (mb
, int_type
);
5669 mono_mb_emit_ldloc (mb
, 0);
5670 mono_mb_emit_stloc (mb
, loc
);
5672 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5673 mono_mb_emit_stloc (mb
, 3);
5675 mono_mb_emit_ldloc (mb
, 0);
5676 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5678 /* allocate result object */
5680 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5681 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5682 mono_mb_emit_stloc (mb
, 3);
5686 mono_mb_emit_ldloc (mb
, 3);
5687 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5688 mono_mb_emit_stloc (mb
, 1);
5690 /* emit conversion code */
5691 emit_struct_conv (mb
, klass
, TRUE
);
5693 emit_struct_free (mb
, klass
, loc
);
5695 /* Free the pointer allocated by unmanaged code */
5696 mono_mb_emit_ldloc (mb
, loc
);
5697 mono_mb_emit_icall (mb
, mono_marshal_free
);
5698 mono_mb_patch_branch (mb
, pos
);
5702 case MARSHAL_ACTION_MANAGED_CONV_IN
:
5703 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
5705 if (m_class_is_delegate (klass
)) {
5706 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5707 mono_mb_emit_op (mb
, CEE_MONO_CLASSCONST
, klass
);
5708 mono_mb_emit_ldarg (mb
, argnum
);
5710 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5711 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL
, NULL
));
5712 mono_mb_emit_stloc (mb
, conv_arg
);
5716 if (klass
== mono_class_try_get_stringbuilder_class ()) {
5717 MonoMarshalNative encoding
;
5719 encoding
= mono_marshal_get_string_encoding (m
->piinfo
, spec
);
5722 g_assert (encoding
== MONO_NATIVE_LPSTR
|| encoding
== MONO_NATIVE_UTF8STR
);
5724 g_assert (!t
->byref
);
5725 g_assert (encoding
!= -1);
5727 mono_mb_emit_ldarg (mb
, argnum
);
5728 mono_mb_emit_icall (mb
, mono_string_utf8_to_builder2
);
5729 mono_mb_emit_stloc (mb
, conv_arg
);
5733 /* The class can not have an automatic layout */
5734 if (mono_class_is_auto_layout (klass
)) {
5735 mono_mb_emit_auto_layout_exception (mb
, klass
);
5739 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
5740 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5741 mono_mb_emit_stloc (mb
, conv_arg
);
5746 mono_mb_emit_ldarg (mb
, argnum
);
5750 /* Check for NULL and raise an exception */
5751 pos2
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5753 mono_mb_emit_exception (mb
, "ArgumentNullException", NULL
);
5755 mono_mb_patch_branch (mb
, pos2
);
5756 mono_mb_emit_ldarg (mb
, argnum
);
5757 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
5760 mono_mb_emit_stloc (mb
, 0);
5762 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5763 mono_mb_emit_stloc (mb
, conv_arg
);
5765 mono_mb_emit_ldloc (mb
, 0);
5766 pos
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
5768 /* Create and set dst */
5769 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
5770 mono_mb_emit_op (mb
, CEE_MONO_NEWOBJ
, klass
);
5771 mono_mb_emit_stloc (mb
, conv_arg
);
5772 mono_mb_emit_ldloc (mb
, conv_arg
);
5773 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5774 mono_mb_emit_stloc (mb
, 1);
5776 /* emit valuetype conversion code */
5777 emit_struct_conv (mb
, klass
, TRUE
);
5779 mono_mb_patch_branch (mb
, pos
);
5782 case MARSHAL_ACTION_MANAGED_CONV_OUT
:
5783 if (m_class_is_delegate (klass
)) {
5786 mono_mb_emit_ldarg (mb
, argnum
);
5787 mono_mb_emit_ldloc (mb
, conv_arg
);
5788 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, &stind_op
));
5789 mono_mb_emit_byte (mb
, stind_op
);
5795 /* Check for null */
5796 mono_mb_emit_ldloc (mb
, conv_arg
);
5797 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5798 mono_mb_emit_ldarg (mb
, argnum
);
5799 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
5800 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5801 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
5803 mono_mb_patch_branch (mb
, pos
);
5806 mono_mb_emit_ldloc (mb
, conv_arg
);
5807 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5808 mono_mb_emit_stloc (mb
, 0);
5810 /* Allocate and set dest */
5811 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5812 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5813 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5814 mono_mb_emit_stloc (mb
, 1);
5816 /* Update argument pointer */
5817 mono_mb_emit_ldarg (mb
, argnum
);
5818 mono_mb_emit_ldloc (mb
, 1);
5819 mono_mb_emit_byte (mb
, CEE_STIND_I
);
5821 /* emit valuetype conversion code */
5822 emit_struct_conv (mb
, klass
, FALSE
);
5824 mono_mb_patch_branch (mb
, pos2
);
5825 } else if (klass
== mono_class_try_get_stringbuilder_class ()) {
5826 // FIXME: What to do here ?
5828 /* byval [Out] marshalling */
5830 /* FIXME: Handle null */
5833 mono_mb_emit_ldloc (mb
, conv_arg
);
5834 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5835 mono_mb_emit_stloc (mb
, 0);
5838 mono_mb_emit_ldarg (mb
, argnum
);
5839 mono_mb_emit_stloc (mb
, 1);
5841 /* emit valuetype conversion code */
5842 emit_struct_conv (mb
, klass
, FALSE
);
5846 case MARSHAL_ACTION_MANAGED_CONV_RESULT
:
5847 if (m_class_is_delegate (klass
)) {
5848 mono_mb_emit_icall_id (mb
, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN
, NULL
));
5849 mono_mb_emit_stloc (mb
, 3);
5853 /* The class can not have an automatic layout */
5854 if (mono_class_is_auto_layout (klass
)) {
5855 mono_mb_emit_auto_layout_exception (mb
, klass
);
5859 mono_mb_emit_stloc (mb
, 0);
5860 /* Check for null */
5861 mono_mb_emit_ldloc (mb
, 0);
5862 pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
5863 mono_mb_emit_byte (mb
, CEE_LDNULL
);
5864 mono_mb_emit_stloc (mb
, 3);
5865 pos2
= mono_mb_emit_branch (mb
, CEE_BR
);
5867 mono_mb_patch_branch (mb
, pos
);
5870 mono_mb_emit_ldloc (mb
, 0);
5871 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
5872 mono_mb_emit_stloc (mb
, 0);
5874 /* Allocate and set dest */
5875 mono_mb_emit_icon (mb
, mono_class_native_size (klass
, NULL
));
5876 mono_mb_emit_byte (mb
, CEE_CONV_I
);
5877 mono_mb_emit_icall (mb
, ves_icall_marshal_alloc
);
5878 mono_mb_emit_byte (mb
, CEE_DUP
);
5879 mono_mb_emit_stloc (mb
, 1);
5880 mono_mb_emit_stloc (mb
, 3);
5882 emit_struct_conv (mb
, klass
, FALSE
);
5884 mono_mb_patch_branch (mb
, pos2
);
5888 g_assert_not_reached ();
5895 emit_marshal_variant_ilgen (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
5896 MonoMarshalSpec
*spec
,
5897 int conv_arg
, MonoType
**conv_arg_type
,
5898 MarshalAction action
)
5901 MonoMethodBuilder
*mb
= m
->mb
;
5902 static MonoMethod
*get_object_for_native_variant
= NULL
;
5903 static MonoMethod
*get_native_variant_for_object
= NULL
;
5904 MonoType
*variant_type
= m_class_get_byval_arg (mono_class_get_variant_class ());
5905 MonoType
*variant_type_byref
= m_class_get_this_arg (mono_class_get_variant_class ());
5906 MonoType
*object_type
= mono_get_object_type ();
5908 if (!get_object_for_native_variant
)
5909 get_object_for_native_variant
= get_method_nofail (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0);
5910 g_assert (get_object_for_native_variant
);
5912 if (!get_native_variant_for_object
)
5913 get_native_variant_for_object
= get_method_nofail (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0);
5914 g_assert (get_native_variant_for_object
);
5917 case MARSHAL_ACTION_CONV_IN
: {
5918 conv_arg
= mono_mb_add_local (mb
, variant_type
);
5921 *conv_arg_type
= variant_type_byref
;
5923 *conv_arg_type
= variant_type
;
5925 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5928 mono_mb_emit_ldarg (mb
, argnum
);
5930 mono_mb_emit_byte(mb
, CEE_LDIND_REF
);
5931 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5932 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
5936 case MARSHAL_ACTION_CONV_OUT
: {
5937 static MonoMethod
*variant_clear
= NULL
;
5940 variant_clear
= get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
5941 g_assert (variant_clear
);
5944 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5945 mono_mb_emit_ldarg (mb
, argnum
);
5946 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5947 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
5948 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
5951 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5952 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
5956 case MARSHAL_ACTION_PUSH
:
5958 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
5960 mono_mb_emit_ldloc (mb
, conv_arg
);
5963 case MARSHAL_ACTION_CONV_RESULT
: {
5964 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
5965 mono_mb_emit_exception_marshal_directive (mb
, msg
);
5969 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
5970 conv_arg
= mono_mb_add_local (mb
, object_type
);
5973 *conv_arg_type
= variant_type_byref
;
5975 *conv_arg_type
= variant_type
;
5977 if (t
->byref
&& !(t
->attrs
& PARAM_ATTRIBUTE_IN
) && t
->attrs
& PARAM_ATTRIBUTE_OUT
)
5981 mono_mb_emit_ldarg (mb
, argnum
);
5983 mono_mb_emit_ldarg_addr (mb
, argnum
);
5984 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
5985 mono_mb_emit_stloc (mb
, conv_arg
);
5989 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
5990 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
|| !(t
->attrs
& PARAM_ATTRIBUTE_IN
))) {
5991 mono_mb_emit_ldloc (mb
, conv_arg
);
5992 mono_mb_emit_ldarg (mb
, argnum
);
5993 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
5998 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
5999 char *msg
= g_strdup ("Marshalling of VARIANT not supported as a return type.");
6000 mono_mb_emit_exception_marshal_directive (mb
, msg
);
6005 g_assert_not_reached ();
6007 #endif /* DISABLE_COM */
6013 emit_managed_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*invoke_sig
, MonoMarshalSpec
**mspecs
, EmitMarshalContext
* m
, MonoMethod
*method
, uint32_t target_handle
)
6015 MonoMethodSignature
*sig
, *csig
;
6016 int i
, *tmp_locals
, orig_domain
, attach_cookie
;
6017 gboolean closed
= FALSE
;
6022 MonoType
*int_type
= mono_get_int_type ();
6023 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
6024 /* allocate local 0 (pointer) src_ptr */
6025 mono_mb_add_local (mb
, int_type
);
6026 /* allocate local 1 (pointer) dst_ptr */
6027 mono_mb_add_local (mb
, int_type
);
6028 /* allocate local 2 (boolean) delete_old */
6029 mono_mb_add_local (mb
, boolean_type
);
6031 if (!sig
->hasthis
&& sig
->param_count
!= invoke_sig
->param_count
) {
6032 /* Closed delegate */
6033 g_assert (sig
->param_count
== invoke_sig
->param_count
+ 1);
6035 /* Use a new signature without the first argument */
6036 sig
= mono_metadata_signature_dup (sig
);
6037 memmove (&sig
->params
[0], &sig
->params
[1], (sig
->param_count
- 1) * sizeof (MonoType
*));
6038 sig
->param_count
--;
6041 if (!MONO_TYPE_IS_VOID(sig
->ret
)) {
6042 /* allocate local 3 to store the return value */
6043 mono_mb_add_local (mb
, sig
->ret
);
6046 if (MONO_TYPE_ISSTRUCT (sig
->ret
))
6047 m
->vtaddr_var
= mono_mb_add_local (mb
, int_type
);
6049 orig_domain
= mono_mb_add_local (mb
, int_type
);
6050 attach_cookie
= mono_mb_add_local (mb
, int_type
);
6053 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
6054 * intptr_t attach_cookie;
6055 * intptr_t orig_domain = mono_threads_attach_coop (domain, &attach_cookie);
6058 * ret = method (...);
6059 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
6060 * mono_threads_detach_coop (orig_domain, &attach_cookie);
6065 mono_mb_emit_icon (mb
, 0);
6066 mono_mb_emit_stloc (mb
, 2);
6068 /* orig_domain = mono_threads_attach_coop (domain, &attach_cookie); */
6069 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6070 mono_mb_emit_byte (mb
, CEE_MONO_LDDOMAIN
);
6071 mono_mb_emit_ldloc_addr (mb
, attach_cookie
);
6073 * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads.
6074 * Keep this in sync with the CEE_JIT_ICALL code in the JIT.
6076 * Special cased in interpreter, keep in sync.
6078 mono_mb_emit_icall (mb
, mono_threads_attach_coop
);
6079 mono_mb_emit_stloc (mb
, orig_domain
);
6081 /* <interrupt check> */
6082 emit_thread_interrupt_checkpoint (mb
);
6084 /* we first do all conversions */
6085 tmp_locals
= g_newa (int, sig
->param_count
);
6086 for (i
= 0; i
< sig
->param_count
; i
++) {
6087 MonoType
*t
= sig
->params
[i
];
6090 case MONO_TYPE_OBJECT
:
6091 case MONO_TYPE_CLASS
:
6092 case MONO_TYPE_VALUETYPE
:
6093 case MONO_TYPE_ARRAY
:
6094 case MONO_TYPE_SZARRAY
:
6095 case MONO_TYPE_STRING
:
6096 case MONO_TYPE_BOOLEAN
:
6097 tmp_locals
[i
] = mono_emit_marshal (m
, i
, sig
->params
[i
], mspecs
[i
+ 1], 0, &csig
->params
[i
], MARSHAL_ACTION_MANAGED_CONV_IN
);
6106 if (target_handle
) {
6107 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
6108 mono_mb_emit_icall (mb
, mono_gchandle_get_target_internal
);
6111 g_assert_not_reached ();
6113 } else if (closed
) {
6114 mono_mb_emit_icon (mb
, (gint32
)target_handle
);
6115 mono_mb_emit_icall (mb
, mono_gchandle_get_target_internal
);
6118 for (i
= 0; i
< sig
->param_count
; i
++) {
6119 MonoType
*t
= sig
->params
[i
];
6121 if (tmp_locals
[i
]) {
6123 mono_mb_emit_ldloc_addr (mb
, tmp_locals
[i
]);
6125 mono_mb_emit_ldloc (mb
, tmp_locals
[i
]);
6128 mono_mb_emit_ldarg (mb
, i
);
6131 /* ret = method (...) */
6132 mono_mb_emit_managed_call (mb
, method
, NULL
);
6134 if (MONO_TYPE_ISSTRUCT (sig
->ret
)) {
6135 MonoClass
*klass
= mono_class_from_mono_type_internal (sig
->ret
);
6136 mono_class_init_internal (klass
);
6137 if (!(mono_class_is_explicit_layout (klass
) || m_class_is_blittable (klass
))) {
6138 /* This is used by get_marshal_cb ()->emit_marshal_vtype (), but it needs to go right before the call */
6139 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6140 mono_mb_emit_byte (mb
, CEE_MONO_VTADDR
);
6141 mono_mb_emit_stloc (mb
, m
->vtaddr_var
);
6145 if (mspecs
[0] && mspecs
[0]->native
== MONO_NATIVE_CUSTOM
) {
6146 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6147 } else if (!sig
->ret
->byref
) {
6148 switch (sig
->ret
->type
) {
6149 case MONO_TYPE_VOID
:
6151 case MONO_TYPE_BOOLEAN
:
6154 case MONO_TYPE_CHAR
:
6166 case MONO_TYPE_OBJECT
:
6167 mono_mb_emit_stloc (mb
, 3);
6169 case MONO_TYPE_STRING
:
6170 csig
->ret
= int_type
;
6171 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6173 case MONO_TYPE_VALUETYPE
:
6174 case MONO_TYPE_CLASS
:
6175 case MONO_TYPE_SZARRAY
:
6176 mono_emit_marshal (m
, 0, sig
->ret
, mspecs
[0], 0, NULL
, MARSHAL_ACTION_MANAGED_CONV_RESULT
);
6179 g_warning ("return type 0x%02x unknown", sig
->ret
->type
);
6180 g_assert_not_reached ();
6183 mono_mb_emit_stloc (mb
, 3);
6186 /* Convert byref arguments back */
6187 for (i
= 0; i
< sig
->param_count
; i
++) {
6188 MonoType
*t
= sig
->params
[i
];
6189 MonoMarshalSpec
*spec
= mspecs
[i
+ 1];
6191 if (spec
&& spec
->native
== MONO_NATIVE_CUSTOM
) {
6192 mono_emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6194 else if (t
->byref
) {
6196 case MONO_TYPE_CLASS
:
6197 case MONO_TYPE_VALUETYPE
:
6198 case MONO_TYPE_OBJECT
:
6199 case MONO_TYPE_STRING
:
6200 case MONO_TYPE_BOOLEAN
:
6201 mono_emit_marshal (m
, i
, t
, mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6207 else if (invoke_sig
->params
[i
]->attrs
& PARAM_ATTRIBUTE_OUT
) {
6208 /* The [Out] information is encoded in the delegate signature */
6210 case MONO_TYPE_SZARRAY
:
6211 case MONO_TYPE_CLASS
:
6212 case MONO_TYPE_VALUETYPE
:
6213 mono_emit_marshal (m
, i
, invoke_sig
->params
[i
], mspecs
[i
+ 1], tmp_locals
[i
], NULL
, MARSHAL_ACTION_MANAGED_CONV_OUT
);
6216 g_assert_not_reached ();
6221 /* mono_threads_detach_coop (orig_domain, &attach_cookie); */
6222 mono_mb_emit_ldloc (mb
, orig_domain
);
6223 mono_mb_emit_ldloc_addr (mb
, attach_cookie
);
6224 /* Special cased in interpreter, keep in sync */
6225 mono_mb_emit_icall (mb
, mono_threads_detach_coop
);
6228 if (m
->retobj_var
) {
6229 mono_mb_emit_ldloc (mb
, m
->retobj_var
);
6230 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6231 mono_mb_emit_op (mb
, CEE_MONO_RETOBJ
, m
->retobj_class
);
6234 if (!MONO_TYPE_IS_VOID (sig
->ret
))
6235 mono_mb_emit_ldloc (mb
, 3);
6236 mono_mb_emit_byte (mb
, CEE_RET
);
6244 emit_struct_to_ptr_ilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
6246 MonoType
*int_type
= mono_get_int_type ();
6247 MonoType
*boolean_type
= m_class_get_byval_arg (mono_defaults
.boolean_class
);
6248 if (m_class_is_blittable (klass
)) {
6249 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6250 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6251 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6252 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
6253 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6254 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6257 /* allocate local 0 (pointer) src_ptr */
6258 mono_mb_add_local (mb
, int_type
);
6259 /* allocate local 1 (pointer) dst_ptr */
6260 mono_mb_add_local (mb
, int_type
);
6261 /* allocate local 2 (boolean) delete_old */
6262 mono_mb_add_local (mb
, boolean_type
);
6263 mono_mb_emit_byte (mb
, CEE_LDARG_2
);
6264 mono_mb_emit_stloc (mb
, 2);
6266 /* initialize src_ptr to point to the start of object data */
6267 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6268 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6269 mono_mb_emit_stloc (mb
, 0);
6271 /* initialize dst_ptr */
6272 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6273 mono_mb_emit_stloc (mb
, 1);
6275 emit_struct_conv (mb
, klass
, FALSE
);
6278 mono_mb_emit_byte (mb
, CEE_RET
);
6282 emit_ptr_to_struct_ilgen (MonoMethodBuilder
*mb
, MonoClass
*klass
)
6284 MonoType
*int_type
= mono_get_int_type ();
6285 if (m_class_is_blittable (klass
)) {
6286 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6287 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6288 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6289 mono_mb_emit_icon (mb
, mono_class_value_size (klass
, NULL
));
6290 mono_mb_emit_byte (mb
, CEE_PREFIX1
);
6291 mono_mb_emit_byte (mb
, CEE_CPBLK
);
6294 /* allocate local 0 (pointer) src_ptr */
6295 mono_mb_add_local (mb
, int_type
);
6296 /* allocate local 1 (pointer) dst_ptr */
6297 mono_mb_add_local (mb
, m_class_get_this_arg (klass
));
6299 /* initialize src_ptr to point to the start of object data */
6300 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6301 mono_mb_emit_stloc (mb
, 0);
6303 /* initialize dst_ptr */
6304 mono_mb_emit_byte (mb
, CEE_LDARG_1
);
6305 mono_mb_emit_ldflda (mb
, MONO_ABI_SIZEOF (MonoObject
));
6306 mono_mb_emit_stloc (mb
, 1);
6308 emit_struct_conv (mb
, klass
, TRUE
);
6311 mono_mb_emit_byte (mb
, CEE_RET
);
6315 emit_create_string_hack_ilgen (MonoMethodBuilder
*mb
, MonoMethodSignature
*csig
, MonoMethod
*res
)
6318 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6319 for (i
= 1; i
<= csig
->param_count
; i
++)
6320 mono_mb_emit_ldarg (mb
, i
);
6321 mono_mb_emit_managed_call (mb
, res
, NULL
);
6322 mono_mb_emit_byte (mb
, CEE_RET
);
6325 /* How the arguments of an icall should be wrapped */
6327 /* Don't wrap at all, pass the argument as is */
6328 ICALL_HANDLES_WRAP_NONE
,
6329 /* Wrap the argument in an object handle, pass the handle to the icall */
6330 ICALL_HANDLES_WRAP_OBJ
,
6331 /* Wrap the argument in an object handle, pass the handle to the icall,
6332 write the value out from the handle when the icall returns */
6333 ICALL_HANDLES_WRAP_OBJ_INOUT
,
6334 /* Initialized an object handle to null, pass to the icalls,
6335 write the value out from the handle when the icall returns */
6336 ICALL_HANDLES_WRAP_OBJ_OUT
,
6337 /* Wrap the argument (a valuetype reference) in a handle to pin its
6338 enclosing object, but pass the raw reference to the icall. This is
6339 also how we pass byref generic parameter arguments to generic method
6340 icalls (e.g. System.Array:GetGenericValue_icall<T>(int idx, T out value)) */
6341 ICALL_HANDLES_WRAP_VALUETYPE_REF
,
6345 IcallHandlesWrap wrap
;
6346 // If wrap is OBJ_OUT or OBJ_INOUT this is >= 0 and holds the referenced managed object,
6347 // in case the actual parameter refers to a native frame.
6348 // Otherwise it is -1.
6350 } IcallHandlesLocal
;
6353 * Describes how to wrap the given parameter.
6356 static IcallHandlesWrap
6357 signature_param_uses_handles (MonoMethodSignature
*sig
, MonoMethodSignature
*generic_sig
, int param
)
6359 /* If there is a generic parameter that isn't passed byref, we don't
6360 * know how to pass it to an icall that expects some arguments to be
6361 * wrapped in handles: if the actual argument type is a reference type
6362 * we'd need to wrap it in a handle, otherwise we'd want to pass it as is.
6364 /* FIXME: We should eventually relax the assertion, below, to
6365 * allow generic parameters that are constrained to be reference types.
6367 g_assert (!generic_sig
|| !mono_type_is_generic_parameter (generic_sig
->params
[param
]));
6369 /* If the parameter in the generic version of the method signature is a
6370 * byref type variable T&, pass the corresponding argument by pinning
6371 * the memory and passing the raw pointer to the icall. Note that we
6372 * do this even if the actual instantiation is a byref reference type
6373 * like string& since the C code for the icall has to work uniformly
6374 * for both valuetypes and reference types.
6376 if (generic_sig
&& mono_type_is_byref_internal (generic_sig
->params
[param
]) &&
6377 (generic_sig
->params
[param
]->type
== MONO_TYPE_VAR
|| generic_sig
->params
[param
]->type
== MONO_TYPE_MVAR
))
6378 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
6380 if (MONO_TYPE_IS_REFERENCE (sig
->params
[param
])) {
6381 if (mono_signature_param_is_out (sig
, param
))
6382 return ICALL_HANDLES_WRAP_OBJ_OUT
;
6383 else if (mono_type_is_byref_internal (sig
->params
[param
]))
6384 return ICALL_HANDLES_WRAP_OBJ_INOUT
;
6386 return ICALL_HANDLES_WRAP_OBJ
;
6387 } else if (mono_type_is_byref_internal (sig
->params
[param
]))
6388 return ICALL_HANDLES_WRAP_VALUETYPE_REF
;
6390 return ICALL_HANDLES_WRAP_NONE
;
6394 emit_native_icall_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, MonoMethodSignature
*csig
, gboolean check_exceptions
, gboolean aot
, MonoMethodPInvoke
*piinfo
)
6397 MonoMethodSignature
*call_sig
= csig
;
6398 gboolean uses_handles
= FALSE
;
6399 gboolean foreign_icall
= FALSE
;
6400 IcallHandlesLocal
*handles_locals
= NULL
;
6401 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
6402 gboolean need_gc_safe
= FALSE
;
6403 GCSafeTransitionBuilder gc_safe_transition_builder
;
6405 (void) mono_lookup_internal_call_full (method
, FALSE
, &uses_handles
, &foreign_icall
);
6407 if (G_UNLIKELY (foreign_icall
)) {
6408 /* FIXME: we only want the transitions for hybrid suspend. Q: What to do about AOT? */
6409 need_gc_safe
= gc_safe_transition_builder_init (&gc_safe_transition_builder
, mb
, FALSE
);
6412 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder
);
6417 * Add a null check since public icalls can be called with 'call' which
6418 * does no such check.
6420 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6421 const int pos
= mono_mb_emit_branch (mb
, CEE_BRTRUE
);
6422 mono_mb_emit_exception (mb
, "NullReferenceException", NULL
);
6423 mono_mb_patch_branch (mb
, pos
);
6427 MonoMethodSignature
*generic_sig
= NULL
;
6429 if (method
->is_inflated
) {
6431 MonoMethod
*generic_method
= ((MonoMethodInflated
*)method
)->declaring
;
6432 generic_sig
= mono_method_signature_checked (generic_method
, error
);
6433 mono_error_assert_ok (error
);
6436 // Add a MonoError argument (due to a fragile test external/coreclr/tests/src/CoreMangLib/cti/system/weakreference/weakreferenceisaliveb.exe),
6437 // vs. on the native side.
6438 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
6439 call_sig
= mono_metadata_signature_alloc (get_method_image (method
), csig
->param_count
+ 1);
6440 call_sig
->param_count
= csig
->param_count
+ 1;
6441 call_sig
->ret
= csig
->ret
;
6442 call_sig
->pinvoke
= csig
->pinvoke
;
6444 /* TODO support adding wrappers to non-static struct methods */
6445 g_assert (!sig
->hasthis
|| !m_class_is_valuetype (mono_method_get_class (method
)));
6447 /* Add MonoError* param */
6448 MonoClass
* const error_class
= mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
6449 int const error_var
= mono_mb_add_local (mb
, m_class_get_byval_arg (error_class
));
6450 call_sig
->params
[csig
->param_count
] = mono_class_get_byref_type (error_class
);
6452 handles_locals
= g_new0 (IcallHandlesLocal
, csig
->param_count
);
6454 for (int i
= 0; i
< csig
->param_count
; ++i
) {
6455 // Determine which args need to be wrapped in handles and adjust icall signature.
6456 // Here, a handle is a pointer to a volatile local in a managed frame -- which is sufficient and efficient.
6457 const IcallHandlesWrap w
= signature_param_uses_handles (csig
, generic_sig
, i
);
6458 handles_locals
[i
].wrap
= w
;
6462 case ICALL_HANDLES_WRAP_OBJ
:
6463 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6464 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6465 call_sig
->params
[i
] = mono_class_get_byref_type (mono_class_from_mono_type_internal (csig
->params
[i
]));
6467 case ICALL_HANDLES_WRAP_NONE
:
6468 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6469 call_sig
->params
[i
] = csig
->params
[i
];
6472 g_assert_not_reached ();
6475 // Add a local var to hold the references for each out arg.
6477 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6478 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6479 // FIXME better type
6480 local
= mono_mb_add_local (mb
, mono_get_object_type ());
6482 if (!mb
->volatile_locals
) {
6483 gpointer mem
= mono_image_alloc0 (get_method_image (method
), mono_bitset_alloc_size (csig
->param_count
+ 1, 0));
6484 mb
->volatile_locals
= mono_bitset_mem_new (mem
, csig
->param_count
+ 1, 0);
6486 mono_bitset_set (mb
->volatile_locals
, local
);
6488 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6489 case ICALL_HANDLES_WRAP_OBJ
:
6490 if (!mb
->volatile_args
) {
6491 gpointer mem
= mono_image_alloc0 (get_method_image (method
), mono_bitset_alloc_size (csig
->param_count
+ 1, 0));
6492 mb
->volatile_args
= mono_bitset_mem_new (mem
, csig
->param_count
+ 1, 0);
6494 mono_bitset_set (mb
->volatile_args
, i
);
6496 case ICALL_HANDLES_WRAP_NONE
:
6499 g_assert_not_reached ();
6501 handles_locals
[i
].handle
= local
;
6503 // Load each argument. References into the managed heap get wrapped in handles.
6504 // Handles here are just pointers to managed volatile locals.
6506 case ICALL_HANDLES_WRAP_NONE
:
6507 case ICALL_HANDLES_WRAP_VALUETYPE_REF
:
6509 mono_mb_emit_ldarg (mb
, i
);
6511 case ICALL_HANDLES_WRAP_OBJ
:
6513 mono_mb_emit_ldarg_addr (mb
, i
);
6515 case ICALL_HANDLES_WRAP_OBJ_INOUT
:
6516 case ICALL_HANDLES_WRAP_OBJ_OUT
:
6517 // If parameter guaranteeably referred to a managed frame,
6518 // then could just be passthrough and volatile. Since
6519 // that cannot be guaranteed, use a managed volatile local intermediate.
6523 // localI = *argI_raw
6525 if (w
== ICALL_HANDLES_WRAP_OBJ_OUT
) {
6526 mono_mb_emit_byte (mb
, CEE_LDNULL
);
6528 mono_mb_emit_ldarg (mb
, i
);
6529 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
6531 mono_mb_emit_stloc (mb
, local
);
6532 mono_mb_emit_ldloc_addr (mb
, local
);
6535 g_assert_not_reached ();
6538 mono_mb_emit_ldloc_addr (mb
, error_var
);
6540 for (int i
= 0; i
< csig
->param_count
; i
++)
6541 mono_mb_emit_ldarg (mb
, i
);
6545 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder
, &piinfo
->method
, aot
);
6548 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6549 mono_mb_emit_op (mb
, CEE_MONO_ICALL_ADDR
, &piinfo
->method
);
6550 mono_mb_emit_calli (mb
, call_sig
);
6552 g_assert (piinfo
->addr
);
6553 mono_mb_emit_native_call (mb
, call_sig
, piinfo
->addr
);
6557 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder
);
6559 // Copy back ObjOut and ObjInOut from locals through parameters.
6560 if (mb
->volatile_locals
) {
6561 g_assert (handles_locals
);
6562 for (int i
= 0; i
< csig
->param_count
; i
++) {
6563 const int local
= handles_locals
[i
].handle
;
6565 // *argI_raw = localI
6566 mono_mb_emit_ldarg (mb
, i
);
6567 mono_mb_emit_ldloc (mb
, local
);
6568 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
6572 g_free (handles_locals
);
6575 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder
);
6577 if (check_exceptions
)
6578 emit_thread_interrupt_checkpoint (mb
);
6579 mono_mb_emit_byte (mb
, CEE_RET
);
6583 mb_emit_exception_ilgen (MonoMethodBuilder
*mb
, const char *exc_nspace
, const char *exc_name
, const char *msg
)
6585 mono_mb_emit_exception_full (mb
, exc_nspace
, exc_name
, msg
);
6589 mb_emit_exception_for_error_ilgen (MonoMethodBuilder
*mb
, const MonoError
*error
)
6591 mono_mb_emit_exception_for_error (mb
, (MonoError
*)error
);
6595 emit_vtfixup_ftnptr_ilgen (MonoMethodBuilder
*mb
, MonoMethod
*method
, int param_count
, guint16 type
)
6597 for (int i
= 0; i
< param_count
; i
++)
6598 mono_mb_emit_ldarg (mb
, i
);
6600 if (type
& VTFIXUP_TYPE_CALL_MOST_DERIVED
)
6601 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
6603 mono_mb_emit_op (mb
, CEE_CALL
, method
);
6604 mono_mb_emit_byte (mb
, CEE_RET
);
6608 emit_icall_wrapper_ilgen (MonoMethodBuilder
*mb
, MonoJitICallInfo
*callinfo
, MonoMethodSignature
*csig2
, gboolean check_exceptions
)
6610 MonoMethodSignature
*const sig
= callinfo
->sig
;
6613 mono_mb_emit_byte (mb
, CEE_LDARG_0
);
6615 for (int i
= 0; i
< sig
->param_count
; i
++)
6616 mono_mb_emit_ldarg (mb
, i
+ sig
->hasthis
);
6618 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
6619 mono_mb_emit_byte (mb
, CEE_MONO_JIT_ICALL_ADDR
);
6620 mono_mb_emit_i4 (mb
, mono_jit_icall_info_index (callinfo
));
6621 mono_mb_emit_calli (mb
, csig2
);
6622 if (check_exceptions
)
6623 emit_thread_interrupt_checkpoint (mb
);
6624 mono_mb_emit_byte (mb
, CEE_RET
);
6628 emit_return_ilgen (MonoMethodBuilder
*mb
)
6630 mono_mb_emit_byte (mb
, CEE_RET
);
6634 mono_marshal_ilgen_init (void)
6636 MonoMarshalCallbacks cb
;
6637 cb
.version
= MONO_MARSHAL_CALLBACKS_VERSION
;
6638 cb
.emit_marshal_array
= emit_marshal_array_ilgen
;
6639 cb
.emit_marshal_boolean
= emit_marshal_boolean_ilgen
;
6640 cb
.emit_marshal_ptr
= emit_marshal_ptr_ilgen
;
6641 cb
.emit_marshal_char
= emit_marshal_char_ilgen
;
6642 cb
.emit_marshal_scalar
= emit_marshal_scalar_ilgen
;
6643 cb
.emit_marshal_custom
= emit_marshal_custom_ilgen
;
6644 cb
.emit_marshal_asany
= emit_marshal_asany_ilgen
;
6645 cb
.emit_marshal_vtype
= emit_marshal_vtype_ilgen
;
6646 cb
.emit_marshal_string
= emit_marshal_string_ilgen
;
6647 cb
.emit_marshal_safehandle
= emit_marshal_safehandle_ilgen
;
6648 cb
.emit_marshal_handleref
= emit_marshal_handleref_ilgen
;
6649 cb
.emit_marshal_object
= emit_marshal_object_ilgen
;
6650 cb
.emit_marshal_variant
= emit_marshal_variant_ilgen
;
6651 cb
.emit_castclass
= emit_castclass_ilgen
;
6652 cb
.emit_struct_to_ptr
= emit_struct_to_ptr_ilgen
;
6653 cb
.emit_ptr_to_struct
= emit_ptr_to_struct_ilgen
;
6654 cb
.emit_isinst
= emit_isinst_ilgen
;
6655 cb
.emit_virtual_stelemref
= emit_virtual_stelemref_ilgen
;
6656 cb
.emit_stelemref
= emit_stelemref_ilgen
;
6657 cb
.emit_array_address
= emit_array_address_ilgen
;
6658 cb
.emit_native_wrapper
= emit_native_wrapper_ilgen
;
6659 cb
.emit_managed_wrapper
= emit_managed_wrapper_ilgen
;
6660 cb
.emit_runtime_invoke_body
= emit_runtime_invoke_body_ilgen
;
6661 cb
.emit_runtime_invoke_dynamic
= emit_runtime_invoke_dynamic_ilgen
;
6662 cb
.emit_delegate_begin_invoke
= emit_delegate_begin_invoke_ilgen
;
6663 cb
.emit_delegate_end_invoke
= emit_delegate_end_invoke_ilgen
;
6664 cb
.emit_delegate_invoke_internal
= emit_delegate_invoke_internal_ilgen
;
6665 cb
.emit_synchronized_wrapper
= emit_synchronized_wrapper_ilgen
;
6666 cb
.emit_unbox_wrapper
= emit_unbox_wrapper_ilgen
;
6667 cb
.emit_array_accessor_wrapper
= emit_array_accessor_wrapper_ilgen
;
6668 cb
.emit_generic_array_helper
= emit_generic_array_helper_ilgen
;
6669 cb
.emit_thunk_invoke_wrapper
= emit_thunk_invoke_wrapper_ilgen
;
6670 cb
.emit_create_string_hack
= emit_create_string_hack_ilgen
;
6671 cb
.emit_native_icall_wrapper
= emit_native_icall_wrapper_ilgen
;
6672 cb
.emit_icall_wrapper
= emit_icall_wrapper_ilgen
;
6673 cb
.emit_return
= emit_return_ilgen
;
6674 cb
.emit_vtfixup_ftnptr
= emit_vtfixup_ftnptr_ilgen
;
6675 cb
.mb_skip_visibility
= mb_skip_visibility_ilgen
;
6676 cb
.mb_set_dynamic
= mb_set_dynamic_ilgen
;
6677 cb
.mb_emit_exception
= mb_emit_exception_ilgen
;
6678 cb
.mb_emit_exception_for_error
= mb_emit_exception_for_error_ilgen
;
6679 cb
.mb_emit_byte
= mb_emit_byte_ilgen
;
6680 mono_install_marshal_callbacks (&cb
);