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