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