Fix SafeHandle marshalling in ref/in/out parameters (#17330)
[mono-project.git] / mono / metadata / marshal-ilgen.c
bloba3342a6f412164d278afbc9ba49b9aa52243c278
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 #define IS_IN(t) ((t->attrs & PARAM_ATTRIBUTE_IN) || !(t->attrs & PARAM_ATTRIBUTE_OUT))
63 #define IS_OUT(t) ((t->attrs & PARAM_ATTRIBUTE_OUT) || !(t->attrs & PARAM_ATTRIBUTE_IN))
65 static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute, "System.Runtime.CompilerServices", "FixedBufferAttribute");
66 static GENERATE_GET_CLASS_WITH_CACHE (date_time, "System", "DateTime");
67 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler");
68 static GENERATE_TRY_GET_CLASS_WITH_CACHE (marshal, "System.Runtime.InteropServices", "Marshal");
70 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
71 static MonoMethod *sh_dangerous_add_ref;
72 static MonoMethod *sh_dangerous_release;
74 static MonoMethod*
75 get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags)
77 MonoMethod *method;
78 ERROR_DECL (error);
79 method = mono_class_get_method_from_name_checked (klass, method_name, num_params, flags, error);
80 mono_error_assert_ok (error);
81 g_assertf (method, "Could not lookup method %s in %s", method_name, m_class_get_name (klass));
82 return method;
85 static void
86 init_safe_handle (void)
88 sh_dangerous_add_ref = get_method_nofail (
89 mono_class_try_get_safehandle_class (), "DangerousAddRef", 1, 0);
90 sh_dangerous_release = get_method_nofail (
91 mono_class_try_get_safehandle_class (), "DangerousRelease", 0, 0);
94 static MonoImage*
95 get_method_image (MonoMethod *method)
97 return m_class_get_image (method->klass);
100 static void
101 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
103 static void
104 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
107 * mono_mb_strdup:
108 * \param mb the MethodBuilder
109 * \param s a string
111 * Creates a copy of the string \p s that can be referenced from the IL of \c mb.
113 * \returns a pointer to the new string which is owned by the method builder
115 char*
116 mono_mb_strdup (MonoMethodBuilder *mb, const char *s)
118 char *res;
119 if (!mb->dynamic)
120 res = mono_image_strdup (get_method_image (mb->method), s);
121 else
122 res = g_strdup (s);
123 return res;
129 * mono_mb_emit_exception_marshal_directive:
131 * This function assumes ownership of MSG, which should be malloc-ed.
133 static void
134 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg)
136 char *s = mono_mb_strdup (mb, msg);
137 g_free (msg);
138 mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", s);
141 static int
142 offset_of_first_nonstatic_field (MonoClass *klass)
144 int i;
145 int fcount = mono_class_get_field_count (klass);
146 mono_class_setup_fields (klass);
147 MonoClassField *klass_fields = m_class_get_fields (klass);
148 for (i = 0; i < fcount; i++) {
149 if (!(klass_fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass_fields[i]))
150 return klass_fields[i].offset - MONO_ABI_SIZEOF (MonoObject);
153 return 0;
156 static gboolean
157 get_fixed_buffer_attr (MonoClassField *field, MonoType **out_etype, int *out_len)
159 ERROR_DECL (error);
160 MonoCustomAttrInfo *cinfo;
161 MonoCustomAttrEntry *attr;
162 int aindex;
164 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
165 if (!is_ok (error))
166 return FALSE;
167 attr = NULL;
168 if (cinfo) {
169 for (aindex = 0; aindex < cinfo->num_attrs; ++aindex) {
170 MonoClass *ctor_class = cinfo->attrs [aindex].ctor->klass;
171 if (mono_class_has_parent (ctor_class, mono_class_get_fixed_buffer_attribute_class ())) {
172 attr = &cinfo->attrs [aindex];
173 break;
177 if (attr) {
178 gpointer *typed_args, *named_args;
179 CattrNamedArg *arginfo;
180 int num_named_args;
182 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size,
183 &typed_args, &named_args, &num_named_args, &arginfo, error);
184 if (!is_ok (error))
185 return FALSE;
186 *out_etype = (MonoType*)typed_args [0];
187 *out_len = *(gint32*)typed_args [1];
188 g_free (typed_args [1]);
189 g_free (typed_args);
190 g_free (named_args);
191 g_free (arginfo);
193 if (cinfo && !cinfo->cached)
194 mono_custom_attrs_free (cinfo);
195 return attr != NULL;
198 static void
199 emit_fixed_buf_conv (MonoMethodBuilder *mb, MonoType *type, MonoType *etype, int len, gboolean to_object, int *out_usize)
201 MonoClass *klass = mono_class_from_mono_type_internal (type);
202 MonoClass *eklass = mono_class_from_mono_type_internal (etype);
203 int esize;
205 esize = mono_class_native_size (eklass, NULL);
207 MonoMarshalNative string_encoding = m_class_is_unicode (klass) ? MONO_NATIVE_LPWSTR : MONO_NATIVE_LPSTR;
208 int usize = mono_class_value_size (eklass, NULL);
209 int msize = mono_class_value_size (eklass, NULL);
211 //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), em_class_is_blittable (klass), string_encoding);
213 if (m_class_is_blittable (eklass)) {
214 /* copy the elements */
215 mono_mb_emit_ldloc (mb, 1);
216 mono_mb_emit_ldloc (mb, 0);
217 mono_mb_emit_icon (mb, len * esize);
218 mono_mb_emit_byte (mb, CEE_PREFIX1);
219 mono_mb_emit_byte (mb, CEE_CPBLK);
220 } else {
221 int index_var;
222 guint32 label2, label3;
224 /* Emit marshalling loop */
225 MonoType *int_type = mono_get_int_type ();
226 index_var = mono_mb_add_local (mb, int_type);
227 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
228 mono_mb_emit_stloc (mb, index_var);
230 /* Loop header */
231 label2 = mono_mb_get_label (mb);
232 mono_mb_emit_ldloc (mb, index_var);
233 mono_mb_emit_icon (mb, len);
234 label3 = mono_mb_emit_branch (mb, CEE_BGE);
236 /* src/dst is already set */
238 /* Do the conversion */
239 MonoTypeEnum t = etype->type;
240 switch (t) {
241 case MONO_TYPE_I4:
242 case MONO_TYPE_U4:
243 case MONO_TYPE_I1:
244 case MONO_TYPE_U1:
245 case MONO_TYPE_BOOLEAN:
246 case MONO_TYPE_I2:
247 case MONO_TYPE_U2:
248 case MONO_TYPE_CHAR:
249 case MONO_TYPE_I8:
250 case MONO_TYPE_U8:
251 case MONO_TYPE_PTR:
252 case MONO_TYPE_R4:
253 case MONO_TYPE_R8:
254 mono_mb_emit_ldloc (mb, 1);
255 mono_mb_emit_ldloc (mb, 0);
256 if (t == MONO_TYPE_CHAR && string_encoding != MONO_NATIVE_LPWSTR) {
257 if (to_object) {
258 mono_mb_emit_byte (mb, CEE_LDIND_U1);
259 mono_mb_emit_byte (mb, CEE_STIND_I2);
260 } else {
261 mono_mb_emit_byte (mb, CEE_LDIND_U2);
262 mono_mb_emit_byte (mb, CEE_STIND_I1);
264 usize = 1;
265 } else {
266 mono_mb_emit_byte (mb, mono_type_to_ldind (etype));
267 mono_mb_emit_byte (mb, mono_type_to_stind (etype));
269 break;
270 default:
271 g_assert_not_reached ();
272 break;
275 if (to_object) {
276 mono_mb_emit_add_to_local (mb, 0, usize);
277 mono_mb_emit_add_to_local (mb, 1, msize);
278 } else {
279 mono_mb_emit_add_to_local (mb, 0, msize);
280 mono_mb_emit_add_to_local (mb, 1, usize);
283 /* Loop footer */
284 mono_mb_emit_add_to_local (mb, index_var, 1);
286 mono_mb_emit_branch_label (mb, CEE_BR, label2);
288 mono_mb_patch_branch (mb, label3);
291 *out_usize = usize * len;
294 static void
295 emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
297 switch (conv) {
298 case MONO_MARSHAL_CONV_BOOL_I4:
299 mono_mb_emit_ldloc (mb, 1);
300 mono_mb_emit_ldloc (mb, 0);
301 mono_mb_emit_byte (mb, CEE_LDIND_I4);
302 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
303 mono_mb_emit_byte (mb, 3);
304 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
305 mono_mb_emit_byte (mb, CEE_BR_S);
306 mono_mb_emit_byte (mb, 1);
307 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
308 mono_mb_emit_byte (mb, CEE_STIND_I1);
309 break;
310 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
311 mono_mb_emit_ldloc (mb, 1);
312 mono_mb_emit_ldloc (mb, 0);
313 mono_mb_emit_byte (mb, CEE_LDIND_I2);
314 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
315 mono_mb_emit_byte (mb, 3);
316 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
317 mono_mb_emit_byte (mb, CEE_BR_S);
318 mono_mb_emit_byte (mb, 1);
319 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
320 mono_mb_emit_byte (mb, CEE_STIND_I1);
321 break;
322 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
323 MonoClass *eklass = NULL;
324 int esize;
326 if (type->type == MONO_TYPE_SZARRAY) {
327 eklass = type->data.klass;
328 } else {
329 g_assert_not_reached ();
332 esize = mono_class_native_size (eklass, NULL);
334 /* create a new array */
335 mono_mb_emit_ldloc (mb, 1);
336 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
337 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
338 mono_mb_emit_byte (mb, CEE_STIND_REF);
340 if (m_class_is_blittable (eklass)) {
341 /* copy the elements */
342 mono_mb_emit_ldloc (mb, 1);
343 mono_mb_emit_byte (mb, CEE_LDIND_I);
344 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
345 mono_mb_emit_byte (mb, CEE_ADD);
346 mono_mb_emit_ldloc (mb, 0);
347 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
348 mono_mb_emit_byte (mb, CEE_PREFIX1);
349 mono_mb_emit_byte (mb, CEE_CPBLK);
351 else {
352 int array_var, src_var, dst_var, index_var;
353 guint32 label2, label3;
355 MonoType *int_type = mono_get_int_type ();
356 array_var = mono_mb_add_local (mb, mono_get_object_type ());
357 src_var = mono_mb_add_local (mb, int_type);
358 dst_var = mono_mb_add_local (mb, int_type);
360 /* set array_var */
361 mono_mb_emit_ldloc (mb, 1);
362 mono_mb_emit_byte (mb, CEE_LDIND_REF);
363 mono_mb_emit_stloc (mb, array_var);
365 /* save the old src pointer */
366 mono_mb_emit_ldloc (mb, 0);
367 mono_mb_emit_stloc (mb, src_var);
368 /* save the old dst pointer */
369 mono_mb_emit_ldloc (mb, 1);
370 mono_mb_emit_stloc (mb, dst_var);
372 /* Emit marshalling loop */
373 index_var = mono_mb_add_local (mb, int_type);
374 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
375 mono_mb_emit_stloc (mb, index_var);
377 /* Loop header */
378 label2 = mono_mb_get_label (mb);
379 mono_mb_emit_ldloc (mb, index_var);
380 mono_mb_emit_ldloc (mb, array_var);
381 mono_mb_emit_byte (mb, CEE_LDLEN);
382 label3 = mono_mb_emit_branch (mb, CEE_BGE);
384 /* src is already set */
386 /* Set dst */
387 mono_mb_emit_ldloc (mb, array_var);
388 mono_mb_emit_ldloc (mb, index_var);
389 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
390 mono_mb_emit_stloc (mb, 1);
392 /* Do the conversion */
393 emit_struct_conv (mb, eklass, TRUE);
395 /* Loop footer */
396 mono_mb_emit_add_to_local (mb, index_var, 1);
398 mono_mb_emit_branch_label (mb, CEE_BR, label2);
400 mono_mb_patch_branch (mb, label3);
402 /* restore the old src pointer */
403 mono_mb_emit_ldloc (mb, src_var);
404 mono_mb_emit_stloc (mb, 0);
405 /* restore the old dst pointer */
406 mono_mb_emit_ldloc (mb, dst_var);
407 mono_mb_emit_stloc (mb, 1);
409 break;
411 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
412 MonoClass *eclass = mono_defaults.char_class;
414 /* create a new array */
415 mono_mb_emit_ldloc (mb, 1);
416 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
417 mono_mb_emit_op (mb, CEE_NEWARR, eclass);
418 mono_mb_emit_byte (mb, CEE_STIND_REF);
420 mono_mb_emit_ldloc (mb, 1);
421 mono_mb_emit_byte (mb, CEE_LDIND_REF);
422 mono_mb_emit_ldloc (mb, 0);
423 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
424 mono_mb_emit_icall (mb, mono_byvalarray_to_byte_array);
425 break;
427 case MONO_MARSHAL_CONV_STR_BYVALSTR:
428 if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) {
429 mono_mb_emit_ldloc (mb, 1);
430 mono_mb_emit_ldloc (mb, 0);
431 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
432 mono_mb_emit_icall (mb, mono_string_from_byvalstr);
433 } else {
434 mono_mb_emit_ldloc (mb, 1);
435 mono_mb_emit_ldloc (mb, 0);
436 mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
438 mono_mb_emit_byte (mb, CEE_STIND_REF);
439 break;
440 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
441 if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) {
442 mono_mb_emit_ldloc (mb, 1);
443 mono_mb_emit_ldloc (mb, 0);
444 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
445 mono_mb_emit_icall (mb, mono_string_from_byvalwstr);
446 } else {
447 mono_mb_emit_ldloc (mb, 1);
448 mono_mb_emit_ldloc (mb, 0);
449 mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
451 mono_mb_emit_byte (mb, CEE_STIND_REF);
452 break;
453 case MONO_MARSHAL_CONV_STR_LPTSTR:
454 mono_mb_emit_ldloc (mb, 1);
455 mono_mb_emit_ldloc (mb, 0);
456 mono_mb_emit_byte (mb, CEE_LDIND_I);
457 #ifdef TARGET_WIN32
458 mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
459 #else
460 mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
461 #endif
462 mono_mb_emit_byte (mb, CEE_STIND_REF);
463 break;
465 // In Mono historically LPSTR was treated as a UTF8STR
466 case MONO_MARSHAL_CONV_STR_LPSTR:
467 case MONO_MARSHAL_CONV_STR_UTF8STR:
468 mono_mb_emit_ldloc (mb, 1);
469 mono_mb_emit_ldloc (mb, 0);
470 mono_mb_emit_byte (mb, CEE_LDIND_I);
471 mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
472 mono_mb_emit_byte (mb, CEE_STIND_REF);
473 break;
474 case MONO_MARSHAL_CONV_STR_LPWSTR:
475 mono_mb_emit_ldloc (mb, 1);
476 mono_mb_emit_ldloc (mb, 0);
477 mono_mb_emit_byte (mb, CEE_LDIND_I);
478 mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
479 mono_mb_emit_byte (mb, CEE_STIND_REF);
480 break;
481 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
482 MonoClass *klass = mono_class_from_mono_type_internal (type);
483 int src_var, dst_var;
485 MonoType *int_type = mono_get_int_type ();
486 src_var = mono_mb_add_local (mb, int_type);
487 dst_var = mono_mb_add_local (mb, int_type);
489 /* *dst = new object */
490 mono_mb_emit_ldloc (mb, 1);
491 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
492 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
493 mono_mb_emit_byte (mb, CEE_STIND_REF);
495 /* save the old src pointer */
496 mono_mb_emit_ldloc (mb, 0);
497 mono_mb_emit_stloc (mb, src_var);
498 /* save the old dst pointer */
499 mono_mb_emit_ldloc (mb, 1);
500 mono_mb_emit_stloc (mb, dst_var);
502 /* dst = pointer to newly created object data */
503 mono_mb_emit_ldloc (mb, 1);
504 mono_mb_emit_byte (mb, CEE_LDIND_I);
505 mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject));
506 mono_mb_emit_byte (mb, CEE_ADD);
507 mono_mb_emit_stloc (mb, 1);
509 emit_struct_conv (mb, klass, TRUE);
511 /* restore the old src pointer */
512 mono_mb_emit_ldloc (mb, src_var);
513 mono_mb_emit_stloc (mb, 0);
514 /* restore the old dst pointer */
515 mono_mb_emit_ldloc (mb, dst_var);
516 mono_mb_emit_stloc (mb, 1);
517 break;
519 case MONO_MARSHAL_CONV_DEL_FTN: {
520 MonoClass *klass = mono_class_from_mono_type_internal (type);
522 mono_mb_emit_ldloc (mb, 1);
523 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
524 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
525 mono_mb_emit_ldloc (mb, 0);
526 mono_mb_emit_byte (mb, CEE_LDIND_I);
527 mono_mb_emit_icall (mb, mono_ftnptr_to_delegate);
528 mono_mb_emit_byte (mb, CEE_STIND_REF);
529 break;
531 case MONO_MARSHAL_CONV_ARRAY_LPARRAY: {
532 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)));
533 mono_mb_emit_exception_marshal_directive (mb, msg);
534 break;
537 #ifndef DISABLE_COM
538 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
539 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
540 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
541 mono_cominterop_emit_ptr_to_object_conv (mb, type, conv, mspec);
542 break;
543 #endif /* DISABLE_COM */
545 case MONO_MARSHAL_CONV_SAFEHANDLE: {
547 * Passing SafeHandles as ref does not allow the unmanaged code
548 * to change the SafeHandle value. If the value is changed,
549 * we should issue a diagnostic exception (NotSupportedException)
550 * that informs the user that changes to handles in unmanaged code
551 * is not supported.
553 * Since we currently have no access to the original
554 * SafeHandle that was used during the marshalling,
555 * for now we just ignore this, and ignore/discard any
556 * changes that might have happened to the handle.
558 break;
561 case MONO_MARSHAL_CONV_HANDLEREF: {
563 * Passing HandleRefs in a struct that is ref()ed does not
564 * copy the values back to the HandleRef
566 break;
569 case MONO_MARSHAL_CONV_STR_BSTR:
570 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
571 case MONO_MARSHAL_CONV_STR_TBSTR:
572 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
573 default: {
574 char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv);
576 mono_mb_emit_exception_marshal_directive (mb, msg);
577 break;
582 static MonoJitICallId
583 conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
585 // FIXME This or its caller might be a good place to inline some
586 // of the wrapper logic. In particular, to produce
587 // volatile stack-based handles. Being data-driven,
588 // from icall-def.h.
590 int dummy;
591 if (!ind_store_type)
592 ind_store_type = &dummy;
593 *ind_store_type = CEE_STIND_I;
594 switch (conv) {
595 case MONO_MARSHAL_CONV_STR_LPWSTR:
596 return MONO_JIT_ICALL_mono_marshal_string_to_utf16;
597 case MONO_MARSHAL_CONV_LPWSTR_STR:
598 *ind_store_type = CEE_STIND_REF;
599 return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16;
600 case MONO_MARSHAL_CONV_LPTSTR_STR:
601 *ind_store_type = CEE_STIND_REF;
602 return MONO_JIT_ICALL_ves_icall_string_new_wrapper;
603 case MONO_MARSHAL_CONV_UTF8STR_STR:
604 case MONO_MARSHAL_CONV_LPSTR_STR:
605 *ind_store_type = CEE_STIND_REF;
606 return MONO_JIT_ICALL_ves_icall_string_new_wrapper;
607 case MONO_MARSHAL_CONV_STR_LPTSTR:
608 #ifdef TARGET_WIN32
609 return MONO_JIT_ICALL_mono_marshal_string_to_utf16;
610 #else
611 return MONO_JIT_ICALL_mono_string_to_utf8str;
612 #endif
613 // In Mono historically LPSTR was treated as a UTF8STR
614 case MONO_MARSHAL_CONV_STR_UTF8STR:
615 case MONO_MARSHAL_CONV_STR_LPSTR:
616 return MONO_JIT_ICALL_mono_string_to_utf8str;
617 case MONO_MARSHAL_CONV_STR_BSTR:
618 return MONO_JIT_ICALL_mono_string_to_bstr;
619 case MONO_MARSHAL_CONV_BSTR_STR:
620 *ind_store_type = CEE_STIND_REF;
621 return MONO_JIT_ICALL_mono_string_from_bstr_icall;
622 case MONO_MARSHAL_CONV_STR_TBSTR:
623 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
624 return MONO_JIT_ICALL_mono_string_to_ansibstr;
625 case MONO_MARSHAL_CONV_SB_UTF8STR:
626 case MONO_MARSHAL_CONV_SB_LPSTR:
627 return MONO_JIT_ICALL_mono_string_builder_to_utf8;
628 case MONO_MARSHAL_CONV_SB_LPTSTR:
629 #ifdef TARGET_WIN32
630 return MONO_JIT_ICALL_mono_string_builder_to_utf16;
631 #else
632 return MONO_JIT_ICALL_mono_string_builder_to_utf8;
633 #endif
634 case MONO_MARSHAL_CONV_SB_LPWSTR:
635 return MONO_JIT_ICALL_mono_string_builder_to_utf16;
636 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
637 return MONO_JIT_ICALL_mono_array_to_savearray;
638 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
639 return MONO_JIT_ICALL_mono_array_to_lparray;
640 case MONO_MARSHAL_FREE_LPARRAY:
641 return MONO_JIT_ICALL_mono_free_lparray;
642 case MONO_MARSHAL_CONV_DEL_FTN:
643 return MONO_JIT_ICALL_mono_delegate_to_ftnptr;
644 case MONO_MARSHAL_CONV_FTN_DEL:
645 *ind_store_type = CEE_STIND_REF;
646 return MONO_JIT_ICALL_mono_ftnptr_to_delegate;
647 case MONO_MARSHAL_CONV_UTF8STR_SB:
648 case MONO_MARSHAL_CONV_LPSTR_SB:
649 *ind_store_type = CEE_STIND_REF;
650 return MONO_JIT_ICALL_mono_string_utf8_to_builder;
651 case MONO_MARSHAL_CONV_LPTSTR_SB:
652 *ind_store_type = CEE_STIND_REF;
653 #ifdef TARGET_WIN32
654 return MONO_JIT_ICALL_mono_string_utf16_to_builder;
655 #else
656 return MONO_JIT_ICALL_mono_string_utf8_to_builder;
657 #endif
658 case MONO_MARSHAL_CONV_LPWSTR_SB:
659 *ind_store_type = CEE_STIND_REF;
660 return MONO_JIT_ICALL_mono_string_utf16_to_builder;
661 case MONO_MARSHAL_FREE_ARRAY:
662 return MONO_JIT_ICALL_mono_marshal_free_array;
663 case MONO_MARSHAL_CONV_STR_BYVALSTR:
664 return MONO_JIT_ICALL_mono_string_to_byvalstr;
665 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
666 return MONO_JIT_ICALL_mono_string_to_byvalwstr;
667 default:
668 g_assert_not_reached ();
671 return MONO_JIT_ICALL_ZeroIsReserved;
674 static void
675 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
677 int pos;
678 int stind_op;
680 switch (conv) {
681 case MONO_MARSHAL_CONV_BOOL_I4:
682 mono_mb_emit_ldloc (mb, 1);
683 mono_mb_emit_ldloc (mb, 0);
684 mono_mb_emit_byte (mb, CEE_LDIND_U1);
685 mono_mb_emit_byte (mb, CEE_STIND_I4);
686 break;
687 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
688 mono_mb_emit_ldloc (mb, 1);
689 mono_mb_emit_ldloc (mb, 0);
690 mono_mb_emit_byte (mb, CEE_LDIND_U1);
691 mono_mb_emit_byte (mb, CEE_NEG);
692 mono_mb_emit_byte (mb, CEE_STIND_I2);
693 break;
694 // In Mono historically LPSTR was treated as a UTF8STR
695 case MONO_MARSHAL_CONV_STR_UTF8STR:
696 case MONO_MARSHAL_CONV_STR_LPWSTR:
697 case MONO_MARSHAL_CONV_STR_LPSTR:
698 case MONO_MARSHAL_CONV_STR_LPTSTR:
699 case MONO_MARSHAL_CONV_STR_BSTR:
700 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
701 case MONO_MARSHAL_CONV_STR_TBSTR: {
702 int pos;
704 /* free space if free == true */
705 mono_mb_emit_ldloc (mb, 2);
706 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
707 mono_mb_emit_ldloc (mb, 1);
708 mono_mb_emit_byte (mb, CEE_LDIND_I);
709 mono_mb_emit_icall (mb, g_free); // aka monoeg_g_free
710 mono_mb_patch_short_branch (mb, pos);
712 mono_mb_emit_ldloc (mb, 1);
713 mono_mb_emit_ldloc (mb, 0);
714 mono_mb_emit_byte (mb, CEE_LDIND_REF);
715 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
716 mono_mb_emit_byte (mb, stind_op);
717 break;
719 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
720 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
721 case MONO_MARSHAL_CONV_DEL_FTN:
722 mono_mb_emit_ldloc (mb, 1);
723 mono_mb_emit_ldloc (mb, 0);
724 mono_mb_emit_byte (mb, CEE_LDIND_REF);
725 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
726 mono_mb_emit_byte (mb, stind_op);
727 break;
728 case MONO_MARSHAL_CONV_STR_BYVALSTR:
729 case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
730 g_assert (mspec);
732 mono_mb_emit_ldloc (mb, 1); /* dst */
733 mono_mb_emit_ldloc (mb, 0);
734 mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
735 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
736 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
737 break;
739 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
740 MonoClass *eklass = NULL;
741 int esize;
743 if (type->type == MONO_TYPE_SZARRAY) {
744 eklass = type->data.klass;
745 } else if (type->type == MONO_TYPE_ARRAY) {
746 eklass = type->data.array->eklass;
747 g_assert(m_class_is_blittable (eklass));
748 } else {
749 g_assert_not_reached ();
752 if (m_class_is_valuetype (eklass))
753 esize = mono_class_native_size (eklass, NULL);
754 else
755 esize = TARGET_SIZEOF_VOID_P;
757 mono_mb_emit_ldloc (mb, 0);
758 mono_mb_emit_byte (mb, CEE_LDIND_REF);
759 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
761 if (m_class_is_blittable (eklass)) {
762 mono_mb_emit_ldloc (mb, 1);
763 mono_mb_emit_ldloc (mb, 0);
764 mono_mb_emit_byte (mb, CEE_LDIND_REF);
765 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
766 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
767 mono_mb_emit_byte (mb, CEE_PREFIX1);
768 mono_mb_emit_byte (mb, CEE_CPBLK);
769 } else {
770 int array_var, src_var, dst_var, index_var;
771 guint32 label2, label3;
773 MonoType *int_type = mono_get_int_type ();
774 MonoType *object_type = mono_get_object_type ();
775 array_var = mono_mb_add_local (mb, object_type);
776 src_var = mono_mb_add_local (mb, int_type);
777 dst_var = mono_mb_add_local (mb, int_type);
779 /* set array_var */
780 mono_mb_emit_ldloc (mb, 0);
781 mono_mb_emit_byte (mb, CEE_LDIND_REF);
782 mono_mb_emit_stloc (mb, array_var);
784 /* save the old src pointer */
785 mono_mb_emit_ldloc (mb, 0);
786 mono_mb_emit_stloc (mb, src_var);
787 /* save the old dst pointer */
788 mono_mb_emit_ldloc (mb, 1);
789 mono_mb_emit_stloc (mb, dst_var);
791 /* Emit marshalling loop */
792 index_var = mono_mb_add_local (mb, int_type);
793 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
794 mono_mb_emit_stloc (mb, index_var);
796 /* Loop header */
797 label2 = mono_mb_get_label (mb);
798 mono_mb_emit_ldloc (mb, index_var);
799 mono_mb_emit_ldloc (mb, array_var);
800 mono_mb_emit_byte (mb, CEE_LDLEN);
801 label3 = mono_mb_emit_branch (mb, CEE_BGE);
803 /* Set src */
804 mono_mb_emit_ldloc (mb, array_var);
805 mono_mb_emit_ldloc (mb, index_var);
806 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
807 mono_mb_emit_stloc (mb, 0);
809 /* dst is already set */
811 /* Do the conversion */
812 emit_struct_conv (mb, eklass, FALSE);
814 /* Loop footer */
815 mono_mb_emit_add_to_local (mb, index_var, 1);
817 mono_mb_emit_branch_label (mb, CEE_BR, label2);
819 mono_mb_patch_branch (mb, label3);
821 /* restore the old src pointer */
822 mono_mb_emit_ldloc (mb, src_var);
823 mono_mb_emit_stloc (mb, 0);
824 /* restore the old dst pointer */
825 mono_mb_emit_ldloc (mb, dst_var);
826 mono_mb_emit_stloc (mb, 1);
829 mono_mb_patch_branch (mb, pos);
830 break;
832 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
833 mono_mb_emit_ldloc (mb, 0);
834 mono_mb_emit_byte (mb, CEE_LDIND_REF);
835 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
837 mono_mb_emit_ldloc (mb, 1);
838 mono_mb_emit_ldloc (mb, 0);
839 mono_mb_emit_byte (mb, CEE_LDIND_REF);
840 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
841 mono_mb_emit_icall (mb, mono_array_to_byte_byvalarray);
842 mono_mb_patch_short_branch (mb, pos);
843 break;
845 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
846 int src_var, dst_var;
848 MonoType *int_type = mono_get_int_type ();
849 src_var = mono_mb_add_local (mb, int_type);
850 dst_var = mono_mb_add_local (mb, int_type);
852 mono_mb_emit_ldloc (mb, 0);
853 mono_mb_emit_byte (mb, CEE_LDIND_I);
854 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
856 /* save the old src pointer */
857 mono_mb_emit_ldloc (mb, 0);
858 mono_mb_emit_stloc (mb, src_var);
859 /* save the old dst pointer */
860 mono_mb_emit_ldloc (mb, 1);
861 mono_mb_emit_stloc (mb, dst_var);
863 /* src = pointer to object data */
864 mono_mb_emit_ldloc (mb, 0);
865 mono_mb_emit_byte (mb, CEE_LDIND_I);
866 mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject));
867 mono_mb_emit_byte (mb, CEE_ADD);
868 mono_mb_emit_stloc (mb, 0);
870 emit_struct_conv (mb, mono_class_from_mono_type_internal (type), FALSE);
872 /* restore the old src pointer */
873 mono_mb_emit_ldloc (mb, src_var);
874 mono_mb_emit_stloc (mb, 0);
875 /* restore the old dst pointer */
876 mono_mb_emit_ldloc (mb, dst_var);
877 mono_mb_emit_stloc (mb, 1);
879 mono_mb_patch_branch (mb, pos);
880 break;
883 #ifndef DISABLE_COM
884 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
885 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
886 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
887 mono_cominterop_emit_object_to_ptr_conv (mb, type, conv, mspec);
888 break;
889 #endif /* DISABLE_COM */
891 case MONO_MARSHAL_CONV_SAFEHANDLE: {
892 int pos;
894 mono_mb_emit_ldloc (mb, 0);
895 mono_mb_emit_byte (mb, CEE_LDIND_I);
896 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
897 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
898 mono_mb_patch_branch (mb, pos);
900 /* Pull the handle field from SafeHandle */
901 mono_mb_emit_ldloc (mb, 1);
902 mono_mb_emit_ldloc (mb, 0);
903 mono_mb_emit_byte (mb, CEE_LDIND_I);
904 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
905 mono_mb_emit_byte (mb, CEE_LDIND_I);
906 mono_mb_emit_byte (mb, CEE_STIND_I);
907 break;
910 case MONO_MARSHAL_CONV_HANDLEREF: {
911 mono_mb_emit_ldloc (mb, 1);
912 mono_mb_emit_ldloc (mb, 0);
913 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle));
914 mono_mb_emit_byte (mb, CEE_ADD);
915 mono_mb_emit_byte (mb, CEE_LDIND_I);
916 mono_mb_emit_byte (mb, CEE_STIND_I);
917 break;
920 default: {
921 g_error ("marshalling conversion %d not implemented", conv);
927 static void
928 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
929 int offset_of_first_child_field, MonoMarshalNative string_encoding)
931 MonoMarshalType *info;
932 int i;
934 if (m_class_get_parent (klass))
935 emit_struct_conv_full (mb, m_class_get_parent (klass), to_object, offset_of_first_nonstatic_field (klass), string_encoding);
937 info = mono_marshal_load_type_info (klass);
939 if (info->native_size == 0)
940 return;
942 if (m_class_is_blittable (klass)) {
943 int usize = mono_class_value_size (klass, NULL);
944 g_assert (usize == info->native_size);
945 mono_mb_emit_ldloc (mb, 1);
946 mono_mb_emit_ldloc (mb, 0);
947 mono_mb_emit_icon (mb, usize);
948 mono_mb_emit_byte (mb, CEE_PREFIX1);
949 mono_mb_emit_byte (mb, CEE_CPBLK);
951 if (to_object) {
952 mono_mb_emit_add_to_local (mb, 0, usize);
953 mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field);
954 } else {
955 mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field);
956 mono_mb_emit_add_to_local (mb, 1, usize);
958 return;
961 if (klass != mono_class_try_get_safehandle_class ()) {
962 if (mono_class_is_auto_layout (klass)) {
963 char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
964 mono_type_full_name (m_class_get_byval_arg (klass)));
965 mono_mb_emit_exception_marshal_directive (mb, msg);
966 return;
970 for (i = 0; i < info->num_fields; i++) {
971 MonoMarshalNative ntype;
972 MonoMarshalConv conv;
973 MonoType *ftype = info->fields [i].field->type;
974 int msize = 0;
975 int usize = 0;
976 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
978 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
979 continue;
981 ntype = (MonoMarshalNative)mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, m_class_is_unicode (klass), &conv);
983 if (last_field) {
984 msize = m_class_get_instance_size (klass) - info->fields [i].field->offset;
985 usize = info->native_size - info->fields [i].offset;
986 } else {
987 msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
988 usize = info->fields [i + 1].offset - info->fields [i].offset;
991 if (klass != mono_class_try_get_safehandle_class ()){
993 * FIXME: Should really check for usize==0 and msize>0, but we apply
994 * the layout to the managed structure as well.
997 if (mono_class_is_explicit_layout (klass) && (usize == 0)) {
998 if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
999 ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
1000 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
1001 "reference field at the same offset as another field.",
1002 mono_type_full_name (m_class_get_byval_arg (klass)));
1006 switch (conv) {
1007 case MONO_MARSHAL_CONV_NONE: {
1008 int t;
1010 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
1011 g_assert (!ftype->byref);
1012 if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
1013 mono_mb_emit_ldloc (mb, 1);
1014 mono_mb_emit_ldloc (mb, 0);
1015 mono_mb_emit_byte (mb, CEE_LDIND_I);
1016 mono_mb_emit_byte (mb, CEE_STIND_I);
1017 break;
1020 handle_enum:
1021 t = ftype->type;
1022 switch (t) {
1023 case MONO_TYPE_I4:
1024 case MONO_TYPE_U4:
1025 case MONO_TYPE_I1:
1026 case MONO_TYPE_U1:
1027 case MONO_TYPE_BOOLEAN:
1028 case MONO_TYPE_I2:
1029 case MONO_TYPE_U2:
1030 case MONO_TYPE_CHAR:
1031 case MONO_TYPE_I8:
1032 case MONO_TYPE_U8:
1033 case MONO_TYPE_PTR:
1034 case MONO_TYPE_R4:
1035 case MONO_TYPE_R8:
1036 mono_mb_emit_ldloc (mb, 1);
1037 mono_mb_emit_ldloc (mb, 0);
1038 if (t == MONO_TYPE_CHAR && ntype == MONO_NATIVE_U1 && string_encoding != MONO_NATIVE_LPWSTR) {
1039 if (to_object) {
1040 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1041 mono_mb_emit_byte (mb, CEE_STIND_I2);
1042 } else {
1043 mono_mb_emit_byte (mb, CEE_LDIND_U2);
1044 mono_mb_emit_byte (mb, CEE_STIND_I1);
1046 } else {
1047 mono_mb_emit_byte (mb, mono_type_to_ldind (ftype));
1048 mono_mb_emit_byte (mb, mono_type_to_stind (ftype));
1050 break;
1051 case MONO_TYPE_GENERICINST:
1052 if (!mono_type_generic_inst_is_valuetype (ftype)) {
1053 char *msg = g_strdup_printf ("Generic type %s cannot be marshaled as field in a struct.",
1054 mono_type_full_name (ftype));
1055 mono_mb_emit_exception_marshal_directive (mb, msg);
1056 break;
1058 /* fall through */
1059 case MONO_TYPE_VALUETYPE: {
1060 int src_var, dst_var;
1061 MonoType *etype;
1062 int len;
1064 if (t == MONO_TYPE_VALUETYPE && m_class_is_enumtype (ftype->data.klass)) {
1065 ftype = mono_class_enum_basetype_internal (ftype->data.klass);
1066 goto handle_enum;
1069 MonoType *int_type = mono_get_int_type ();
1070 src_var = mono_mb_add_local (mb, int_type);
1071 dst_var = mono_mb_add_local (mb, int_type);
1073 /* save the old src pointer */
1074 mono_mb_emit_ldloc (mb, 0);
1075 mono_mb_emit_stloc (mb, src_var);
1076 /* save the old dst pointer */
1077 mono_mb_emit_ldloc (mb, 1);
1078 mono_mb_emit_stloc (mb, dst_var);
1080 if (get_fixed_buffer_attr (info->fields [i].field, &etype, &len)) {
1081 emit_fixed_buf_conv (mb, ftype, etype, len, to_object, &usize);
1082 } else {
1083 emit_struct_conv (mb, mono_class_from_mono_type_internal (ftype), to_object);
1086 /* restore the old src pointer */
1087 mono_mb_emit_ldloc (mb, src_var);
1088 mono_mb_emit_stloc (mb, 0);
1089 /* restore the old dst pointer */
1090 mono_mb_emit_ldloc (mb, dst_var);
1091 mono_mb_emit_stloc (mb, 1);
1092 break;
1094 case MONO_TYPE_OBJECT: {
1095 #ifndef DISABLE_COM
1096 if (to_object) {
1097 static MonoMethod *variant_clear = NULL;
1098 static MonoMethod *get_object_for_native_variant = NULL;
1100 if (!variant_clear)
1101 variant_clear = get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
1102 if (!get_object_for_native_variant)
1103 get_object_for_native_variant = get_method_nofail (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0);
1104 mono_mb_emit_ldloc (mb, 1);
1105 mono_mb_emit_ldloc (mb, 0);
1106 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
1107 mono_mb_emit_byte (mb, CEE_STIND_REF);
1109 mono_mb_emit_ldloc (mb, 0);
1110 mono_mb_emit_managed_call (mb, variant_clear, NULL);
1112 else {
1113 static MonoMethod *get_native_variant_for_object = NULL;
1115 if (!get_native_variant_for_object)
1116 get_native_variant_for_object = get_method_nofail (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0);
1118 mono_mb_emit_ldloc (mb, 0);
1119 mono_mb_emit_byte(mb, CEE_LDIND_REF);
1120 mono_mb_emit_ldloc (mb, 1);
1121 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
1123 #else
1124 char *msg = g_strdup_printf ("COM support was disabled at compilation time.");
1125 mono_mb_emit_exception_marshal_directive (mb, msg);
1126 #endif
1127 break;
1130 default:
1131 g_warning ("marshaling type %02x not implemented", ftype->type);
1132 g_assert_not_reached ();
1134 break;
1136 default: {
1137 int src_var, dst_var;
1139 MonoType *int_type = mono_get_int_type ();
1140 src_var = mono_mb_add_local (mb, int_type);
1141 dst_var = mono_mb_add_local (mb, int_type);
1143 /* save the old src pointer */
1144 mono_mb_emit_ldloc (mb, 0);
1145 mono_mb_emit_stloc (mb, src_var);
1146 /* save the old dst pointer */
1147 mono_mb_emit_ldloc (mb, 1);
1148 mono_mb_emit_stloc (mb, dst_var);
1150 if (to_object)
1151 emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec);
1152 else
1153 emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec);
1155 /* restore the old src pointer */
1156 mono_mb_emit_ldloc (mb, src_var);
1157 mono_mb_emit_stloc (mb, 0);
1158 /* restore the old dst pointer */
1159 mono_mb_emit_ldloc (mb, dst_var);
1160 mono_mb_emit_stloc (mb, 1);
1164 if (to_object) {
1165 mono_mb_emit_add_to_local (mb, 0, usize);
1166 mono_mb_emit_add_to_local (mb, 1, msize);
1167 } else {
1168 mono_mb_emit_add_to_local (mb, 0, msize);
1169 mono_mb_emit_add_to_local (mb, 1, usize);
1174 static void
1175 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
1177 emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1);
1180 static void
1181 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
1183 /* Call DestroyStructure */
1184 /* FIXME: Only do this if needed */
1185 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1186 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
1187 mono_mb_emit_ldloc (mb, struct_var);
1188 mono_mb_emit_icall (mb, mono_struct_delete_old);
1191 static void
1192 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, MonoJitICallId checkpoint_icall_id)
1194 int pos_noabort, pos_noex;
1196 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1197 mono_mb_emit_byte (mb, CEE_MONO_LDPTR_INT_REQ_FLAG);
1198 mono_mb_emit_byte (mb, CEE_LDIND_U4);
1199 pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
1201 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1202 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
1204 mono_mb_emit_icall_id (mb, checkpoint_icall_id);
1205 /* Throw the exception returned by the checkpoint function, if any */
1206 mono_mb_emit_byte (mb, CEE_DUP);
1207 pos_noex = mono_mb_emit_branch (mb, CEE_BRFALSE);
1209 mono_mb_emit_byte (mb, CEE_DUP);
1210 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoException, caught_in_unmanaged));
1211 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1212 mono_mb_emit_byte (mb, CEE_STIND_I4);
1214 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1215 mono_mb_emit_byte (mb, CEE_MONO_RETHROW);
1217 mono_mb_patch_branch (mb, pos_noex);
1218 mono_mb_emit_byte (mb, CEE_POP);
1220 mono_mb_patch_branch (mb, pos_noabort);
1223 static void
1224 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
1226 // FIXME Put a boolean in MonoMethodBuilder instead.
1227 if (strstr (mb->name, "mono_thread_interruption_checkpoint"))
1228 return;
1230 emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_interruption_checkpoint);
1233 static void
1234 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
1236 emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise);
1239 void
1240 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
1242 emit_thread_interrupt_checkpoint (mb);
1245 void
1246 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
1248 emit_thread_force_interrupt_checkpoint (mb);
1252 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
1254 int i, params_var, tmp_var;
1256 MonoType *int_type = mono_get_int_type ();
1257 /* allocate local (pointer) *params[] */
1258 params_var = mono_mb_add_local (mb, int_type);
1259 /* allocate local (pointer) tmp */
1260 tmp_var = mono_mb_add_local (mb, int_type);
1262 /* alloate space on stack to store an array of pointers to the arguments */
1263 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * (sig->param_count + 1));
1264 mono_mb_emit_byte (mb, CEE_PREFIX1);
1265 mono_mb_emit_byte (mb, CEE_LOCALLOC);
1266 mono_mb_emit_stloc (mb, params_var);
1268 /* tmp = params */
1269 mono_mb_emit_ldloc (mb, params_var);
1270 mono_mb_emit_stloc (mb, tmp_var);
1272 if (save_this && sig->hasthis) {
1273 mono_mb_emit_ldloc (mb, tmp_var);
1274 mono_mb_emit_ldarg_addr (mb, 0);
1275 mono_mb_emit_byte (mb, CEE_STIND_I);
1276 /* tmp = tmp + sizeof (gpointer) */
1277 if (sig->param_count)
1278 mono_mb_emit_add_to_local (mb, tmp_var, TARGET_SIZEOF_VOID_P);
1282 for (i = 0; i < sig->param_count; i++) {
1283 mono_mb_emit_ldloc (mb, tmp_var);
1284 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
1285 mono_mb_emit_byte (mb, CEE_STIND_I);
1286 /* tmp = tmp + sizeof (gpointer) */
1287 if (i < (sig->param_count - 1))
1288 mono_mb_emit_add_to_local (mb, tmp_var, TARGET_SIZEOF_VOID_P);
1291 return params_var;
1295 void
1296 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
1298 MonoType *t = mono_type_get_underlying_type (return_type);
1299 MonoType *int_type = mono_get_int_type ();
1301 if (return_type->byref)
1302 return_type = int_type;
1304 switch (t->type) {
1305 case MONO_TYPE_VOID:
1306 g_assert_not_reached ();
1307 break;
1308 case MONO_TYPE_PTR:
1309 case MONO_TYPE_STRING:
1310 case MONO_TYPE_CLASS:
1311 case MONO_TYPE_OBJECT:
1312 case MONO_TYPE_ARRAY:
1313 case MONO_TYPE_SZARRAY:
1314 /* nothing to do */
1315 break;
1316 case MONO_TYPE_U1:
1317 case MONO_TYPE_BOOLEAN:
1318 case MONO_TYPE_I1:
1319 case MONO_TYPE_U2:
1320 case MONO_TYPE_CHAR:
1321 case MONO_TYPE_I2:
1322 case MONO_TYPE_I:
1323 case MONO_TYPE_U:
1324 case MONO_TYPE_I4:
1325 case MONO_TYPE_U4:
1326 case MONO_TYPE_U8:
1327 case MONO_TYPE_I8:
1328 case MONO_TYPE_R4:
1329 case MONO_TYPE_R8:
1330 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type_internal (return_type));
1331 mono_mb_emit_byte (mb, mono_type_to_ldind (return_type));
1332 break;
1333 case MONO_TYPE_GENERICINST:
1334 if (!mono_type_generic_inst_is_valuetype (t))
1335 break;
1336 /* fall through */
1337 case MONO_TYPE_VALUETYPE: {
1338 MonoClass *klass = mono_class_from_mono_type_internal (return_type);
1339 mono_mb_emit_op (mb, CEE_UNBOX, klass);
1340 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
1341 break;
1343 case MONO_TYPE_VAR:
1344 case MONO_TYPE_MVAR: {
1345 MonoClass *klass = mono_class_from_mono_type_internal (return_type);
1346 mono_mb_emit_op (mb, CEE_UNBOX_ANY, klass);
1347 break;
1349 default:
1350 g_warning ("type 0x%x not handled", return_type->type);
1351 g_assert_not_reached ();
1354 mono_mb_emit_byte (mb, CEE_RET);
1358 * emit_invoke_call:
1360 * Emit the call to the wrapper method from a runtime invoke wrapper.
1362 static void
1363 emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method,
1364 MonoMethodSignature *sig, MonoMethodSignature *callsig,
1365 int loc_res,
1366 gboolean virtual_, gboolean need_direct_wrapper)
1368 static MonoString *string_dummy = NULL;
1369 int i;
1370 int *tmp_nullable_locals;
1371 gboolean void_ret = FALSE;
1372 gboolean string_ctor = method && method->string_ctor;
1374 /* to make it work with our special string constructors */
1375 if (!string_dummy) {
1376 ERROR_DECL (error);
1378 // FIXME Allow for static construction of MonoString.
1380 SETUP_ICALL_FUNCTION;
1381 SETUP_ICALL_FRAME;
1383 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy, MONO_ROOT_SOURCE_MARSHAL, NULL, "Marshal Dummy String");
1385 MonoStringHandle string_dummy_handle = mono_string_new_utf8_len (mono_get_root_domain (), "dummy", 5, error);
1386 string_dummy = MONO_HANDLE_RAW (string_dummy_handle);
1387 mono_error_assert_ok (error);
1389 CLEAR_ICALL_FRAME;
1392 if (virtual_) {
1393 g_assert (sig->hasthis);
1394 g_assert (method->flags & METHOD_ATTRIBUTE_VIRTUAL);
1397 if (sig->hasthis) {
1398 if (string_ctor) {
1399 if (mono_gc_is_moving ()) {
1400 mono_mb_emit_ptr (mb, &string_dummy);
1401 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1402 } else {
1403 mono_mb_emit_ptr (mb, string_dummy);
1405 } else {
1406 mono_mb_emit_ldarg (mb, 0);
1410 tmp_nullable_locals = g_new0 (int, sig->param_count);
1412 for (i = 0; i < sig->param_count; i++) {
1413 MonoType *t = sig->params [i];
1414 int type;
1416 mono_mb_emit_ldarg (mb, 1);
1417 if (i) {
1418 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * i);
1419 mono_mb_emit_byte (mb, CEE_ADD);
1422 if (t->byref) {
1423 mono_mb_emit_byte (mb, CEE_LDIND_I);
1424 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
1425 * So to make this work we unbox it to a local variablee and push a reference to that.
1427 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
1428 tmp_nullable_locals [i] = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_from_mono_type_internal (t)));
1430 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type_internal (t));
1431 mono_mb_emit_stloc (mb, tmp_nullable_locals [i]);
1432 mono_mb_emit_ldloc_addr (mb, tmp_nullable_locals [i]);
1434 continue;
1437 type = sig->params [i]->type;
1438 handle_enum:
1439 switch (type) {
1440 case MONO_TYPE_I1:
1441 case MONO_TYPE_BOOLEAN:
1442 case MONO_TYPE_U1:
1443 case MONO_TYPE_I2:
1444 case MONO_TYPE_U2:
1445 case MONO_TYPE_CHAR:
1446 case MONO_TYPE_I:
1447 case MONO_TYPE_U:
1448 case MONO_TYPE_I4:
1449 case MONO_TYPE_U4:
1450 case MONO_TYPE_R4:
1451 case MONO_TYPE_R8:
1452 case MONO_TYPE_I8:
1453 case MONO_TYPE_U8:
1454 mono_mb_emit_byte (mb, CEE_LDIND_I);
1455 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
1456 break;
1457 case MONO_TYPE_STRING:
1458 case MONO_TYPE_CLASS:
1459 case MONO_TYPE_ARRAY:
1460 case MONO_TYPE_PTR:
1461 case MONO_TYPE_SZARRAY:
1462 case MONO_TYPE_OBJECT:
1463 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
1464 break;
1465 case MONO_TYPE_GENERICINST:
1466 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
1467 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
1468 break;
1471 t = m_class_get_byval_arg (t->data.generic_class->container_class);
1472 type = t->type;
1473 goto handle_enum;
1474 case MONO_TYPE_VALUETYPE:
1475 if (type == MONO_TYPE_VALUETYPE && m_class_is_enumtype (t->data.klass)) {
1476 type = mono_class_enum_basetype_internal (t->data.klass)->type;
1477 goto handle_enum;
1479 mono_mb_emit_byte (mb, CEE_LDIND_I);
1480 if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig->params [i]))) {
1481 /* Need to convert a boxed vtype to an mp to a Nullable struct */
1482 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type_internal (sig->params [i]));
1483 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i]));
1484 } else {
1485 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i]));
1487 break;
1488 default:
1489 g_assert_not_reached ();
1493 if (virtual_) {
1494 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1495 } else if (need_direct_wrapper) {
1496 mono_mb_emit_op (mb, CEE_CALL, method);
1497 } else {
1498 mono_mb_emit_ldarg (mb, 3);
1499 mono_mb_emit_calli (mb, callsig);
1502 if (sig->ret->byref) {
1503 /* perform indirect load and return by value */
1504 #ifdef ENABLE_NETCORE
1505 int pos;
1506 mono_mb_emit_byte (mb, CEE_DUP);
1507 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
1508 mono_mb_emit_exception_full (mb, "Mono", "NullByRefReturnException", NULL);
1509 mono_mb_patch_branch (mb, pos);
1510 #endif
1512 int ldind_op;
1513 MonoType* ret_byval = m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret));
1514 g_assert (!ret_byval->byref);
1515 // TODO: Handle null references
1516 ldind_op = mono_type_to_ldind (ret_byval);
1517 /* taken from similar code in mini-generic-sharing.c
1518 * we need to use mono_mb_emit_op to add method data when loading
1519 * a structure since method-to-ir needs this data for wrapper methods */
1520 if (ldind_op == CEE_LDOBJ)
1521 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (ret_byval));
1522 else
1523 mono_mb_emit_byte (mb, ldind_op);
1526 switch (sig->ret->type) {
1527 case MONO_TYPE_VOID:
1528 if (!string_ctor)
1529 void_ret = TRUE;
1530 break;
1531 case MONO_TYPE_BOOLEAN:
1532 case MONO_TYPE_CHAR:
1533 case MONO_TYPE_I1:
1534 case MONO_TYPE_U1:
1535 case MONO_TYPE_I2:
1536 case MONO_TYPE_U2:
1537 case MONO_TYPE_I4:
1538 case MONO_TYPE_U4:
1539 case MONO_TYPE_I:
1540 case MONO_TYPE_U:
1541 case MONO_TYPE_R4:
1542 case MONO_TYPE_R8:
1543 case MONO_TYPE_I8:
1544 case MONO_TYPE_U8:
1545 case MONO_TYPE_VALUETYPE:
1546 case MONO_TYPE_TYPEDBYREF:
1547 case MONO_TYPE_GENERICINST:
1548 /* box value types */
1549 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (sig->ret));
1550 break;
1551 case MONO_TYPE_STRING:
1552 case MONO_TYPE_CLASS:
1553 case MONO_TYPE_ARRAY:
1554 case MONO_TYPE_SZARRAY:
1555 case MONO_TYPE_OBJECT:
1556 /* nothing to do */
1557 break;
1558 case MONO_TYPE_PTR:
1559 /* The result is an IntPtr */
1560 mono_mb_emit_op (mb, CEE_BOX, mono_defaults.int_class);
1561 break;
1562 default:
1563 g_assert_not_reached ();
1566 if (!void_ret)
1567 mono_mb_emit_stloc (mb, loc_res);
1569 /* Convert back nullable-byref arguments */
1570 for (i = 0; i < sig->param_count; i++) {
1571 MonoType *t = sig->params [i];
1574 * Box the result and put it back into the array, the caller will have
1575 * to obtain it from there.
1577 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
1578 mono_mb_emit_ldarg (mb, 1);
1579 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * i);
1580 mono_mb_emit_byte (mb, CEE_ADD);
1582 mono_mb_emit_ldloc (mb, tmp_nullable_locals [i]);
1583 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t));
1585 mono_mb_emit_byte (mb, CEE_STIND_REF);
1589 g_free (tmp_nullable_locals);
1592 static void
1593 emit_runtime_invoke_body_ilgen (MonoMethodBuilder *mb, const char **param_names, MonoImage *image, MonoMethod *method,
1594 MonoMethodSignature *sig, MonoMethodSignature *callsig,
1595 gboolean virtual_, gboolean need_direct_wrapper)
1597 gint32 labels [16];
1598 MonoExceptionClause *clause;
1599 int loc_res, loc_exc;
1601 mono_mb_set_param_names (mb, param_names);
1603 /* The wrapper looks like this:
1605 * <interrupt check>
1606 * if (exc) {
1607 * try {
1608 * return <call>
1609 * } catch (Exception e) {
1610 * *exc = e;
1612 * } else {
1613 * return <call>
1617 MonoType *object_type = mono_get_object_type ();
1618 /* allocate local 0 (object) tmp */
1619 loc_res = mono_mb_add_local (mb, object_type);
1620 /* allocate local 1 (object) exc */
1621 loc_exc = mono_mb_add_local (mb, object_type);
1623 /* *exc is assumed to be initialized to NULL by the caller */
1625 mono_mb_emit_byte (mb, CEE_LDARG_2);
1626 labels [0] = mono_mb_emit_branch (mb, CEE_BRFALSE);
1629 * if (exc) case
1631 labels [1] = mono_mb_get_label (mb);
1632 emit_thread_force_interrupt_checkpoint (mb);
1633 emit_invoke_call (mb, method, sig, callsig, loc_res, virtual_, need_direct_wrapper);
1635 labels [2] = mono_mb_emit_branch (mb, CEE_LEAVE);
1637 /* Add a try clause around the call */
1638 clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
1639 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
1640 clause->data.catch_class = mono_defaults.exception_class;
1641 clause->try_offset = labels [1];
1642 clause->try_len = mono_mb_get_label (mb) - labels [1];
1644 clause->handler_offset = mono_mb_get_label (mb);
1646 /* handler code */
1647 mono_mb_emit_stloc (mb, loc_exc);
1648 mono_mb_emit_byte (mb, CEE_LDARG_2);
1649 mono_mb_emit_ldloc (mb, loc_exc);
1650 mono_mb_emit_byte (mb, CEE_STIND_REF);
1652 mono_mb_emit_branch (mb, CEE_LEAVE);
1654 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
1656 mono_mb_set_clauses (mb, 1, clause);
1658 mono_mb_patch_branch (mb, labels [2]);
1659 mono_mb_emit_ldloc (mb, loc_res);
1660 mono_mb_emit_byte (mb, CEE_RET);
1663 * if (!exc) case
1665 mono_mb_patch_branch (mb, labels [0]);
1666 emit_thread_force_interrupt_checkpoint (mb);
1667 emit_invoke_call (mb, method, sig, callsig, loc_res, virtual_, need_direct_wrapper);
1669 mono_mb_emit_ldloc (mb, 0);
1670 mono_mb_emit_byte (mb, CEE_RET);
1673 static void
1674 emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder *mb)
1676 int pos;
1677 MonoExceptionClause *clause;
1679 MonoType *object_type = mono_get_object_type ();
1680 /* allocate local 0 (object) tmp */
1681 mono_mb_add_local (mb, object_type);
1682 /* allocate local 1 (object) exc */
1683 mono_mb_add_local (mb, object_type);
1685 /* cond set *exc to null */
1686 mono_mb_emit_byte (mb, CEE_LDARG_1);
1687 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1688 mono_mb_emit_byte (mb, 3);
1689 mono_mb_emit_byte (mb, CEE_LDARG_1);
1690 mono_mb_emit_byte (mb, CEE_LDNULL);
1691 mono_mb_emit_byte (mb, CEE_STIND_REF);
1693 emit_thread_force_interrupt_checkpoint (mb);
1695 mono_mb_emit_byte (mb, CEE_LDARG_0);
1696 mono_mb_emit_byte (mb, CEE_LDARG_2);
1697 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1698 mono_mb_emit_byte (mb, CEE_MONO_DYN_CALL);
1700 pos = mono_mb_emit_branch (mb, CEE_LEAVE);
1702 clause = (MonoExceptionClause *)mono_image_alloc0 (mono_defaults.corlib, sizeof (MonoExceptionClause));
1703 clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
1704 clause->try_len = mono_mb_get_label (mb);
1706 /* filter code */
1707 clause->data.filter_offset = mono_mb_get_label (mb);
1709 mono_mb_emit_byte (mb, CEE_POP);
1710 mono_mb_emit_byte (mb, CEE_LDARG_1);
1711 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1712 mono_mb_emit_byte (mb, CEE_PREFIX1);
1713 mono_mb_emit_byte (mb, CEE_CGT_UN);
1714 mono_mb_emit_byte (mb, CEE_PREFIX1);
1715 mono_mb_emit_byte (mb, CEE_ENDFILTER);
1717 clause->handler_offset = mono_mb_get_label (mb);
1719 /* handler code */
1720 /* store exception */
1721 mono_mb_emit_stloc (mb, 1);
1723 mono_mb_emit_byte (mb, CEE_LDARG_1);
1724 mono_mb_emit_ldloc (mb, 1);
1725 mono_mb_emit_byte (mb, CEE_STIND_REF);
1727 mono_mb_emit_byte (mb, CEE_LDNULL);
1728 mono_mb_emit_stloc (mb, 0);
1730 mono_mb_emit_branch (mb, CEE_LEAVE);
1732 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
1734 mono_mb_set_clauses (mb, 1, clause);
1736 /* return result */
1737 mono_mb_patch_branch (mb, pos);
1738 //mono_mb_emit_ldloc (mb, 0);
1739 mono_mb_emit_byte (mb, CEE_RET);
1742 static void
1743 mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
1745 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));
1746 mono_mb_emit_exception_marshal_directive (mb, msg);
1749 typedef struct EmitGCSafeTransitionBuilder {
1750 MonoMethodBuilder *mb;
1751 gboolean func_param;
1752 int coop_gc_stack_dummy;
1753 int coop_gc_var;
1754 #ifndef DISABLE_COM
1755 int coop_cominterop_fnptr;
1756 #endif
1757 } GCSafeTransitionBuilder;
1759 static gboolean
1760 gc_safe_transition_builder_init (GCSafeTransitionBuilder *builder, MonoMethodBuilder *mb, gboolean func_param)
1762 builder->mb = mb;
1763 builder->func_param = func_param;
1764 builder->coop_gc_stack_dummy = -1;
1765 builder->coop_gc_var = -1;
1766 #ifndef DISABLE_COM
1767 builder->coop_cominterop_fnptr = -1;
1768 #endif
1769 #if defined (TARGET_WASM)
1770 return FALSE;
1771 #else
1772 return TRUE;
1773 #endif
1777 * adds locals for the gc safe transition to the method builder.
1779 static void
1780 gc_safe_transition_builder_add_locals (GCSafeTransitionBuilder *builder)
1782 MonoType *int_type = mono_get_int_type();
1783 /* local 4, dummy local used to get a stack address for suspend funcs */
1784 builder->coop_gc_stack_dummy = mono_mb_add_local (builder->mb, int_type);
1785 /* local 5, the local to be used when calling the suspend funcs */
1786 builder->coop_gc_var = mono_mb_add_local (builder->mb, int_type);
1787 #ifndef DISABLE_COM
1788 if (!builder->func_param && MONO_CLASS_IS_IMPORT (builder->mb->method->klass)) {
1789 builder->coop_cominterop_fnptr = mono_mb_add_local (builder->mb, int_type);
1791 #endif
1795 * emits
1796 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1799 static void
1800 gc_safe_transition_builder_emit_enter (GCSafeTransitionBuilder *builder, MonoMethod *method, gboolean aot)
1803 // Perform an extra, early lookup of the function address, so any exceptions
1804 // potentially resulting from the lookup occur before entering blocking mode.
1805 if (!builder->func_param && !MONO_CLASS_IS_IMPORT (builder->mb->method->klass) && aot) {
1806 mono_mb_emit_byte (builder->mb, MONO_CUSTOM_PREFIX);
1807 mono_mb_emit_op (builder->mb, CEE_MONO_ICALL_ADDR, method);
1808 mono_mb_emit_byte (builder->mb, CEE_POP); // Result not needed yet
1811 #ifndef DISABLE_COM
1812 if (!builder->func_param && MONO_CLASS_IS_IMPORT (builder->mb->method->klass)) {
1813 mono_mb_emit_cominterop_get_function_pointer (builder->mb, method);
1814 mono_mb_emit_stloc (builder->mb, builder->coop_cominterop_fnptr);
1816 #endif
1818 mono_mb_emit_ldloc_addr (builder->mb, builder->coop_gc_stack_dummy);
1819 mono_mb_emit_icall (builder->mb, mono_threads_enter_gc_safe_region_unbalanced);
1820 mono_mb_emit_stloc (builder->mb, builder->coop_gc_var);
1824 * emits
1825 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1828 static void
1829 gc_safe_transition_builder_emit_exit (GCSafeTransitionBuilder *builder)
1831 mono_mb_emit_ldloc (builder->mb, builder->coop_gc_var);
1832 mono_mb_emit_ldloc_addr (builder->mb, builder->coop_gc_stack_dummy);
1833 mono_mb_emit_icall (builder->mb, mono_threads_exit_gc_safe_region_unbalanced);
1836 static void
1837 gc_safe_transition_builder_cleanup (GCSafeTransitionBuilder *builder)
1839 builder->mb = NULL;
1840 builder->coop_gc_stack_dummy = -1;
1841 builder->coop_gc_var = -1;
1842 #ifndef DISABLE_COM
1843 builder->coop_cominterop_fnptr = -1;
1844 #endif
1848 * emit_native_wrapper_ilgen:
1849 * \param image the image to use for looking up custom marshallers
1850 * \param sig The signature of the native function
1851 * \param piinfo Marshalling information
1852 * \param mspecs Marshalling information
1853 * \param aot whenever the created method will be compiled by the AOT compiler
1854 * \param method if non-NULL, the pinvoke method to call
1855 * \param check_exceptions Whenever to check for pending exceptions after the native call
1856 * \param func_param the function to call is passed as a boxed IntPtr as the first parameter
1858 * generates IL code for the pinvoke wrapper, the generated code calls \p func .
1860 static void
1861 emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param)
1863 EmitMarshalContext m;
1864 MonoMethodSignature *csig;
1865 MonoClass *klass;
1866 int i, argnum, *tmp_locals;
1867 int type, param_shift = 0;
1868 gboolean need_gc_safe = FALSE;
1869 GCSafeTransitionBuilder gc_safe_transition_builder;
1871 memset (&m, 0, sizeof (m));
1872 m.mb = mb;
1873 m.sig = sig;
1874 m.piinfo = piinfo;
1876 need_gc_safe = gc_safe_transition_builder_init (&gc_safe_transition_builder, mb, func_param);
1878 /* we copy the signature, so that we can set pinvoke to 0 */
1879 if (func_param) {
1880 /* The function address is passed as the first argument */
1881 g_assert (!sig->hasthis);
1882 param_shift += 1;
1884 csig = mono_metadata_signature_dup_full (get_method_image (mb->method), sig);
1885 csig->pinvoke = 1;
1886 m.csig = csig;
1887 m.image = image;
1889 if (sig->hasthis)
1890 param_shift += 1;
1892 MonoType *int_type = mono_get_int_type ();
1893 MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
1894 /* we allocate local for use with emit_struct_conv() */
1895 /* allocate local 0 (pointer) src_ptr */
1896 mono_mb_add_local (mb, int_type);
1897 /* allocate local 1 (pointer) dst_ptr */
1898 mono_mb_add_local (mb, int_type);
1899 /* allocate local 2 (boolean) delete_old */
1900 mono_mb_add_local (mb, boolean_type);
1902 /* delete_old = FALSE */
1903 mono_mb_emit_icon (mb, 0);
1904 mono_mb_emit_stloc (mb, 2);
1906 if (!MONO_TYPE_IS_VOID (sig->ret)) {
1907 /* allocate local 3 to store the return value */
1908 mono_mb_add_local (mb, sig->ret);
1911 if (need_gc_safe) {
1912 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder);
1916 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
1918 * ret = method (...);
1920 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
1922 * <interrupt check>
1924 * return ret;
1927 if (MONO_TYPE_ISSTRUCT (sig->ret))
1928 m.vtaddr_var = mono_mb_add_local (mb, int_type);
1930 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
1931 /* Return type custom marshaling */
1933 * Since we can't determine the return type of the unmanaged function,
1934 * we assume it returns a pointer, and pass that pointer to
1935 * MarshalNativeToManaged.
1937 csig->ret = int_type;
1940 /* we first do all conversions */
1941 tmp_locals = g_newa (int, sig->param_count);
1942 m.orig_conv_args = g_newa (int, sig->param_count + 1);
1944 for (i = 0; i < sig->param_count; i ++) {
1945 tmp_locals [i] = mono_emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
1948 // In coop mode need to register blocking state during native call
1949 if (need_gc_safe)
1950 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder, &piinfo->method, aot);
1952 /* push all arguments */
1954 if (sig->hasthis)
1955 mono_mb_emit_byte (mb, CEE_LDARG_0);
1957 for (i = 0; i < sig->param_count; i++) {
1958 mono_emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
1961 /* call the native method */
1962 if (func_param) {
1963 mono_mb_emit_byte (mb, CEE_LDARG_0);
1964 mono_mb_emit_op (mb, CEE_UNBOX, mono_defaults.int_class);
1965 mono_mb_emit_byte (mb, CEE_LDIND_I);
1966 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
1967 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1968 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR);
1970 mono_mb_emit_calli (mb, csig);
1971 } else if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
1972 #ifndef DISABLE_COM
1973 mono_mb_emit_ldloc (mb, gc_safe_transition_builder.coop_cominterop_fnptr);
1974 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
1975 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1976 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR);
1978 mono_mb_emit_cominterop_call_function_pointer (mb, csig);
1979 #else
1980 g_assert_not_reached ();
1981 #endif
1982 } else {
1983 if (aot) {
1984 /* Reuse the ICALL_ADDR opcode for pinvokes too */
1985 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1986 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
1987 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
1988 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1989 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR);
1991 mono_mb_emit_calli (mb, csig);
1992 } else {
1993 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
1994 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1995 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR);
1997 mono_mb_emit_native_call (mb, csig, func);
2001 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2002 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
2003 mono_class_init_internal (klass);
2004 if (!(mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass))) {
2005 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
2006 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2007 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
2008 mono_mb_emit_stloc (mb, m.vtaddr_var);
2012 /* Unblock before converting the result, since that can involve calls into the runtime */
2013 if (need_gc_safe)
2014 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder);
2016 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder);
2018 /* convert the result */
2019 if (!sig->ret->byref) {
2020 MonoMarshalSpec *spec = mspecs [0];
2021 type = sig->ret->type;
2023 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
2024 mono_emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
2025 } else {
2026 handle_enum:
2027 switch (type) {
2028 case MONO_TYPE_VOID:
2029 break;
2030 case MONO_TYPE_VALUETYPE:
2031 klass = sig->ret->data.klass;
2032 if (m_class_is_enumtype (klass)) {
2033 type = mono_class_enum_basetype_internal (sig->ret->data.klass)->type;
2034 goto handle_enum;
2036 mono_emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
2037 break;
2038 case MONO_TYPE_I1:
2039 case MONO_TYPE_U1:
2040 case MONO_TYPE_I2:
2041 case MONO_TYPE_U2:
2042 case MONO_TYPE_I4:
2043 case MONO_TYPE_U4:
2044 case MONO_TYPE_I:
2045 case MONO_TYPE_U:
2046 case MONO_TYPE_R4:
2047 case MONO_TYPE_R8:
2048 case MONO_TYPE_I8:
2049 case MONO_TYPE_U8:
2050 case MONO_TYPE_FNPTR:
2051 case MONO_TYPE_STRING:
2052 case MONO_TYPE_CLASS:
2053 case MONO_TYPE_OBJECT:
2054 case MONO_TYPE_BOOLEAN:
2055 case MONO_TYPE_ARRAY:
2056 case MONO_TYPE_SZARRAY:
2057 case MONO_TYPE_CHAR:
2058 case MONO_TYPE_PTR:
2059 case MONO_TYPE_GENERICINST:
2060 mono_emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
2061 break;
2062 case MONO_TYPE_TYPEDBYREF:
2063 default:
2064 g_warning ("return type 0x%02x unknown", sig->ret->type);
2065 g_assert_not_reached ();
2068 } else {
2069 mono_mb_emit_stloc (mb, 3);
2073 * Need to call this after converting the result since MONO_VTADDR needs
2074 * to be adjacent to the call instruction.
2076 if (check_exceptions)
2077 emit_thread_interrupt_checkpoint (mb);
2079 /* we need to convert byref arguments back and free string arrays */
2080 for (i = 0; i < sig->param_count; i++) {
2081 MonoType *t = sig->params [i];
2082 MonoMarshalSpec *spec = mspecs [i + 1];
2084 argnum = i + param_shift;
2086 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
2087 mono_emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
2088 continue;
2091 switch (t->type) {
2092 case MONO_TYPE_STRING:
2093 case MONO_TYPE_VALUETYPE:
2094 case MONO_TYPE_CLASS:
2095 case MONO_TYPE_OBJECT:
2096 case MONO_TYPE_SZARRAY:
2097 case MONO_TYPE_BOOLEAN:
2098 mono_emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
2099 break;
2100 default:
2101 break;
2105 if (!MONO_TYPE_IS_VOID(sig->ret))
2106 mono_mb_emit_ldloc (mb, 3);
2108 mono_mb_emit_byte (mb, CEE_RET);
2112 * The code directly following this is the cache hit, value positive branch
2114 * This function takes a new method builder with 0 locals and adds two locals
2115 * to create multiple out-branches and the fall through state of having the object
2116 * on the stack after a cache miss
2118 static void
2119 generate_check_cache (int obj_arg_position, int class_arg_position, int cache_arg_position, // In-parameters
2120 int *null_obj, int *cache_hit_neg, int *cache_hit_pos, // Out-parameters
2121 MonoMethodBuilder *mb)
2123 int cache_miss_pos;
2125 MonoType *int_type = mono_get_int_type ();
2126 /* allocate local 0 (pointer) obj_vtable */
2127 mono_mb_add_local (mb, int_type);
2128 /* allocate local 1 (pointer) cached_vtable */
2129 mono_mb_add_local (mb, int_type);
2131 /*if (!obj)*/
2132 mono_mb_emit_ldarg (mb, obj_arg_position);
2133 *null_obj = mono_mb_emit_branch (mb, CEE_BRFALSE);
2135 /*obj_vtable = obj->vtable;*/
2136 mono_mb_emit_ldarg (mb, obj_arg_position);
2137 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
2138 mono_mb_emit_byte (mb, CEE_LDIND_I);
2139 mono_mb_emit_stloc (mb, 0);
2141 /* cached_vtable = *cache*/
2142 mono_mb_emit_ldarg (mb, cache_arg_position);
2143 mono_mb_emit_byte (mb, CEE_LDIND_I);
2144 mono_mb_emit_stloc (mb, 1);
2146 mono_mb_emit_ldloc (mb, 1);
2147 mono_mb_emit_byte (mb, CEE_LDC_I4);
2148 mono_mb_emit_i4 (mb, ~0x1);
2149 mono_mb_emit_byte (mb, CEE_CONV_I);
2150 mono_mb_emit_byte (mb, CEE_AND);
2151 mono_mb_emit_ldloc (mb, 0);
2152 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
2153 cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
2155 /*return (cached_vtable & 0x1) ? NULL : obj;*/
2156 mono_mb_emit_ldloc (mb, 1);
2157 mono_mb_emit_byte(mb, CEE_LDC_I4_1);
2158 mono_mb_emit_byte (mb, CEE_CONV_U);
2159 mono_mb_emit_byte (mb, CEE_AND);
2160 *cache_hit_neg = mono_mb_emit_branch (mb, CEE_BRTRUE);
2161 *cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
2163 // slow path
2164 mono_mb_patch_branch (mb, cache_miss_pos);
2166 // if isinst
2167 mono_mb_emit_ldarg (mb, obj_arg_position);
2168 mono_mb_emit_ldarg (mb, class_arg_position);
2169 mono_mb_emit_ldarg (mb, cache_arg_position);
2170 mono_mb_emit_icall (mb, mono_marshal_isinst_with_cache);
2173 static void
2174 emit_castclass_ilgen (MonoMethodBuilder *mb)
2176 int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos, invalid_cast_pos;
2177 const int obj_arg_position = TYPECHECK_OBJECT_ARG_POS;
2178 const int class_arg_position = TYPECHECK_CLASS_ARG_POS;
2179 const int cache_arg_position = TYPECHECK_CACHE_ARG_POS;
2181 generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position,
2182 &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
2183 invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
2185 /*return obj;*/
2186 mono_mb_patch_branch (mb, positive_cache_hit_pos);
2187 mono_mb_emit_ldarg (mb, obj_arg_position);
2188 mono_mb_emit_byte (mb, CEE_RET);
2190 /*fails*/
2191 mono_mb_patch_branch (mb, negative_cache_hit_pos);
2192 mono_mb_patch_branch (mb, invalid_cast_pos);
2193 mono_mb_emit_exception (mb, "InvalidCastException", NULL);
2195 /*return null*/
2196 mono_mb_patch_branch (mb, return_null_pos);
2197 mono_mb_emit_byte (mb, CEE_LDNULL);
2198 mono_mb_emit_byte (mb, CEE_RET);
2201 static void
2202 emit_isinst_ilgen (MonoMethodBuilder *mb)
2204 int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos;
2205 const int obj_arg_position = TYPECHECK_OBJECT_ARG_POS;
2206 const int class_arg_position = TYPECHECK_CLASS_ARG_POS;
2207 const int cache_arg_position = TYPECHECK_CACHE_ARG_POS;
2209 generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position,
2210 &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
2211 // Return the object gotten via the slow path.
2212 mono_mb_emit_byte (mb, CEE_RET);
2214 // return NULL;
2215 mono_mb_patch_branch (mb, negative_cache_hit_pos);
2216 mono_mb_patch_branch (mb, return_null_pos);
2217 mono_mb_emit_byte (mb, CEE_LDNULL);
2218 mono_mb_emit_byte (mb, CEE_RET);
2220 // return obj
2221 mono_mb_patch_branch (mb, positive_cache_hit_pos);
2222 mono_mb_emit_ldarg (mb, obj_arg_position);
2223 mono_mb_emit_byte (mb, CEE_RET);
2226 static void
2227 load_array_element_address (MonoMethodBuilder *mb)
2229 mono_mb_emit_ldarg (mb, 0);
2230 mono_mb_emit_ldarg (mb, 1);
2231 mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
2234 static void
2235 load_array_class (MonoMethodBuilder *mb, int aklass)
2237 mono_mb_emit_ldarg (mb, 0);
2238 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
2239 mono_mb_emit_byte (mb, CEE_LDIND_I);
2240 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
2241 mono_mb_emit_byte (mb, CEE_LDIND_I);
2242 mono_mb_emit_ldflda (mb, m_class_offsetof_element_class ());
2243 mono_mb_emit_byte (mb, CEE_LDIND_I);
2244 mono_mb_emit_stloc (mb, aklass);
2247 static void
2248 load_value_class (MonoMethodBuilder *mb, int vklass)
2250 mono_mb_emit_ldarg (mb, 2);
2251 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
2252 mono_mb_emit_byte (mb, CEE_LDIND_I);
2253 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
2254 mono_mb_emit_byte (mb, CEE_LDIND_I);
2255 mono_mb_emit_stloc (mb, vklass);
2258 static int
2259 emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
2260 MonoMarshalSpec *spec,
2261 int conv_arg, MonoType **conv_arg_type,
2262 MarshalAction action)
2264 MonoMethodBuilder *mb = m->mb;
2265 MonoClass *klass = mono_class_from_mono_type_internal (t);
2266 gboolean need_convert, need_free;
2267 MonoMarshalNative encoding;
2269 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
2270 MonoType *int_type = mono_get_int_type ();
2271 MonoType *object_type = mono_get_object_type ();
2273 MonoClass *eklass = m_class_get_element_class (klass);
2275 switch (action) {
2276 case MARSHAL_ACTION_CONV_IN:
2277 *conv_arg_type = object_type;
2278 conv_arg = mono_mb_add_local (mb, object_type);
2280 if (m_class_is_blittable (eklass)) {
2281 mono_mb_emit_ldarg (mb, argnum);
2282 if (t->byref)
2283 mono_mb_emit_byte (mb, CEE_LDIND_I);
2284 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
2285 mono_mb_emit_stloc (mb, conv_arg);
2286 } else {
2287 guint32 label1, label2, label3;
2288 int index_var, src_var, dest_ptr, esize;
2289 MonoMarshalConv conv;
2290 gboolean is_string = FALSE;
2292 dest_ptr = mono_mb_add_local (mb, int_type);
2294 if (eklass == mono_defaults.string_class) {
2295 is_string = TRUE;
2296 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
2298 else if (eklass == mono_class_try_get_stringbuilder_class ()) {
2299 is_string = TRUE;
2300 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
2302 else
2303 conv = MONO_MARSHAL_CONV_INVALID;
2305 if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
2306 char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
2307 mono_mb_emit_exception_marshal_directive (mb, msg);
2308 break;
2311 src_var = mono_mb_add_local (mb, object_type);
2312 mono_mb_emit_ldarg (mb, argnum);
2313 if (t->byref)
2314 mono_mb_emit_byte (mb, CEE_LDIND_I);
2315 mono_mb_emit_stloc (mb, src_var);
2317 /* Check null */
2318 mono_mb_emit_ldloc (mb, src_var);
2319 mono_mb_emit_stloc (mb, conv_arg);
2320 mono_mb_emit_ldloc (mb, src_var);
2321 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
2323 if (is_string)
2324 esize = TARGET_SIZEOF_VOID_P;
2325 else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
2326 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
2327 else
2328 esize = mono_class_native_size (eklass, NULL);
2330 /* allocate space for the native struct and store the address */
2331 mono_mb_emit_icon (mb, esize);
2332 mono_mb_emit_ldloc (mb, src_var);
2333 mono_mb_emit_byte (mb, CEE_LDLEN);
2335 if (eklass == mono_defaults.string_class) {
2336 /* Make the array bigger for the terminating null */
2337 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2338 mono_mb_emit_byte (mb, CEE_ADD);
2340 mono_mb_emit_byte (mb, CEE_MUL);
2341 mono_mb_emit_byte (mb, CEE_PREFIX1);
2342 mono_mb_emit_byte (mb, CEE_LOCALLOC);
2343 mono_mb_emit_stloc (mb, conv_arg);
2345 mono_mb_emit_ldloc (mb, conv_arg);
2346 mono_mb_emit_stloc (mb, dest_ptr);
2348 /* Emit marshalling loop */
2349 index_var = mono_mb_add_local (mb, int_type);
2350 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2351 mono_mb_emit_stloc (mb, index_var);
2352 label2 = mono_mb_get_label (mb);
2353 mono_mb_emit_ldloc (mb, index_var);
2354 mono_mb_emit_ldloc (mb, src_var);
2355 mono_mb_emit_byte (mb, CEE_LDLEN);
2356 label3 = mono_mb_emit_branch (mb, CEE_BGE);
2358 /* Emit marshalling code */
2360 if (is_string) {
2361 int stind_op;
2362 mono_mb_emit_ldloc (mb, dest_ptr);
2363 mono_mb_emit_ldloc (mb, src_var);
2364 mono_mb_emit_ldloc (mb, index_var);
2365 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2366 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
2367 mono_mb_emit_byte (mb, stind_op);
2368 } else {
2369 /* set the src_ptr */
2370 mono_mb_emit_ldloc (mb, src_var);
2371 mono_mb_emit_ldloc (mb, index_var);
2372 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
2373 mono_mb_emit_stloc (mb, 0);
2375 /* set dst_ptr */
2376 mono_mb_emit_ldloc (mb, dest_ptr);
2377 mono_mb_emit_stloc (mb, 1);
2379 /* emit valuetype conversion code */
2380 emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
2383 mono_mb_emit_add_to_local (mb, index_var, 1);
2384 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
2386 mono_mb_emit_branch_label (mb, CEE_BR, label2);
2388 mono_mb_patch_branch (mb, label3);
2390 if (eklass == mono_defaults.string_class) {
2391 /* Null terminate */
2392 mono_mb_emit_ldloc (mb, dest_ptr);
2393 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2394 mono_mb_emit_byte (mb, CEE_STIND_I);
2397 mono_mb_patch_branch (mb, label1);
2400 break;
2402 case MARSHAL_ACTION_CONV_OUT:
2403 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
2404 need_convert = ((eklass == mono_defaults.char_class) && (encoding == MONO_NATIVE_LPWSTR)) || (eklass == mono_class_try_get_stringbuilder_class ()) || (t->attrs & PARAM_ATTRIBUTE_OUT);
2405 need_free = mono_marshal_need_free (m_class_get_byval_arg (eklass), m->piinfo, spec);
2407 if ((t->attrs & PARAM_ATTRIBUTE_OUT) && spec && spec->native == MONO_NATIVE_LPARRAY && spec->data.array_data.param_num != -1) {
2408 int param_num = spec->data.array_data.param_num;
2409 MonoType *param_type;
2411 param_type = m->sig->params [param_num];
2413 if (param_type->byref && param_type->type != MONO_TYPE_I4) {
2414 char *msg = g_strdup ("Not implemented.");
2415 mono_mb_emit_exception_marshal_directive (mb, msg);
2416 break;
2419 if (t->byref ) {
2420 mono_mb_emit_ldarg (mb, argnum);
2422 /* Create the managed array */
2423 mono_mb_emit_ldarg (mb, param_num);
2424 if (m->sig->params [param_num]->byref)
2425 // FIXME: Support other types
2426 mono_mb_emit_byte (mb, CEE_LDIND_I4);
2427 mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
2428 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
2429 /* Store into argument */
2430 mono_mb_emit_byte (mb, CEE_STIND_REF);
2434 if (need_convert || need_free) {
2435 /* FIXME: Optimize blittable case */
2436 guint32 label1, label2, label3;
2437 int index_var, src_ptr, loc, esize;
2439 if ((eklass == mono_class_try_get_stringbuilder_class ()) || (eklass == mono_defaults.string_class))
2440 esize = TARGET_SIZEOF_VOID_P;
2441 else if (eklass == mono_defaults.char_class)
2442 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
2443 else
2444 esize = mono_class_native_size (eklass, NULL);
2445 src_ptr = mono_mb_add_local (mb, int_type);
2446 loc = mono_mb_add_local (mb, int_type);
2448 /* Check null */
2449 mono_mb_emit_ldarg (mb, argnum);
2450 if (t->byref)
2451 mono_mb_emit_byte (mb, CEE_LDIND_I);
2452 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
2454 mono_mb_emit_ldloc (mb, conv_arg);
2455 mono_mb_emit_stloc (mb, src_ptr);
2457 /* Emit marshalling loop */
2458 index_var = mono_mb_add_local (mb, int_type);
2459 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2460 mono_mb_emit_stloc (mb, index_var);
2461 label2 = mono_mb_get_label (mb);
2462 mono_mb_emit_ldloc (mb, index_var);
2463 mono_mb_emit_ldarg (mb, argnum);
2464 if (t->byref)
2465 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2466 mono_mb_emit_byte (mb, CEE_LDLEN);
2467 label3 = mono_mb_emit_branch (mb, CEE_BGE);
2469 /* Emit marshalling code */
2471 if (eklass == mono_class_try_get_stringbuilder_class ()) {
2472 gboolean need_free2;
2473 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
2475 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
2477 /* dest */
2478 mono_mb_emit_ldarg (mb, argnum);
2479 if (t->byref)
2480 mono_mb_emit_byte (mb, CEE_LDIND_I);
2481 mono_mb_emit_ldloc (mb, index_var);
2482 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2484 /* src */
2485 mono_mb_emit_ldloc (mb, src_ptr);
2486 mono_mb_emit_byte (mb, CEE_LDIND_I);
2488 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
2490 if (need_free) {
2491 /* src */
2492 mono_mb_emit_ldloc (mb, src_ptr);
2493 mono_mb_emit_byte (mb, CEE_LDIND_I);
2495 mono_mb_emit_icall (mb, mono_marshal_free);
2498 else if (eklass == mono_defaults.string_class) {
2499 if (need_free) {
2500 /* src */
2501 mono_mb_emit_ldloc (mb, src_ptr);
2502 mono_mb_emit_byte (mb, CEE_LDIND_I);
2504 mono_mb_emit_icall (mb, mono_marshal_free);
2507 else {
2508 if (need_convert) {
2509 /* set the src_ptr */
2510 mono_mb_emit_ldloc (mb, src_ptr);
2511 mono_mb_emit_stloc (mb, 0);
2513 /* set dst_ptr */
2514 mono_mb_emit_ldarg (mb, argnum);
2515 if (t->byref)
2516 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2517 mono_mb_emit_ldloc (mb, index_var);
2518 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
2519 mono_mb_emit_stloc (mb, 1);
2521 /* emit valuetype conversion code */
2522 emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
2525 if (need_free) {
2526 mono_mb_emit_ldloc (mb, src_ptr);
2527 mono_mb_emit_stloc (mb, loc);
2529 emit_struct_free (mb, eklass, loc);
2533 mono_mb_emit_add_to_local (mb, index_var, 1);
2534 mono_mb_emit_add_to_local (mb, src_ptr, esize);
2536 mono_mb_emit_branch_label (mb, CEE_BR, label2);
2538 mono_mb_patch_branch (mb, label1);
2539 mono_mb_patch_branch (mb, label3);
2542 if (m_class_is_blittable (eklass)) {
2543 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
2545 mono_mb_emit_ldarg (mb, argnum);
2546 if (t->byref)
2547 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2548 mono_mb_emit_ldloc (mb, conv_arg);
2549 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
2552 break;
2554 case MARSHAL_ACTION_PUSH:
2555 if (t->byref)
2556 mono_mb_emit_ldloc_addr (mb, conv_arg);
2557 else
2558 mono_mb_emit_ldloc (mb, conv_arg);
2559 break;
2561 case MARSHAL_ACTION_CONV_RESULT:
2562 /* fixme: we need conversions here */
2563 mono_mb_emit_stloc (mb, 3);
2564 break;
2566 case MARSHAL_ACTION_MANAGED_CONV_IN: {
2567 guint32 label1, label2, label3;
2568 int index_var, src_ptr, esize, param_num, num_elem;
2569 MonoMarshalConv conv;
2570 gboolean is_string = FALSE;
2572 conv_arg = mono_mb_add_local (mb, object_type);
2573 *conv_arg_type = int_type;
2575 if (t->byref) {
2576 char *msg = g_strdup ("Byref array marshalling to managed code is not implemented.");
2577 mono_mb_emit_exception_marshal_directive (mb, msg);
2578 return conv_arg;
2580 if (!spec) {
2581 char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
2582 mono_mb_emit_exception_marshal_directive (mb, msg);
2583 return conv_arg;
2586 switch (spec->native) {
2587 case MONO_NATIVE_LPARRAY:
2588 break;
2589 case MONO_NATIVE_SAFEARRAY:
2590 #ifndef DISABLE_COM
2591 if (spec->data.safearray_data.elem_type != MONO_VARIANT_VARIANT) {
2592 char *msg = g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented.");
2593 mono_mb_emit_exception_marshal_directive (mb, msg);
2594 return conv_arg;
2596 return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
2597 #endif
2598 default: {
2599 char *msg = g_strdup ("Unsupported array type marshalling to managed code.");
2600 mono_mb_emit_exception_marshal_directive (mb, msg);
2601 return conv_arg;
2605 /* FIXME: t is from the method which is wrapped, not the delegate type */
2606 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
2608 param_num = spec->data.array_data.param_num;
2609 num_elem = spec->data.array_data.num_elem;
2610 if (spec->data.array_data.elem_mult == 0)
2611 /* param_num is not specified */
2612 param_num = -1;
2614 if (param_num == -1) {
2615 if (num_elem <= 0) {
2616 char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
2617 mono_mb_emit_exception_marshal_directive (mb, msg);
2618 return conv_arg;
2622 /* FIXME: Optimize blittable case */
2624 if (eklass == mono_defaults.string_class) {
2625 is_string = TRUE;
2626 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
2628 else if (eklass == mono_class_try_get_stringbuilder_class ()) {
2629 is_string = TRUE;
2630 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
2632 else
2633 conv = MONO_MARSHAL_CONV_INVALID;
2635 mono_marshal_load_type_info (eklass);
2637 if (is_string)
2638 esize = TARGET_SIZEOF_VOID_P;
2639 else
2640 esize = mono_class_native_size (eklass, NULL);
2641 src_ptr = mono_mb_add_local (mb, int_type);
2643 mono_mb_emit_byte (mb, CEE_LDNULL);
2644 mono_mb_emit_stloc (mb, conv_arg);
2646 /* Check param index */
2647 if (param_num != -1) {
2648 if (param_num >= m->sig->param_count) {
2649 char *msg = g_strdup ("Array size control parameter index is out of range.");
2650 mono_mb_emit_exception_marshal_directive (mb, msg);
2651 return conv_arg;
2653 switch (m->sig->params [param_num]->type) {
2654 case MONO_TYPE_I1:
2655 case MONO_TYPE_U1:
2656 case MONO_TYPE_I2:
2657 case MONO_TYPE_U2:
2658 case MONO_TYPE_I4:
2659 case MONO_TYPE_U4:
2660 case MONO_TYPE_I:
2661 case MONO_TYPE_U:
2662 case MONO_TYPE_I8:
2663 case MONO_TYPE_U8:
2664 break;
2665 default: {
2666 char *msg = g_strdup ("Array size control parameter must be an integral type.");
2667 mono_mb_emit_exception_marshal_directive (mb, msg);
2668 return conv_arg;
2673 /* Check null */
2674 mono_mb_emit_ldarg (mb, argnum);
2675 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
2677 mono_mb_emit_ldarg (mb, argnum);
2678 mono_mb_emit_stloc (mb, src_ptr);
2680 /* Create managed array */
2682 * The LPArray marshalling spec says that sometimes param_num starts
2683 * from 1, sometimes it starts from 0. But MS seems to allways start
2684 * from 0.
2687 if (param_num == -1) {
2688 mono_mb_emit_icon (mb, num_elem);
2689 } else {
2690 mono_mb_emit_ldarg (mb, param_num);
2691 if (num_elem > 0) {
2692 mono_mb_emit_icon (mb, num_elem);
2693 mono_mb_emit_byte (mb, CEE_ADD);
2695 mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
2698 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
2699 mono_mb_emit_stloc (mb, conv_arg);
2701 if (m_class_is_blittable (eklass)) {
2702 mono_mb_emit_ldloc (mb, conv_arg);
2703 mono_mb_emit_byte (mb, CEE_CONV_I);
2704 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
2705 mono_mb_emit_byte (mb, CEE_ADD);
2706 mono_mb_emit_ldarg (mb, argnum);
2707 mono_mb_emit_ldloc (mb, conv_arg);
2708 mono_mb_emit_byte (mb, CEE_LDLEN);
2709 mono_mb_emit_icon (mb, esize);
2710 mono_mb_emit_byte (mb, CEE_MUL);
2711 mono_mb_emit_byte (mb, CEE_PREFIX1);
2712 mono_mb_emit_byte (mb, CEE_CPBLK);
2713 mono_mb_patch_branch (mb, label1);
2714 break;
2717 /* Emit marshalling loop */
2718 index_var = mono_mb_add_local (mb, int_type);
2719 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2720 mono_mb_emit_stloc (mb, index_var);
2721 label2 = mono_mb_get_label (mb);
2722 mono_mb_emit_ldloc (mb, index_var);
2723 mono_mb_emit_ldloc (mb, conv_arg);
2724 mono_mb_emit_byte (mb, CEE_LDLEN);
2725 label3 = mono_mb_emit_branch (mb, CEE_BGE);
2727 /* Emit marshalling code */
2728 if (is_string) {
2729 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
2731 mono_mb_emit_ldloc (mb, conv_arg);
2732 mono_mb_emit_ldloc (mb, index_var);
2734 mono_mb_emit_ldloc (mb, src_ptr);
2735 mono_mb_emit_byte (mb, CEE_LDIND_I);
2737 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
2738 mono_mb_emit_byte (mb, CEE_STELEM_REF);
2740 else {
2741 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2742 mono_mb_emit_exception_marshal_directive (mb, msg);
2743 return conv_arg;
2746 mono_mb_emit_add_to_local (mb, index_var, 1);
2747 mono_mb_emit_add_to_local (mb, src_ptr, esize);
2749 mono_mb_emit_branch_label (mb, CEE_BR, label2);
2751 mono_mb_patch_branch (mb, label1);
2752 mono_mb_patch_branch (mb, label3);
2754 break;
2756 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
2757 guint32 label1, label2, label3;
2758 int index_var, dest_ptr, esize, param_num, num_elem;
2759 MonoMarshalConv conv;
2760 gboolean is_string = FALSE;
2762 if (!spec)
2763 /* Already handled in CONV_IN */
2764 break;
2766 /* These are already checked in CONV_IN */
2767 g_assert (!t->byref);
2768 g_assert (spec->native == MONO_NATIVE_LPARRAY);
2769 g_assert (t->attrs & PARAM_ATTRIBUTE_OUT);
2771 param_num = spec->data.array_data.param_num;
2772 num_elem = spec->data.array_data.num_elem;
2774 if (spec->data.array_data.elem_mult == 0)
2775 /* param_num is not specified */
2776 param_num = -1;
2778 if (param_num == -1) {
2779 if (num_elem <= 0) {
2780 g_assert_not_reached ();
2784 /* FIXME: Optimize blittable case */
2786 if (eklass == mono_defaults.string_class) {
2787 is_string = TRUE;
2788 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
2790 else if (eklass == mono_class_try_get_stringbuilder_class ()) {
2791 is_string = TRUE;
2792 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
2794 else
2795 conv = MONO_MARSHAL_CONV_INVALID;
2797 mono_marshal_load_type_info (eklass);
2799 if (is_string)
2800 esize = TARGET_SIZEOF_VOID_P;
2801 else
2802 esize = mono_class_native_size (eklass, NULL);
2804 dest_ptr = mono_mb_add_local (mb, int_type);
2806 /* Check null */
2807 mono_mb_emit_ldloc (mb, conv_arg);
2808 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
2810 mono_mb_emit_ldarg (mb, argnum);
2811 mono_mb_emit_stloc (mb, dest_ptr);
2813 if (m_class_is_blittable (eklass)) {
2814 /* dest */
2815 mono_mb_emit_ldarg (mb, argnum);
2816 /* src */
2817 mono_mb_emit_ldloc (mb, conv_arg);
2818 mono_mb_emit_byte (mb, CEE_CONV_I);
2819 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
2820 mono_mb_emit_byte (mb, CEE_ADD);
2821 /* length */
2822 mono_mb_emit_ldloc (mb, conv_arg);
2823 mono_mb_emit_byte (mb, CEE_LDLEN);
2824 mono_mb_emit_icon (mb, esize);
2825 mono_mb_emit_byte (mb, CEE_MUL);
2826 mono_mb_emit_byte (mb, CEE_PREFIX1);
2827 mono_mb_emit_byte (mb, CEE_CPBLK);
2828 break;
2831 /* Emit marshalling loop */
2832 index_var = mono_mb_add_local (mb, int_type);
2833 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2834 mono_mb_emit_stloc (mb, index_var);
2835 label2 = mono_mb_get_label (mb);
2836 mono_mb_emit_ldloc (mb, index_var);
2837 mono_mb_emit_ldloc (mb, conv_arg);
2838 mono_mb_emit_byte (mb, CEE_LDLEN);
2839 label3 = mono_mb_emit_branch (mb, CEE_BGE);
2841 /* Emit marshalling code */
2842 if (is_string) {
2843 int stind_op;
2844 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
2846 /* dest */
2847 mono_mb_emit_ldloc (mb, dest_ptr);
2849 /* src */
2850 mono_mb_emit_ldloc (mb, conv_arg);
2851 mono_mb_emit_ldloc (mb, index_var);
2853 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2855 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
2856 mono_mb_emit_byte (mb, stind_op);
2858 else {
2859 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
2860 mono_mb_emit_exception_marshal_directive (mb, msg);
2861 return conv_arg;
2864 mono_mb_emit_add_to_local (mb, index_var, 1);
2865 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
2867 mono_mb_emit_branch_label (mb, CEE_BR, label2);
2869 mono_mb_patch_branch (mb, label1);
2870 mono_mb_patch_branch (mb, label3);
2872 break;
2874 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
2875 guint32 label1, label2, label3;
2876 int index_var, src, dest, esize;
2877 MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
2878 gboolean is_string = FALSE;
2880 g_assert (!t->byref);
2882 mono_marshal_load_type_info (eklass);
2884 if (eklass == mono_defaults.string_class) {
2885 is_string = TRUE;
2886 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
2888 else {
2889 g_assert_not_reached ();
2892 if (is_string)
2893 esize = TARGET_SIZEOF_VOID_P;
2894 else if (eklass == mono_defaults.char_class)
2895 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
2896 else
2897 esize = mono_class_native_size (eklass, NULL);
2899 src = mono_mb_add_local (mb, object_type);
2900 dest = mono_mb_add_local (mb, int_type);
2902 mono_mb_emit_stloc (mb, src);
2903 mono_mb_emit_ldloc (mb, src);
2904 mono_mb_emit_stloc (mb, 3);
2906 /* Check for null */
2907 mono_mb_emit_ldloc (mb, src);
2908 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
2910 /* Allocate native array */
2911 mono_mb_emit_icon (mb, esize);
2912 mono_mb_emit_ldloc (mb, src);
2913 mono_mb_emit_byte (mb, CEE_LDLEN);
2915 if (eklass == mono_defaults.string_class) {
2916 /* Make the array bigger for the terminating null */
2917 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2918 mono_mb_emit_byte (mb, CEE_ADD);
2920 mono_mb_emit_byte (mb, CEE_MUL);
2921 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
2922 mono_mb_emit_stloc (mb, dest);
2923 mono_mb_emit_ldloc (mb, dest);
2924 mono_mb_emit_stloc (mb, 3);
2926 /* Emit marshalling loop */
2927 index_var = mono_mb_add_local (mb, int_type);
2928 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2929 mono_mb_emit_stloc (mb, index_var);
2930 label2 = mono_mb_get_label (mb);
2931 mono_mb_emit_ldloc (mb, index_var);
2932 mono_mb_emit_ldloc (mb, src);
2933 mono_mb_emit_byte (mb, CEE_LDLEN);
2934 label3 = mono_mb_emit_branch (mb, CEE_BGE);
2936 /* Emit marshalling code */
2937 if (is_string) {
2938 int stind_op;
2939 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
2941 /* dest */
2942 mono_mb_emit_ldloc (mb, dest);
2944 /* src */
2945 mono_mb_emit_ldloc (mb, src);
2946 mono_mb_emit_ldloc (mb, index_var);
2948 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
2950 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
2951 mono_mb_emit_byte (mb, stind_op);
2953 else {
2954 char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
2955 mono_mb_emit_exception_marshal_directive (mb, msg);
2956 return conv_arg;
2959 mono_mb_emit_add_to_local (mb, index_var, 1);
2960 mono_mb_emit_add_to_local (mb, dest, esize);
2962 mono_mb_emit_branch_label (mb, CEE_BR, label2);
2964 mono_mb_patch_branch (mb, label3);
2965 mono_mb_patch_branch (mb, label1);
2966 break;
2968 default:
2969 g_assert_not_reached ();
2971 return conv_arg;
2974 static int
2975 emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
2976 MonoMarshalSpec *spec,
2977 int conv_arg, MonoType **conv_arg_type,
2978 MarshalAction action)
2980 MonoMethodBuilder *mb = m->mb;
2981 MonoType *int_type = mono_get_int_type ();
2982 MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
2984 switch (action) {
2985 case MARSHAL_ACTION_CONV_IN: {
2986 MonoType *local_type;
2987 int label_false;
2988 guint8 ldc_op = CEE_LDC_I4_1;
2990 local_type = mono_marshal_boolean_conv_in_get_local_type (spec, &ldc_op);
2991 if (t->byref)
2992 *conv_arg_type = int_type;
2993 else
2994 *conv_arg_type = local_type;
2995 conv_arg = mono_mb_add_local (mb, local_type);
2997 mono_mb_emit_ldarg (mb, argnum);
2998 if (t->byref)
2999 mono_mb_emit_byte (mb, CEE_LDIND_I1);
3000 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
3001 mono_mb_emit_byte (mb, ldc_op);
3002 mono_mb_emit_stloc (mb, conv_arg);
3003 mono_mb_patch_branch (mb, label_false);
3005 break;
3008 case MARSHAL_ACTION_CONV_OUT:
3010 int label_false, label_end;
3011 if (!t->byref)
3012 break;
3014 mono_mb_emit_ldarg (mb, argnum);
3015 mono_mb_emit_ldloc (mb, conv_arg);
3017 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
3018 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3020 label_end = mono_mb_emit_branch (mb, CEE_BR);
3021 mono_mb_patch_branch (mb, label_false);
3022 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3023 mono_mb_patch_branch (mb, label_end);
3025 mono_mb_emit_byte (mb, CEE_STIND_I1);
3026 break;
3029 case MARSHAL_ACTION_PUSH:
3030 if (t->byref)
3031 mono_mb_emit_ldloc_addr (mb, conv_arg);
3032 else if (conv_arg)
3033 mono_mb_emit_ldloc (mb, conv_arg);
3034 else
3035 mono_mb_emit_ldarg (mb, argnum);
3036 break;
3038 case MARSHAL_ACTION_CONV_RESULT:
3039 /* maybe we need to make sure that it fits within 8 bits */
3040 mono_mb_emit_stloc (mb, 3);
3041 break;
3043 case MARSHAL_ACTION_MANAGED_CONV_IN: {
3044 MonoClass* conv_arg_class = mono_defaults.int32_class;
3045 guint8 ldop = CEE_LDIND_I4;
3046 int label_null, label_false;
3048 conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, &ldop);
3049 conv_arg = mono_mb_add_local (mb, boolean_type);
3051 if (t->byref)
3052 *conv_arg_type = m_class_get_this_arg (conv_arg_class);
3053 else
3054 *conv_arg_type = m_class_get_byval_arg (conv_arg_class);
3057 mono_mb_emit_ldarg (mb, argnum);
3059 /* Check null */
3060 if (t->byref) {
3061 label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
3062 mono_mb_emit_ldarg (mb, argnum);
3063 mono_mb_emit_byte (mb, ldop);
3064 } else
3065 label_null = 0;
3067 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
3068 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3069 mono_mb_emit_stloc (mb, conv_arg);
3070 mono_mb_patch_branch (mb, label_false);
3072 if (t->byref)
3073 mono_mb_patch_branch (mb, label_null);
3074 break;
3077 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
3078 guint8 stop = CEE_STIND_I4;
3079 guint8 ldc_op = CEE_LDC_I4_1;
3080 int label_null,label_false, label_end;
3082 if (!t->byref)
3083 break;
3084 if (spec) {
3085 switch (spec->native) {
3086 case MONO_NATIVE_I1:
3087 case MONO_NATIVE_U1:
3088 stop = CEE_STIND_I1;
3089 break;
3090 case MONO_NATIVE_VARIANTBOOL:
3091 stop = CEE_STIND_I2;
3092 ldc_op = CEE_LDC_I4_M1;
3093 break;
3094 default:
3095 break;
3099 /* Check null */
3100 mono_mb_emit_ldarg (mb, argnum);
3101 label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
3103 mono_mb_emit_ldarg (mb, argnum);
3104 mono_mb_emit_ldloc (mb, conv_arg);
3106 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
3107 mono_mb_emit_byte (mb, ldc_op);
3108 label_end = mono_mb_emit_branch (mb, CEE_BR);
3110 mono_mb_patch_branch (mb, label_false);
3111 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3112 mono_mb_patch_branch (mb, label_end);
3114 mono_mb_emit_byte (mb, stop);
3115 mono_mb_patch_branch (mb, label_null);
3116 break;
3119 default:
3120 g_assert_not_reached ();
3122 return conv_arg;
3125 static int
3126 emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
3127 MonoMarshalSpec *spec, int conv_arg,
3128 MonoType **conv_arg_type, MarshalAction action)
3130 MonoMethodBuilder *mb = m->mb;
3132 switch (action) {
3133 case MARSHAL_ACTION_CONV_IN:
3134 /* MS seems to allow this in some cases, ie. bxc #158 */
3136 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) {
3137 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
3138 mono_mb_emit_exception_marshal_directive (m->mb, msg);
3141 break;
3143 case MARSHAL_ACTION_PUSH:
3144 mono_mb_emit_ldarg (mb, argnum);
3145 break;
3147 case MARSHAL_ACTION_CONV_RESULT:
3148 /* no conversions necessary */
3149 mono_mb_emit_stloc (mb, 3);
3150 break;
3152 default:
3153 break;
3155 return conv_arg;
3158 static int
3159 emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
3160 MonoMarshalSpec *spec, int conv_arg,
3161 MonoType **conv_arg_type, MarshalAction action)
3163 MonoMethodBuilder *mb = m->mb;
3165 switch (action) {
3166 case MARSHAL_ACTION_PUSH:
3167 /* fixme: dont know how to marshal that. We cant simply
3168 * convert it to a one byte UTF8 character, because an
3169 * unicode character may need more that one byte in UTF8 */
3170 mono_mb_emit_ldarg (mb, argnum);
3171 break;
3173 case MARSHAL_ACTION_CONV_RESULT:
3174 /* fixme: we need conversions here */
3175 mono_mb_emit_stloc (mb, 3);
3176 break;
3178 default:
3179 break;
3181 return conv_arg;
3184 static int
3185 emit_marshal_scalar_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
3186 MonoMarshalSpec *spec, int conv_arg,
3187 MonoType **conv_arg_type, MarshalAction action)
3189 MonoMethodBuilder *mb = m->mb;
3191 switch (action) {
3192 case MARSHAL_ACTION_PUSH:
3193 mono_mb_emit_ldarg (mb, argnum);
3194 break;
3196 case MARSHAL_ACTION_CONV_RESULT:
3197 /* no conversions necessary */
3198 mono_mb_emit_stloc (mb, 3);
3199 break;
3201 default:
3202 break;
3204 return conv_arg;
3207 static void
3208 emit_virtual_stelemref_ilgen (MonoMethodBuilder *mb, const char **param_names, MonoStelemrefKind kind)
3210 guint32 b1, b2, b3, b4;
3211 int aklass, vklass, vtable, uiid;
3212 int array_slot_addr;
3214 mono_mb_set_param_names (mb, param_names);
3215 MonoType *int_type = mono_get_int_type ();
3216 MonoType *int32_type = m_class_get_byval_arg (mono_defaults.int32_class);
3217 MonoType *object_type_byref = m_class_get_this_arg (mono_defaults.object_class);
3219 /*For now simply call plain old stelemref*/
3220 switch (kind) {
3221 case STELEMREF_OBJECT:
3222 /* ldelema (implicit bound check) */
3223 load_array_element_address (mb);
3224 /* do_store */
3225 mono_mb_emit_ldarg (mb, 2);
3226 mono_mb_emit_byte (mb, CEE_STIND_REF);
3227 mono_mb_emit_byte (mb, CEE_RET);
3228 break;
3230 case STELEMREF_COMPLEX: {
3231 int b_fast;
3233 <ldelema (bound check)>
3234 if (!value)
3235 goto store;
3236 if (!mono_object_isinst (value, aklass))
3237 goto do_exception;
3239 do_store:
3240 *array_slot_addr = value;
3242 do_exception:
3243 throw new ArrayTypeMismatchException ();
3246 aklass = mono_mb_add_local (mb, int_type);
3247 vklass = mono_mb_add_local (mb, int_type);
3248 array_slot_addr = mono_mb_add_local (mb, object_type_byref);
3250 #if 0
3252 /*Use this to debug/record stores that are going thru the slow path*/
3253 MonoMethodSignature *csig;
3254 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
3255 csig->ret = mono_get_void_type ();
3256 csig->params [0] = object_type;
3257 csig->params [1] = int_type; /* this is a natural sized int */
3258 csig->params [2] = object_type;
3259 mono_mb_emit_ldarg (mb, 0);
3260 mono_mb_emit_ldarg (mb, 1);
3261 mono_mb_emit_ldarg (mb, 2);
3262 mono_mb_emit_native_call (mb, csig, record_slot_vstore);
3264 #endif
3266 /* ldelema (implicit bound check) */
3267 load_array_element_address (mb);
3268 mono_mb_emit_stloc (mb, array_slot_addr);
3270 /* if (!value) goto do_store */
3271 mono_mb_emit_ldarg (mb, 2);
3272 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3274 /* aklass = array->vtable->klass->element_class */
3275 load_array_class (mb, aklass);
3276 /* vklass = value->vtable->klass */
3277 load_value_class (mb, vklass);
3279 /* fastpath */
3280 mono_mb_emit_ldloc (mb, vklass);
3281 mono_mb_emit_ldloc (mb, aklass);
3282 b_fast = mono_mb_emit_branch (mb, CEE_BEQ);
3284 /*if (mono_object_isinst (value, aklass)) */
3285 mono_mb_emit_ldarg (mb, 2);
3286 mono_mb_emit_ldloc (mb, aklass);
3287 mono_mb_emit_icall (mb, mono_object_isinst_icall);
3288 b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3290 /* do_store: */
3291 mono_mb_patch_branch (mb, b1);
3292 mono_mb_patch_branch (mb, b_fast);
3293 mono_mb_emit_ldloc (mb, array_slot_addr);
3294 mono_mb_emit_ldarg (mb, 2);
3295 mono_mb_emit_byte (mb, CEE_STIND_REF);
3296 mono_mb_emit_byte (mb, CEE_RET);
3298 /* do_exception: */
3299 mono_mb_patch_branch (mb, b2);
3301 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
3302 break;
3304 case STELEMREF_SEALED_CLASS:
3306 <ldelema (bound check)>
3307 if (!value)
3308 goto store;
3310 aklass = array->vtable->m_class_get_element_class (klass);
3311 vklass = value->vtable->klass;
3313 if (vklass != aklass)
3314 goto do_exception;
3316 do_store:
3317 *array_slot_addr = value;
3319 do_exception:
3320 throw new ArrayTypeMismatchException ();
3322 aklass = mono_mb_add_local (mb, int_type);
3323 vklass = mono_mb_add_local (mb, int_type);
3324 array_slot_addr = mono_mb_add_local (mb, object_type_byref);
3326 /* ldelema (implicit bound check) */
3327 load_array_element_address (mb);
3328 mono_mb_emit_stloc (mb, array_slot_addr);
3330 /* if (!value) goto do_store */
3331 mono_mb_emit_ldarg (mb, 2);
3332 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3334 /* aklass = array->vtable->klass->element_class */
3335 load_array_class (mb, aklass);
3337 /* vklass = value->vtable->klass */
3338 load_value_class (mb, vklass);
3340 /*if (vklass != aklass) goto do_exception; */
3341 mono_mb_emit_ldloc (mb, aklass);
3342 mono_mb_emit_ldloc (mb, vklass);
3343 b2 = mono_mb_emit_branch (mb, CEE_BNE_UN);
3345 /* do_store: */
3346 mono_mb_patch_branch (mb, b1);
3347 mono_mb_emit_ldloc (mb, array_slot_addr);
3348 mono_mb_emit_ldarg (mb, 2);
3349 mono_mb_emit_byte (mb, CEE_STIND_REF);
3350 mono_mb_emit_byte (mb, CEE_RET);
3352 /* do_exception: */
3353 mono_mb_patch_branch (mb, b2);
3354 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
3355 break;
3357 case STELEMREF_CLASS: {
3359 the method:
3360 <ldelema (bound check)>
3361 if (!value)
3362 goto do_store;
3364 aklass = array->vtable->m_class_get_element_class (klass);
3365 vklass = value->vtable->klass;
3367 if (vklass->idepth < aklass->idepth)
3368 goto do_exception;
3370 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3371 goto do_exception;
3373 do_store:
3374 *array_slot_addr = value;
3375 return;
3377 long:
3378 throw new ArrayTypeMismatchException ();
3380 aklass = mono_mb_add_local (mb, int_type);
3381 vklass = mono_mb_add_local (mb, int_type);
3382 array_slot_addr = mono_mb_add_local (mb, object_type_byref);
3384 /* ldelema (implicit bound check) */
3385 load_array_element_address (mb);
3386 mono_mb_emit_stloc (mb, array_slot_addr);
3388 /* if (!value) goto do_store */
3389 mono_mb_emit_ldarg (mb, 2);
3390 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3392 /* aklass = array->vtable->klass->element_class */
3393 load_array_class (mb, aklass);
3395 /* vklass = value->vtable->klass */
3396 load_value_class (mb, vklass);
3398 /* if (vklass->idepth < aklass->idepth) goto failue */
3399 mono_mb_emit_ldloc (mb, vklass);
3400 mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ());
3401 mono_mb_emit_byte (mb, CEE_LDIND_U2);
3403 mono_mb_emit_ldloc (mb, aklass);
3404 mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ());
3405 mono_mb_emit_byte (mb, CEE_LDIND_U2);
3407 b3 = mono_mb_emit_branch (mb, CEE_BLT_UN);
3409 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3410 mono_mb_emit_ldloc (mb, vklass);
3411 mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ());
3412 mono_mb_emit_byte (mb, CEE_LDIND_I);
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);
3417 mono_mb_emit_icon (mb, 1);
3418 mono_mb_emit_byte (mb, CEE_SUB);
3419 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
3420 mono_mb_emit_byte (mb, CEE_MUL);
3421 mono_mb_emit_byte (mb, CEE_ADD);
3422 mono_mb_emit_byte (mb, CEE_LDIND_I);
3424 mono_mb_emit_ldloc (mb, aklass);
3425 b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
3427 /* do_store: */
3428 mono_mb_patch_branch (mb, b1);
3429 mono_mb_emit_ldloc (mb, array_slot_addr);
3430 mono_mb_emit_ldarg (mb, 2);
3431 mono_mb_emit_byte (mb, CEE_STIND_REF);
3432 mono_mb_emit_byte (mb, CEE_RET);
3434 /* do_exception: */
3435 mono_mb_patch_branch (mb, b3);
3436 mono_mb_patch_branch (mb, b4);
3438 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
3439 break;
3442 case STELEMREF_CLASS_SMALL_IDEPTH:
3444 the method:
3445 <ldelema (bound check)>
3446 if (!value)
3447 goto do_store;
3449 aklass = array->vtable->m_class_get_element_class (klass);
3450 vklass = value->vtable->klass;
3452 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3453 goto do_exception;
3455 do_store:
3456 *array_slot_addr = value;
3457 return;
3459 long:
3460 throw new ArrayTypeMismatchException ();
3462 aklass = mono_mb_add_local (mb, int_type);
3463 vklass = mono_mb_add_local (mb, int_type);
3464 array_slot_addr = mono_mb_add_local (mb, object_type_byref);
3466 /* ldelema (implicit bound check) */
3467 load_array_element_address (mb);
3468 mono_mb_emit_stloc (mb, array_slot_addr);
3470 /* if (!value) goto do_store */
3471 mono_mb_emit_ldarg (mb, 2);
3472 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3474 /* aklass = array->vtable->klass->element_class */
3475 load_array_class (mb, aklass);
3477 /* vklass = value->vtable->klass */
3478 load_value_class (mb, vklass);
3480 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3481 mono_mb_emit_ldloc (mb, vklass);
3482 mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ());
3483 mono_mb_emit_byte (mb, CEE_LDIND_I);
3485 mono_mb_emit_ldloc (mb, aklass);
3486 mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ());
3487 mono_mb_emit_byte (mb, CEE_LDIND_U2);
3488 mono_mb_emit_icon (mb, 1);
3489 mono_mb_emit_byte (mb, CEE_SUB);
3490 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
3491 mono_mb_emit_byte (mb, CEE_MUL);
3492 mono_mb_emit_byte (mb, CEE_ADD);
3493 mono_mb_emit_byte (mb, CEE_LDIND_I);
3495 mono_mb_emit_ldloc (mb, aklass);
3496 b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
3498 /* do_store: */
3499 mono_mb_patch_branch (mb, b1);
3500 mono_mb_emit_ldloc (mb, array_slot_addr);
3501 mono_mb_emit_ldarg (mb, 2);
3502 mono_mb_emit_byte (mb, CEE_STIND_REF);
3503 mono_mb_emit_byte (mb, CEE_RET);
3505 /* do_exception: */
3506 mono_mb_patch_branch (mb, b4);
3508 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
3509 break;
3511 case STELEMREF_INTERFACE:
3512 /*Mono *klass;
3513 MonoVTable *vt;
3514 unsigned uiid;
3515 if (value == NULL)
3516 goto store;
3518 klass = array->obj.vtable->klass->element_class;
3519 vt = value->vtable;
3520 uiid = klass->interface_id;
3521 if (uiid > vt->max_interface_id)
3522 goto exception;
3523 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
3524 goto exception;
3525 store:
3526 mono_array_setref_internal (array, index, value);
3527 return;
3528 exception:
3529 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
3531 array_slot_addr = mono_mb_add_local (mb, object_type_byref);
3532 aklass = mono_mb_add_local (mb, int_type);
3533 vtable = mono_mb_add_local (mb, int_type);
3534 uiid = mono_mb_add_local (mb, int32_type);
3536 /* ldelema (implicit bound check) */
3537 load_array_element_address (mb);
3538 mono_mb_emit_stloc (mb, array_slot_addr);
3540 /* if (!value) goto do_store */
3541 mono_mb_emit_ldarg (mb, 2);
3542 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3544 /* klass = array->vtable->m_class_get_element_class (klass) */
3545 load_array_class (mb, aklass);
3547 /* vt = value->vtable */
3548 mono_mb_emit_ldarg (mb, 2);
3549 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
3550 mono_mb_emit_byte (mb, CEE_LDIND_I);
3551 mono_mb_emit_stloc (mb, vtable);
3553 /* uiid = klass->interface_id; */
3554 mono_mb_emit_ldloc (mb, aklass);
3555 mono_mb_emit_ldflda (mb, m_class_offsetof_interface_id ());
3556 mono_mb_emit_byte (mb, CEE_LDIND_U4);
3557 mono_mb_emit_stloc (mb, uiid);
3559 /*if (uiid > vt->max_interface_id)*/
3560 mono_mb_emit_ldloc (mb, uiid);
3561 mono_mb_emit_ldloc (mb, vtable);
3562 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
3563 mono_mb_emit_byte (mb, CEE_LDIND_U4);
3564 b2 = mono_mb_emit_branch (mb, CEE_BGT_UN);
3566 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
3568 /*vt->interface_bitmap*/
3569 mono_mb_emit_ldloc (mb, vtable);
3570 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap));
3571 mono_mb_emit_byte (mb, CEE_LDIND_I);
3573 /*uiid >> 3*/
3574 mono_mb_emit_ldloc (mb, uiid);
3575 mono_mb_emit_icon (mb, 3);
3576 mono_mb_emit_byte (mb, CEE_SHR_UN);
3578 /*vt->interface_bitmap [(uiid) >> 3]*/
3579 mono_mb_emit_byte (mb, CEE_ADD); /*interface_bitmap is a guint8 array*/
3580 mono_mb_emit_byte (mb, CEE_LDIND_U1);
3582 /*(1 << ((uiid)&7)))*/
3583 mono_mb_emit_icon (mb, 1);
3584 mono_mb_emit_ldloc (mb, uiid);
3585 mono_mb_emit_icon (mb, 7);
3586 mono_mb_emit_byte (mb, CEE_AND);
3587 mono_mb_emit_byte (mb, CEE_SHL);
3589 /*bitwise and the whole thing*/
3590 mono_mb_emit_byte (mb, CEE_AND);
3591 b3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3593 /* do_store: */
3594 mono_mb_patch_branch (mb, b1);
3595 mono_mb_emit_ldloc (mb, array_slot_addr);
3596 mono_mb_emit_ldarg (mb, 2);
3597 mono_mb_emit_byte (mb, CEE_STIND_REF);
3598 mono_mb_emit_byte (mb, CEE_RET);
3600 /* do_exception: */
3601 mono_mb_patch_branch (mb, b2);
3602 mono_mb_patch_branch (mb, b3);
3603 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
3604 break;
3606 default:
3607 mono_mb_emit_ldarg (mb, 0);
3608 mono_mb_emit_ldarg (mb, 1);
3609 mono_mb_emit_ldarg (mb, 2);
3610 mono_mb_emit_managed_call (mb, mono_marshal_get_stelemref (), NULL);
3611 mono_mb_emit_byte (mb, CEE_RET);
3612 g_assert (0);
3616 static void
3617 emit_stelemref_ilgen (MonoMethodBuilder *mb)
3619 guint32 b1, b2, b3, b4;
3620 guint32 copy_pos;
3621 int aklass, vklass;
3622 int array_slot_addr;
3624 MonoType *int_type = mono_get_int_type ();
3625 MonoType *object_type_byref = m_class_get_this_arg (mono_defaults.object_class);
3627 aklass = mono_mb_add_local (mb, int_type);
3628 vklass = mono_mb_add_local (mb, int_type);
3629 array_slot_addr = mono_mb_add_local (mb, object_type_byref);
3632 the method:
3633 <ldelema (bound check)>
3634 if (!value)
3635 goto store;
3637 aklass = array->vtable->m_class_get_element_class (klass);
3638 vklass = value->vtable->klass;
3640 if (vklass->idepth < aklass->idepth)
3641 goto long;
3643 if (vklass->supertypes [aklass->idepth - 1] != aklass)
3644 goto long;
3646 store:
3647 *array_slot_addr = value;
3648 return;
3650 long:
3651 if (mono_object_isinst (value, aklass))
3652 goto store;
3654 throw new ArrayTypeMismatchException ();
3657 /* ldelema (implicit bound check) */
3658 mono_mb_emit_ldarg (mb, 0);
3659 mono_mb_emit_ldarg (mb, 1);
3660 mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
3661 mono_mb_emit_stloc (mb, array_slot_addr);
3663 /* if (!value) goto do_store */
3664 mono_mb_emit_ldarg (mb, 2);
3665 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3667 /* aklass = array->vtable->klass->element_class */
3668 mono_mb_emit_ldarg (mb, 0);
3669 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
3670 mono_mb_emit_byte (mb, CEE_LDIND_I);
3671 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
3672 mono_mb_emit_byte (mb, CEE_LDIND_I);
3673 mono_mb_emit_ldflda (mb, m_class_offsetof_element_class ());
3674 mono_mb_emit_byte (mb, CEE_LDIND_I);
3675 mono_mb_emit_stloc (mb, aklass);
3677 /* vklass = value->vtable->klass */
3678 mono_mb_emit_ldarg (mb, 2);
3679 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
3680 mono_mb_emit_byte (mb, CEE_LDIND_I);
3681 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
3682 mono_mb_emit_byte (mb, CEE_LDIND_I);
3683 mono_mb_emit_stloc (mb, vklass);
3685 /* if (vklass->idepth < aklass->idepth) goto failue */
3686 mono_mb_emit_ldloc (mb, vklass);
3687 mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ());
3688 mono_mb_emit_byte (mb, CEE_LDIND_U2);
3690 mono_mb_emit_ldloc (mb, aklass);
3691 mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ());
3692 mono_mb_emit_byte (mb, CEE_LDIND_U2);
3694 b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
3696 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
3697 mono_mb_emit_ldloc (mb, vklass);
3698 mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ());
3699 mono_mb_emit_byte (mb, CEE_LDIND_I);
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);
3704 mono_mb_emit_icon (mb, 1);
3705 mono_mb_emit_byte (mb, CEE_SUB);
3706 mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P);
3707 mono_mb_emit_byte (mb, CEE_MUL);
3708 mono_mb_emit_byte (mb, CEE_ADD);
3709 mono_mb_emit_byte (mb, CEE_LDIND_I);
3711 mono_mb_emit_ldloc (mb, aklass);
3713 b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
3715 copy_pos = mono_mb_get_label (mb);
3716 /* do_store */
3717 mono_mb_patch_branch (mb, b1);
3718 mono_mb_emit_ldloc (mb, array_slot_addr);
3719 mono_mb_emit_ldarg (mb, 2);
3720 mono_mb_emit_byte (mb, CEE_STIND_REF);
3722 mono_mb_emit_byte (mb, CEE_RET);
3724 /* the hard way */
3725 mono_mb_patch_branch (mb, b2);
3726 mono_mb_patch_branch (mb, b3);
3728 mono_mb_emit_ldarg (mb, 2);
3729 mono_mb_emit_ldloc (mb, aklass);
3730 mono_mb_emit_icall (mb, mono_object_isinst_icall);
3732 b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
3733 mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
3734 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
3736 mono_mb_emit_byte (mb, CEE_RET);
3739 static void
3740 mb_emit_byte_ilgen (MonoMethodBuilder *mb, guint8 op)
3742 mono_mb_emit_byte (mb, op);
3745 static void
3746 emit_array_address_ilgen (MonoMethodBuilder *mb, int rank, int elem_size)
3748 int i, bounds, ind, realidx;
3749 int branch_pos, *branch_positions;
3751 MonoType *int_type = mono_get_int_type ();
3752 MonoType *int32_type = mono_get_int32_type ();
3754 branch_positions = g_new0 (int, rank);
3756 bounds = mono_mb_add_local (mb, int_type);
3757 ind = mono_mb_add_local (mb, int32_type);
3758 realidx = mono_mb_add_local (mb, int32_type);
3760 /* bounds = array->bounds; */
3761 mono_mb_emit_ldarg (mb, 0);
3762 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, bounds));
3763 mono_mb_emit_byte (mb, CEE_LDIND_I);
3764 mono_mb_emit_stloc (mb, bounds);
3766 /* ind is the overall element index, realidx is the partial index in a single dimension */
3767 /* ind = idx0 - bounds [0].lower_bound */
3768 mono_mb_emit_ldarg (mb, 1);
3769 mono_mb_emit_ldloc (mb, bounds);
3770 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
3771 mono_mb_emit_byte (mb, CEE_ADD);
3772 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3773 mono_mb_emit_byte (mb, CEE_SUB);
3774 mono_mb_emit_stloc (mb, ind);
3775 /* if (ind >= bounds [0].length) goto exeception; */
3776 mono_mb_emit_ldloc (mb, ind);
3777 mono_mb_emit_ldloc (mb, bounds);
3778 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
3779 mono_mb_emit_byte (mb, CEE_ADD);
3780 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3781 /* note that we use unsigned comparison */
3782 branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
3784 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
3785 * We could also decide to ignore the passed elem_size and get it
3786 * from the array object, to reduce the number of methods we generate:
3787 * the additional cost is 3 memory loads and a non-immediate mul.
3789 for (i = 1; i < rank; ++i) {
3790 /* realidx = idxi - bounds [i].lower_bound */
3791 mono_mb_emit_ldarg (mb, 1 + i);
3792 mono_mb_emit_ldloc (mb, bounds);
3793 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
3794 mono_mb_emit_byte (mb, CEE_ADD);
3795 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3796 mono_mb_emit_byte (mb, CEE_SUB);
3797 mono_mb_emit_stloc (mb, realidx);
3798 /* if (realidx >= bounds [i].length) goto exeception; */
3799 mono_mb_emit_ldloc (mb, realidx);
3800 mono_mb_emit_ldloc (mb, bounds);
3801 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
3802 mono_mb_emit_byte (mb, CEE_ADD);
3803 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3804 branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
3805 /* ind = ind * bounds [i].length + realidx */
3806 mono_mb_emit_ldloc (mb, ind);
3807 mono_mb_emit_ldloc (mb, bounds);
3808 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
3809 mono_mb_emit_byte (mb, CEE_ADD);
3810 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3811 mono_mb_emit_byte (mb, CEE_MUL);
3812 mono_mb_emit_ldloc (mb, realidx);
3813 mono_mb_emit_byte (mb, CEE_ADD);
3814 mono_mb_emit_stloc (mb, ind);
3817 /* return array->vector + ind * element_size */
3818 mono_mb_emit_ldarg (mb, 0);
3819 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
3820 mono_mb_emit_ldloc (mb, ind);
3821 if (elem_size) {
3822 mono_mb_emit_icon (mb, elem_size);
3823 } else {
3824 /* Load arr->vtable->klass->sizes.element_class */
3825 mono_mb_emit_ldarg (mb, 0);
3826 mono_mb_emit_byte (mb, CEE_CONV_I);
3827 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
3828 mono_mb_emit_byte (mb, CEE_ADD);
3829 mono_mb_emit_byte (mb, CEE_LDIND_I);
3830 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
3831 mono_mb_emit_byte (mb, CEE_ADD);
3832 mono_mb_emit_byte (mb, CEE_LDIND_I);
3833 /* sizes is an union, so this reads sizes.element_size */
3834 mono_mb_emit_icon (mb, m_class_offsetof_sizes ());
3835 mono_mb_emit_byte (mb, CEE_ADD);
3836 mono_mb_emit_byte (mb, CEE_LDIND_I4);
3838 mono_mb_emit_byte (mb, CEE_MUL);
3839 mono_mb_emit_byte (mb, CEE_ADD);
3840 mono_mb_emit_byte (mb, CEE_RET);
3842 /* patch the branches to get here and throw */
3843 for (i = 1; i < rank; ++i) {
3844 mono_mb_patch_branch (mb, branch_positions [i]);
3846 mono_mb_patch_branch (mb, branch_pos);
3847 /* throw exception */
3848 mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
3850 g_free (branch_positions);
3853 static void
3854 emit_delegate_begin_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig)
3856 int params_var;
3857 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
3859 mono_mb_emit_ldarg (mb, 0);
3860 mono_mb_emit_ldloc (mb, params_var);
3861 mono_mb_emit_icall (mb, mono_delegate_begin_invoke);
3862 mono_mb_emit_byte (mb, CEE_RET);
3865 static void
3866 emit_delegate_end_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig)
3868 int params_var;
3869 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
3871 mono_mb_emit_ldarg (mb, 0);
3872 mono_mb_emit_ldloc (mb, params_var);
3873 mono_mb_emit_icall (mb, mono_delegate_end_invoke);
3875 if (sig->ret->type == MONO_TYPE_VOID) {
3876 mono_mb_emit_byte (mb, CEE_POP);
3877 mono_mb_emit_byte (mb, CEE_RET);
3878 } else
3879 mono_mb_emit_restore_result (mb, sig->ret);
3882 static void
3883 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)
3885 int local_i, local_len, local_delegates, local_d, local_target, local_res;
3886 int pos0, pos1, pos2;
3887 int i;
3888 gboolean void_ret;
3890 MonoType *int32_type = mono_get_int32_type ();
3891 MonoType *object_type = mono_get_object_type ();
3893 void_ret = sig->ret->type == MONO_TYPE_VOID && !method->string_ctor;
3895 /* allocate local 0 (object) */
3896 local_i = mono_mb_add_local (mb, int32_type);
3897 local_len = mono_mb_add_local (mb, int32_type);
3898 local_delegates = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.array_class));
3899 local_d = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.multicastdelegate_class));
3900 local_target = mono_mb_add_local (mb, object_type);
3902 if (!void_ret)
3903 local_res = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret)));
3905 g_assert (sig->hasthis);
3908 * {type: sig->ret} res;
3909 * if (delegates == null) {
3910 * return this.<target> ( args .. );
3911 * } else {
3912 * int i = 0, len = this.delegates.Length;
3913 * do {
3914 * res = this.delegates [i].Invoke ( args .. );
3915 * } while (++i < len);
3916 * return res;
3920 /* this wrapper can be used in unmanaged-managed transitions */
3921 emit_thread_interrupt_checkpoint (mb);
3923 /* delegates = this.delegates */
3924 mono_mb_emit_ldarg (mb, 0);
3925 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoMulticastDelegate, delegates));
3926 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3927 mono_mb_emit_stloc (mb, local_delegates);
3929 /* if (delegates == null) */
3930 mono_mb_emit_ldloc (mb, local_delegates);
3931 pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
3933 /* return target.<target_method|method_ptr> ( args .. ); */
3935 /* target = d.target; */
3936 mono_mb_emit_ldarg (mb, 0);
3937 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, target));
3938 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3939 mono_mb_emit_stloc (mb, local_target);
3941 /*static methods with bound first arg can have null target and still be bound*/
3942 if (!static_method_with_first_arg_bound) {
3943 /* if target != null */
3944 mono_mb_emit_ldloc (mb, local_target);
3945 pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3947 /* then call this->method_ptr nonstatic */
3948 if (callvirt) {
3949 // FIXME:
3950 mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
3951 } else {
3952 mono_mb_emit_ldloc (mb, local_target);
3953 for (i = 0; i < sig->param_count; ++i)
3954 mono_mb_emit_ldarg (mb, i + 1);
3955 mono_mb_emit_ldarg (mb, 0);
3956 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
3957 mono_mb_emit_byte (mb, CEE_LDIND_I);
3958 mono_mb_emit_ldarg (mb, 0);
3959 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3960 mono_mb_emit_byte (mb, CEE_MONO_LD_DELEGATE_METHOD_PTR);
3961 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3962 mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig);
3963 mono_mb_emit_byte (mb, CEE_RET);
3966 /* else [target == null] call this->method_ptr static */
3967 mono_mb_patch_branch (mb, pos0);
3970 if (callvirt) {
3971 if (!closed_over_null) {
3972 /* if target_method is not really virtual, turn it into a direct call */
3973 if (!(target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) || m_class_is_valuetype (target_class)) {
3974 mono_mb_emit_ldarg (mb, 1);
3975 for (i = 1; i < sig->param_count; ++i)
3976 mono_mb_emit_ldarg (mb, i + 1);
3977 mono_mb_emit_op (mb, CEE_CALL, target_method);
3978 } else {
3979 mono_mb_emit_ldarg (mb, 1);
3980 mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
3981 for (i = 1; i < sig->param_count; ++i)
3982 mono_mb_emit_ldarg (mb, i + 1);
3983 mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
3985 } else {
3986 mono_mb_emit_byte (mb, CEE_LDNULL);
3987 for (i = 0; i < sig->param_count; ++i)
3988 mono_mb_emit_ldarg (mb, i + 1);
3989 mono_mb_emit_op (mb, CEE_CALL, target_method);
3991 } else {
3992 if (static_method_with_first_arg_bound) {
3993 mono_mb_emit_ldloc (mb, local_target);
3994 if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
3995 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type_internal (invoke_sig->params[0]));
3997 for (i = 0; i < sig->param_count; ++i)
3998 mono_mb_emit_ldarg (mb, i + 1);
3999 mono_mb_emit_ldarg (mb, 0);
4000 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
4001 mono_mb_emit_byte (mb, CEE_LDIND_I);
4002 mono_mb_emit_ldarg (mb, 0);
4003 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4004 mono_mb_emit_byte (mb, CEE_MONO_LD_DELEGATE_METHOD_PTR);
4005 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4006 mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig);
4009 mono_mb_emit_byte (mb, CEE_RET);
4011 /* else [delegates != null] */
4012 mono_mb_patch_branch (mb, pos2);
4014 /* len = delegates.Length; */
4015 mono_mb_emit_ldloc (mb, local_delegates);
4016 mono_mb_emit_byte (mb, CEE_LDLEN);
4017 mono_mb_emit_byte (mb, CEE_CONV_I4);
4018 mono_mb_emit_stloc (mb, local_len);
4020 /* i = 0; */
4021 mono_mb_emit_icon (mb, 0);
4022 mono_mb_emit_stloc (mb, local_i);
4024 pos1 = mono_mb_get_label (mb);
4026 /* d = delegates [i]; */
4027 mono_mb_emit_ldloc (mb, local_delegates);
4028 mono_mb_emit_ldloc (mb, local_i);
4029 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
4030 mono_mb_emit_stloc (mb, local_d);
4032 /* res = d.Invoke ( args .. ); */
4033 mono_mb_emit_ldloc (mb, local_d);
4034 for (i = 0; i < sig->param_count; i++)
4035 mono_mb_emit_ldarg (mb, i + 1);
4036 if (!ctx) {
4037 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
4038 } else {
4039 ERROR_DECL (error);
4040 mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method_checked (method, &container->context, error));
4041 g_assert (is_ok (error)); /* FIXME don't swallow the error */
4043 if (!void_ret)
4044 mono_mb_emit_stloc (mb, local_res);
4046 /* i += 1 */
4047 mono_mb_emit_add_to_local (mb, local_i, 1);
4049 /* i < l */
4050 mono_mb_emit_ldloc (mb, local_i);
4051 mono_mb_emit_ldloc (mb, local_len);
4052 mono_mb_emit_branch_label (mb, CEE_BLT, pos1);
4054 /* return res */
4055 if (!void_ret)
4056 mono_mb_emit_ldloc (mb, local_res);
4057 mono_mb_emit_byte (mb, CEE_RET);
4060 static void
4061 mb_skip_visibility_ilgen (MonoMethodBuilder *mb)
4063 mb->skip_visibility = 1;
4066 static void
4067 mb_set_dynamic_ilgen (MonoMethodBuilder *mb)
4069 mb->dynamic = 1;
4072 static void
4073 emit_synchronized_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoGenericContext *ctx, MonoGenericContainer *container, MonoMethod *enter_method, MonoMethod *exit_method, MonoMethod *gettypefromhandle_method)
4075 int i, pos, pos2, this_local, taken_local, ret_local = 0;
4076 MonoMethodSignature *sig = mono_method_signature_internal (method);
4077 MonoExceptionClause *clause;
4079 /* result */
4080 if (!MONO_TYPE_IS_VOID (sig->ret))
4081 ret_local = mono_mb_add_local (mb, sig->ret);
4083 if (m_class_is_valuetype (method->klass) && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
4084 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
4085 mono_class_set_type_load_failure (method->klass, "");
4086 /* This will throw the type load exception when the wrapper is compiled */
4087 mono_mb_emit_byte (mb, CEE_LDNULL);
4088 mono_mb_emit_op (mb, CEE_ISINST, method->klass);
4089 mono_mb_emit_byte (mb, CEE_POP);
4091 if (!MONO_TYPE_IS_VOID (sig->ret))
4092 mono_mb_emit_ldloc (mb, ret_local);
4093 mono_mb_emit_byte (mb, CEE_RET);
4095 return;
4098 MonoType *object_type = mono_get_object_type ();
4099 MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
4100 /* this */
4101 this_local = mono_mb_add_local (mb, object_type);
4102 taken_local = mono_mb_add_local (mb, boolean_type);
4104 clause = (MonoExceptionClause *)mono_image_alloc0 (get_method_image (method), sizeof (MonoExceptionClause));
4105 clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
4107 /* Push this or the type object */
4108 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
4109 /* We have special handling for this in the JIT */
4110 int index = mono_mb_add_data (mb, method->klass);
4111 mono_mb_add_data (mb, mono_defaults.typehandle_class);
4112 mono_mb_emit_byte (mb, CEE_LDTOKEN);
4113 mono_mb_emit_i4 (mb, index);
4115 mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL);
4117 else
4118 mono_mb_emit_ldarg (mb, 0);
4119 mono_mb_emit_stloc (mb, this_local);
4121 clause->try_offset = mono_mb_get_label (mb);
4122 /* Call Monitor::Enter() */
4123 mono_mb_emit_ldloc (mb, this_local);
4124 mono_mb_emit_ldloc_addr (mb, taken_local);
4125 mono_mb_emit_managed_call (mb, enter_method, NULL);
4127 /* Call the method */
4128 if (sig->hasthis)
4129 mono_mb_emit_ldarg (mb, 0);
4130 for (i = 0; i < sig->param_count; i++)
4131 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
4133 if (ctx) {
4134 ERROR_DECL (error);
4135 mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, error), NULL);
4136 g_assert (is_ok (error)); /* FIXME don't swallow the error */
4137 } else {
4138 mono_mb_emit_managed_call (mb, method, NULL);
4141 if (!MONO_TYPE_IS_VOID (sig->ret))
4142 mono_mb_emit_stloc (mb, ret_local);
4144 pos = mono_mb_emit_branch (mb, CEE_LEAVE);
4146 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
4147 clause->handler_offset = mono_mb_get_label (mb);
4149 /* Call Monitor::Exit() if needed */
4150 mono_mb_emit_ldloc (mb, taken_local);
4151 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4152 mono_mb_emit_ldloc (mb, this_local);
4153 mono_mb_emit_managed_call (mb, exit_method, NULL);
4154 mono_mb_patch_branch (mb, pos2);
4155 mono_mb_emit_byte (mb, CEE_ENDFINALLY);
4157 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
4159 mono_mb_patch_branch (mb, pos);
4160 if (!MONO_TYPE_IS_VOID (sig->ret))
4161 mono_mb_emit_ldloc (mb, ret_local);
4162 mono_mb_emit_byte (mb, CEE_RET);
4164 mono_mb_set_clauses (mb, 1, clause);
4167 static void
4168 emit_unbox_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method)
4170 MonoMethodSignature *sig = mono_method_signature_internal (method);
4172 mono_mb_emit_ldarg (mb, 0);
4173 mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject));
4174 mono_mb_emit_byte (mb, CEE_ADD);
4175 for (int i = 0; i < sig->param_count; ++i)
4176 mono_mb_emit_ldarg (mb, i + 1);
4177 mono_mb_emit_managed_call (mb, method, NULL);
4178 mono_mb_emit_byte (mb, CEE_RET);
4181 static void
4182 emit_array_accessor_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *sig, MonoGenericContext *ctx)
4184 MonoGenericContainer *container = NULL;
4185 /* Call the method */
4186 if (sig->hasthis)
4187 mono_mb_emit_ldarg (mb, 0);
4188 for (int i = 0; i < sig->param_count; i++)
4189 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
4191 if (ctx) {
4192 ERROR_DECL (error);
4193 mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, error), NULL);
4194 g_assert (is_ok (error)); /* FIXME don't swallow the error */
4195 } else {
4196 mono_mb_emit_managed_call (mb, method, NULL);
4198 mono_mb_emit_byte (mb, CEE_RET);
4201 static void
4202 emit_generic_array_helper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig)
4204 mono_mb_emit_ldarg (mb, 0);
4205 for (int i = 0; i < csig->param_count; i++)
4206 mono_mb_emit_ldarg (mb, i + 1);
4207 mono_mb_emit_managed_call (mb, method, NULL);
4208 mono_mb_emit_byte (mb, CEE_RET);
4211 static void
4212 emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig)
4214 MonoImage *image = get_method_image (method);
4215 MonoMethodSignature *sig = mono_method_signature_internal (method);
4216 int param_count = sig->param_count + sig->hasthis + 1;
4217 int pos_leave, coop_gc_var = 0, coop_gc_stack_dummy = 0;
4218 MonoExceptionClause *clause;
4219 MonoType *object_type = mono_get_object_type ();
4220 #if defined (TARGET_WASM)
4221 const gboolean do_blocking_transition = FALSE;
4222 #else
4223 const gboolean do_blocking_transition = TRUE;
4224 #endif
4226 /* local 0 (temp for exception object) */
4227 mono_mb_add_local (mb, object_type);
4229 /* local 1 (temp for result) */
4230 if (!MONO_TYPE_IS_VOID (sig->ret))
4231 mono_mb_add_local (mb, sig->ret);
4233 if (do_blocking_transition) {
4234 /* local 4, dummy local used to get a stack address for suspend funcs */
4235 coop_gc_stack_dummy = mono_mb_add_local (mb, mono_get_int_type ());
4236 /* local 5, the local to be used when calling the suspend funcs */
4237 coop_gc_var = mono_mb_add_local (mb, mono_get_int_type ());
4240 /* clear exception arg */
4241 mono_mb_emit_ldarg (mb, param_count - 1);
4242 mono_mb_emit_byte (mb, CEE_LDNULL);
4243 mono_mb_emit_byte (mb, CEE_STIND_REF);
4245 if (do_blocking_transition) {
4246 mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
4247 mono_mb_emit_icall (mb, mono_threads_enter_gc_unsafe_region_unbalanced);
4248 mono_mb_emit_stloc (mb, coop_gc_var);
4251 /* try */
4252 clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
4253 clause->try_offset = mono_mb_get_label (mb);
4255 /* push method's args */
4256 for (int i = 0; i < param_count - 1; i++) {
4257 MonoType *type;
4258 MonoClass *klass;
4260 mono_mb_emit_ldarg (mb, i);
4262 /* get the byval type of the param */
4263 klass = mono_class_from_mono_type_internal (csig->params [i]);
4264 type = m_class_get_byval_arg (klass);
4266 /* unbox struct args */
4267 if (MONO_TYPE_ISSTRUCT (type)) {
4268 mono_mb_emit_op (mb, CEE_UNBOX, klass);
4270 /* byref args & and the "this" arg must remain a ptr.
4271 Otherwise make a copy of the value type */
4272 if (!(csig->params [i]->byref || (i == 0 && sig->hasthis)))
4273 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
4275 csig->params [i] = object_type;
4279 /* call */
4280 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
4281 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
4282 else
4283 mono_mb_emit_op (mb, CEE_CALL, method);
4285 /* save result at local 1 */
4286 if (!MONO_TYPE_IS_VOID (sig->ret))
4287 mono_mb_emit_stloc (mb, 1);
4289 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
4291 /* catch */
4292 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
4293 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
4294 clause->data.catch_class = mono_defaults.object_class;
4296 clause->handler_offset = mono_mb_get_label (mb);
4298 /* store exception at local 0 */
4299 mono_mb_emit_stloc (mb, 0);
4300 mono_mb_emit_ldarg (mb, param_count - 1);
4301 mono_mb_emit_ldloc (mb, 0);
4302 mono_mb_emit_byte (mb, CEE_STIND_REF);
4303 mono_mb_emit_branch (mb, CEE_LEAVE);
4305 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
4307 mono_mb_set_clauses (mb, 1, clause);
4309 mono_mb_patch_branch (mb, pos_leave);
4310 /* end-try */
4312 if (!MONO_TYPE_IS_VOID (sig->ret)) {
4313 mono_mb_emit_ldloc (mb, 1);
4315 /* box the return value */
4316 if (MONO_TYPE_ISSTRUCT (sig->ret))
4317 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (sig->ret));
4320 if (do_blocking_transition) {
4321 mono_mb_emit_ldloc (mb, coop_gc_var);
4322 mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
4323 mono_mb_emit_icall (mb, mono_threads_exit_gc_unsafe_region_unbalanced);
4326 mono_mb_emit_byte (mb, CEE_RET);
4329 static void
4330 emit_marshal_custom_get_instance (MonoMethodBuilder *mb, MonoClass *klass, MonoMarshalSpec *spec)
4332 static MonoClass *Marshal = NULL;
4333 static MonoMethod *get_instance;
4335 if (!Marshal) {
4336 Marshal = mono_class_try_get_marshal_class ();
4337 g_assert (Marshal);
4339 get_instance = get_method_nofail (Marshal, "GetCustomMarshalerInstance", 2, 0);
4340 g_assert (get_instance);
4343 // HACK: We cannot use ldtoken in this type of wrapper.
4344 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4345 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
4346 mono_mb_emit_icall (mb, mono_marshal_get_type_object);
4347 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4349 mono_mb_emit_op (mb, CEE_CALL, get_instance);
4352 static int
4353 emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
4354 MonoMarshalSpec *spec,
4355 int conv_arg, MonoType **conv_arg_type,
4356 MarshalAction action)
4358 ERROR_DECL (error);
4359 MonoType *mtype;
4360 MonoClass *mklass;
4361 static MonoClass *ICustomMarshaler = NULL;
4362 static MonoMethod *cleanup_native, *cleanup_managed;
4363 static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
4364 MonoMethodBuilder *mb = m->mb;
4365 guint32 loc1;
4366 int pos2;
4368 MonoType *int_type = mono_get_int_type ();
4369 MonoType *object_type = mono_get_object_type ();
4371 if (!ICustomMarshaler) {
4372 MonoClass *klass = mono_class_try_get_icustom_marshaler_class ();
4373 if (!klass) {
4374 char *exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
4375 /* Throw exception and emit compensation code if neccesary */
4376 switch (action) {
4377 case MARSHAL_ACTION_CONV_IN:
4378 case MARSHAL_ACTION_CONV_RESULT:
4379 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4380 if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT))
4381 mono_mb_emit_byte (mb, CEE_POP);
4383 mono_mb_emit_exception_full (mb, "System", "ApplicationException", exception_msg);
4385 break;
4386 case MARSHAL_ACTION_PUSH:
4387 mono_mb_emit_byte (mb, CEE_LDNULL);
4388 break;
4389 default:
4390 break;
4392 return 0;
4395 cleanup_native = get_method_nofail (klass, "CleanUpNativeData", 1, 0);
4396 g_assert (cleanup_native);
4397 cleanup_managed = get_method_nofail (klass, "CleanUpManagedData", 1, 0);
4398 g_assert (cleanup_managed);
4399 marshal_managed_to_native = get_method_nofail (klass, "MarshalManagedToNative", 1, 0);
4400 g_assert (marshal_managed_to_native);
4401 marshal_native_to_managed = get_method_nofail (klass, "MarshalNativeToManaged", 1, 0);
4402 g_assert (marshal_native_to_managed);
4404 mono_memory_barrier ();
4405 ICustomMarshaler = klass;
4408 if (spec->data.custom_data.image)
4409 mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, error);
4410 else
4411 mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, error);
4412 g_assert (mtype != NULL);
4413 mono_error_assert_ok (error);
4414 mklass = mono_class_from_mono_type_internal (mtype);
4415 g_assert (mklass != NULL);
4417 switch (action) {
4418 case MARSHAL_ACTION_CONV_IN:
4419 switch (t->type) {
4420 case MONO_TYPE_CLASS:
4421 case MONO_TYPE_OBJECT:
4422 case MONO_TYPE_STRING:
4423 case MONO_TYPE_ARRAY:
4424 case MONO_TYPE_SZARRAY:
4425 case MONO_TYPE_VALUETYPE:
4426 break;
4428 default:
4429 g_warning ("custom marshalling of type %x is currently not supported", t->type);
4430 g_assert_not_reached ();
4431 break;
4434 conv_arg = mono_mb_add_local (mb, int_type);
4436 mono_mb_emit_byte (mb, CEE_LDNULL);
4437 mono_mb_emit_stloc (mb, conv_arg);
4439 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
4440 break;
4442 /* Minic MS.NET behavior */
4443 if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
4444 break;
4446 /* Check for null */
4447 mono_mb_emit_ldarg (mb, argnum);
4448 if (t->byref)
4449 mono_mb_emit_byte (mb, CEE_LDIND_I);
4450 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4452 emit_marshal_custom_get_instance (mb, mklass, spec);
4454 mono_mb_emit_ldarg (mb, argnum);
4455 if (t->byref)
4456 mono_mb_emit_byte (mb, CEE_LDIND_REF);
4458 if (t->type == MONO_TYPE_VALUETYPE) {
4460 * Since we can't determine the type of the argument, we
4461 * will assume the unmanaged function takes a pointer.
4463 *conv_arg_type = int_type;
4465 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t));
4468 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
4469 mono_mb_emit_stloc (mb, conv_arg);
4471 mono_mb_patch_branch (mb, pos2);
4472 break;
4474 case MARSHAL_ACTION_CONV_OUT:
4475 /* Check for null */
4476 mono_mb_emit_ldloc (mb, conv_arg);
4477 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4479 if (t->byref) {
4480 mono_mb_emit_ldarg (mb, argnum);
4482 emit_marshal_custom_get_instance (mb, mklass, spec);
4484 mono_mb_emit_ldloc (mb, conv_arg);
4485 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4486 mono_mb_emit_byte (mb, CEE_STIND_REF);
4487 } else if (t->attrs & PARAM_ATTRIBUTE_OUT) {
4488 emit_marshal_custom_get_instance (mb, mklass, spec);
4490 mono_mb_emit_ldloc (mb, conv_arg);
4491 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4493 /* We have nowhere to store the result */
4494 mono_mb_emit_byte (mb, CEE_POP);
4497 emit_marshal_custom_get_instance (mb, mklass, spec);
4499 mono_mb_emit_ldloc (mb, conv_arg);
4501 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
4503 mono_mb_patch_branch (mb, pos2);
4504 break;
4506 case MARSHAL_ACTION_PUSH:
4507 if (t->byref)
4508 mono_mb_emit_ldloc_addr (mb, conv_arg);
4509 else
4510 mono_mb_emit_ldloc (mb, conv_arg);
4511 break;
4513 case MARSHAL_ACTION_CONV_RESULT:
4514 loc1 = mono_mb_add_local (mb, int_type);
4516 mono_mb_emit_stloc (mb, 3);
4518 mono_mb_emit_ldloc (mb, 3);
4519 mono_mb_emit_stloc (mb, loc1);
4521 /* Check for null */
4522 mono_mb_emit_ldloc (mb, 3);
4523 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4525 emit_marshal_custom_get_instance (mb, mklass, spec);
4526 mono_mb_emit_byte (mb, CEE_DUP);
4528 mono_mb_emit_ldloc (mb, 3);
4529 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4530 mono_mb_emit_stloc (mb, 3);
4532 mono_mb_emit_ldloc (mb, loc1);
4533 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
4535 mono_mb_patch_branch (mb, pos2);
4536 break;
4538 case MARSHAL_ACTION_MANAGED_CONV_IN:
4539 conv_arg = mono_mb_add_local (mb, object_type);
4541 mono_mb_emit_byte (mb, CEE_LDNULL);
4542 mono_mb_emit_stloc (mb, conv_arg);
4544 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
4545 break;
4547 /* Check for null */
4548 mono_mb_emit_ldarg (mb, argnum);
4549 if (t->byref)
4550 mono_mb_emit_byte (mb, CEE_LDIND_I);
4551 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4553 emit_marshal_custom_get_instance (mb, mklass, spec);
4555 mono_mb_emit_ldarg (mb, argnum);
4556 if (t->byref)
4557 mono_mb_emit_byte (mb, CEE_LDIND_I);
4559 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4560 mono_mb_emit_stloc (mb, conv_arg);
4562 mono_mb_patch_branch (mb, pos2);
4563 break;
4565 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4566 g_assert (!t->byref);
4568 loc1 = mono_mb_add_local (mb, object_type);
4570 mono_mb_emit_stloc (mb, 3);
4572 mono_mb_emit_ldloc (mb, 3);
4573 mono_mb_emit_stloc (mb, loc1);
4575 /* Check for null */
4576 mono_mb_emit_ldloc (mb, 3);
4577 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4579 emit_marshal_custom_get_instance (mb, mklass, spec);
4580 mono_mb_emit_byte (mb, CEE_DUP);
4582 mono_mb_emit_ldloc (mb, 3);
4583 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
4584 mono_mb_emit_stloc (mb, 3);
4586 mono_mb_emit_ldloc (mb, loc1);
4587 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
4589 mono_mb_patch_branch (mb, pos2);
4590 break;
4592 case MARSHAL_ACTION_MANAGED_CONV_OUT:
4594 /* Check for null */
4595 mono_mb_emit_ldloc (mb, conv_arg);
4596 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4598 if (t->byref) {
4599 mono_mb_emit_ldarg (mb, argnum);
4601 emit_marshal_custom_get_instance (mb, mklass, spec);
4603 mono_mb_emit_ldloc (mb, conv_arg);
4604 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
4605 mono_mb_emit_byte (mb, CEE_STIND_I);
4608 /* Call CleanUpManagedData */
4609 emit_marshal_custom_get_instance (mb, mklass, spec);
4611 mono_mb_emit_ldloc (mb, conv_arg);
4612 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
4614 mono_mb_patch_branch (mb, pos2);
4615 break;
4617 default:
4618 g_assert_not_reached ();
4620 return conv_arg;
4623 static int
4624 emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
4625 MonoMarshalSpec *spec,
4626 int conv_arg, MonoType **conv_arg_type,
4627 MarshalAction action)
4629 MonoMethodBuilder *mb = m->mb;
4631 MonoType *int_type = mono_get_int_type ();
4632 switch (action) {
4633 case MARSHAL_ACTION_CONV_IN: {
4634 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
4636 g_assert (t->type == MONO_TYPE_OBJECT);
4637 g_assert (!t->byref);
4639 conv_arg = mono_mb_add_local (mb, int_type);
4640 mono_mb_emit_ldarg (mb, argnum);
4641 mono_mb_emit_icon (mb, encoding);
4642 mono_mb_emit_icon (mb, t->attrs);
4643 mono_mb_emit_icall (mb, mono_marshal_asany);
4644 mono_mb_emit_stloc (mb, conv_arg);
4645 break;
4648 case MARSHAL_ACTION_PUSH:
4649 mono_mb_emit_ldloc (mb, conv_arg);
4650 break;
4652 case MARSHAL_ACTION_CONV_OUT: {
4653 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
4655 mono_mb_emit_ldarg (mb, argnum);
4656 mono_mb_emit_ldloc (mb, conv_arg);
4657 mono_mb_emit_icon (mb, encoding);
4658 mono_mb_emit_icon (mb, t->attrs);
4659 mono_mb_emit_icall (mb, mono_marshal_free_asany);
4660 break;
4663 default:
4664 g_assert_not_reached ();
4666 return conv_arg;
4669 static int
4670 emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
4671 MonoMarshalSpec *spec,
4672 int conv_arg, MonoType **conv_arg_type,
4673 MarshalAction action)
4675 MonoMethodBuilder *mb = m->mb;
4676 MonoClass *klass, *date_time_class;
4677 int pos = 0, pos2;
4679 klass = mono_class_from_mono_type_internal (t);
4681 date_time_class = mono_class_get_date_time_class ();
4683 MonoType *int_type = mono_get_int_type ();
4684 MonoType *double_type = m_class_get_byval_arg (mono_defaults.double_class);
4686 switch (action) {
4687 case MARSHAL_ACTION_CONV_IN:
4688 if (klass == date_time_class) {
4689 /* Convert it to an OLE DATE type */
4690 static MonoMethod *to_oadate;
4692 if (!to_oadate)
4693 to_oadate = get_method_nofail (date_time_class, "ToOADate", 0, 0);
4694 g_assert (to_oadate);
4696 conv_arg = mono_mb_add_local (mb, double_type);
4698 if (t->byref) {
4699 mono_mb_emit_ldarg (mb, argnum);
4700 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
4703 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
4704 if (!t->byref)
4705 m->csig->params [argnum - m->csig->hasthis] = double_type;
4707 mono_mb_emit_ldarg_addr (mb, argnum);
4708 mono_mb_emit_managed_call (mb, to_oadate, NULL);
4709 mono_mb_emit_stloc (mb, conv_arg);
4712 if (t->byref)
4713 mono_mb_patch_branch (mb, pos);
4714 break;
4717 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass))
4718 break;
4720 conv_arg = mono_mb_add_local (mb, int_type);
4722 /* store the address of the source into local variable 0 */
4723 if (t->byref)
4724 mono_mb_emit_ldarg (mb, argnum);
4725 else
4726 mono_mb_emit_ldarg_addr (mb, argnum);
4728 mono_mb_emit_stloc (mb, 0);
4730 /* allocate space for the native struct and
4731 * store the address into local variable 1 (dest) */
4732 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
4733 mono_mb_emit_byte (mb, CEE_PREFIX1);
4734 mono_mb_emit_byte (mb, CEE_LOCALLOC);
4735 mono_mb_emit_stloc (mb, conv_arg);
4737 if (t->byref) {
4738 mono_mb_emit_ldloc (mb, 0);
4739 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
4742 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
4743 /* set dst_ptr */
4744 mono_mb_emit_ldloc (mb, conv_arg);
4745 mono_mb_emit_stloc (mb, 1);
4747 /* emit valuetype conversion code */
4748 emit_struct_conv (mb, klass, FALSE);
4751 if (t->byref)
4752 mono_mb_patch_branch (mb, pos);
4753 break;
4755 case MARSHAL_ACTION_PUSH:
4756 if (spec && spec->native == MONO_NATIVE_LPSTRUCT) {
4757 /* FIXME: */
4758 g_assert (!t->byref);
4760 /* Have to change the signature since the vtype is passed byref */
4761 m->csig->params [argnum - m->csig->hasthis] = int_type;
4763 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass))
4764 mono_mb_emit_ldarg_addr (mb, argnum);
4765 else
4766 mono_mb_emit_ldloc (mb, conv_arg);
4767 break;
4770 if (klass == date_time_class) {
4771 if (t->byref)
4772 mono_mb_emit_ldloc_addr (mb, conv_arg);
4773 else
4774 mono_mb_emit_ldloc (mb, conv_arg);
4775 break;
4778 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) {
4779 mono_mb_emit_ldarg (mb, argnum);
4780 break;
4782 mono_mb_emit_ldloc (mb, conv_arg);
4783 if (!t->byref) {
4784 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4785 mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass);
4787 break;
4789 case MARSHAL_ACTION_CONV_OUT:
4790 if (klass == date_time_class) {
4791 /* Convert from an OLE DATE type */
4792 static MonoMethod *from_oadate;
4794 if (!t->byref)
4795 break;
4797 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
4798 if (!from_oadate)
4799 from_oadate = get_method_nofail (date_time_class, "FromOADate", 1, 0);
4800 g_assert (from_oadate);
4802 mono_mb_emit_ldarg (mb, argnum);
4803 mono_mb_emit_ldloc (mb, conv_arg);
4804 mono_mb_emit_managed_call (mb, from_oadate, NULL);
4805 mono_mb_emit_op (mb, CEE_STOBJ, date_time_class);
4807 break;
4810 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass))
4811 break;
4813 if (t->byref) {
4814 /* dst = argument */
4815 mono_mb_emit_ldarg (mb, argnum);
4816 mono_mb_emit_stloc (mb, 1);
4818 mono_mb_emit_ldloc (mb, 1);
4819 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
4821 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
4822 /* src = tmp_locals [i] */
4823 mono_mb_emit_ldloc (mb, conv_arg);
4824 mono_mb_emit_stloc (mb, 0);
4826 /* emit valuetype conversion code */
4827 emit_struct_conv (mb, klass, TRUE);
4831 emit_struct_free (mb, klass, conv_arg);
4833 if (t->byref)
4834 mono_mb_patch_branch (mb, pos);
4835 break;
4837 case MARSHAL_ACTION_CONV_RESULT:
4838 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass)) {
4839 mono_mb_emit_stloc (mb, 3);
4840 break;
4843 /* load pointer to returned value type */
4844 g_assert (m->vtaddr_var);
4845 mono_mb_emit_ldloc (mb, m->vtaddr_var);
4846 /* store the address of the source into local variable 0 */
4847 mono_mb_emit_stloc (mb, 0);
4848 /* set dst_ptr */
4849 mono_mb_emit_ldloc_addr (mb, 3);
4850 mono_mb_emit_stloc (mb, 1);
4852 /* emit valuetype conversion code */
4853 emit_struct_conv (mb, klass, TRUE);
4854 break;
4856 case MARSHAL_ACTION_MANAGED_CONV_IN:
4857 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) {
4858 conv_arg = 0;
4859 break;
4862 conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass));
4864 if (t->attrs & PARAM_ATTRIBUTE_OUT)
4865 break;
4867 if (t->byref)
4868 mono_mb_emit_ldarg (mb, argnum);
4869 else
4870 mono_mb_emit_ldarg_addr (mb, argnum);
4871 mono_mb_emit_stloc (mb, 0);
4873 if (t->byref) {
4874 mono_mb_emit_ldloc (mb, 0);
4875 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
4878 mono_mb_emit_ldloc_addr (mb, conv_arg);
4879 mono_mb_emit_stloc (mb, 1);
4881 /* emit valuetype conversion code */
4882 emit_struct_conv (mb, klass, TRUE);
4884 if (t->byref)
4885 mono_mb_patch_branch (mb, pos);
4886 break;
4888 case MARSHAL_ACTION_MANAGED_CONV_OUT:
4889 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass))
4890 break;
4891 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))
4892 break;
4894 /* Check for null */
4895 mono_mb_emit_ldarg (mb, argnum);
4896 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4898 /* Set src */
4899 mono_mb_emit_ldloc_addr (mb, conv_arg);
4900 mono_mb_emit_stloc (mb, 0);
4902 /* Set dest */
4903 mono_mb_emit_ldarg (mb, argnum);
4904 mono_mb_emit_stloc (mb, 1);
4906 /* emit valuetype conversion code */
4907 emit_struct_conv (mb, klass, FALSE);
4909 mono_mb_patch_branch (mb, pos2);
4910 break;
4912 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4913 if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) {
4914 mono_mb_emit_stloc (mb, 3);
4915 m->retobj_var = 0;
4916 break;
4919 /* load pointer to returned value type */
4920 g_assert (m->vtaddr_var);
4921 mono_mb_emit_ldloc (mb, m->vtaddr_var);
4923 /* store the address of the source into local variable 0 */
4924 mono_mb_emit_stloc (mb, 0);
4925 /* allocate space for the native struct and
4926 * store the address into dst_ptr */
4927 m->retobj_var = mono_mb_add_local (mb, int_type);
4928 m->retobj_class = klass;
4929 g_assert (m->retobj_var);
4930 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
4931 mono_mb_emit_byte (mb, CEE_CONV_I);
4932 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
4933 mono_mb_emit_stloc (mb, 1);
4934 mono_mb_emit_ldloc (mb, 1);
4935 mono_mb_emit_stloc (mb, m->retobj_var);
4937 /* emit valuetype conversion code */
4938 emit_struct_conv (mb, klass, FALSE);
4939 break;
4941 default:
4942 g_assert_not_reached ();
4944 return conv_arg;
4947 static int
4948 emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
4949 MonoMarshalSpec *spec,
4950 int conv_arg, MonoType **conv_arg_type,
4951 MarshalAction action)
4953 MonoMethodBuilder *mb = m->mb;
4954 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
4955 MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
4956 gboolean need_free;
4958 MonoType *int_type = mono_get_int_type ();
4959 MonoType *object_type = mono_get_object_type ();
4960 switch (action) {
4961 case MARSHAL_ACTION_CONV_IN:
4962 *conv_arg_type = int_type;
4963 conv_arg = mono_mb_add_local (mb, int_type);
4965 if (t->byref) {
4966 if (t->attrs & PARAM_ATTRIBUTE_OUT)
4967 break;
4969 mono_mb_emit_ldarg (mb, argnum);
4970 mono_mb_emit_byte (mb, CEE_LDIND_I);
4971 } else {
4972 mono_mb_emit_ldarg (mb, argnum);
4975 if (conv == MONO_MARSHAL_CONV_INVALID) {
4976 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
4977 mono_mb_emit_exception_marshal_directive (mb, msg);
4978 } else {
4979 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
4981 mono_mb_emit_stloc (mb, conv_arg);
4983 break;
4985 case MARSHAL_ACTION_CONV_OUT:
4986 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
4987 if (conv == MONO_MARSHAL_CONV_INVALID) {
4988 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
4989 mono_mb_emit_exception_marshal_directive (mb, msg);
4990 break;
4993 if (encoding == MONO_NATIVE_VBBYREFSTR) {
4994 static MonoMethod *m;
4996 if (!m)
4997 m = get_method_nofail (mono_defaults.string_class, "get_Length", -1, 0);
4999 if (!t->byref) {
5000 char *msg = g_strdup ("VBByRefStr marshalling requires a ref parameter.");
5001 mono_mb_emit_exception_marshal_directive (mb, msg);
5002 break;
5006 * Have to allocate a new string with the same length as the original, and
5007 * copy the contents of the buffer pointed to by CONV_ARG into it.
5009 g_assert (t->byref);
5010 mono_mb_emit_ldarg (mb, argnum);
5011 mono_mb_emit_ldloc (mb, conv_arg);
5012 mono_mb_emit_ldarg (mb, argnum);
5013 mono_mb_emit_byte (mb, CEE_LDIND_I);
5014 mono_mb_emit_managed_call (mb, m, NULL);
5015 mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
5016 mono_mb_emit_byte (mb, CEE_STIND_REF);
5017 } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
5018 int stind_op;
5019 mono_mb_emit_ldarg (mb, argnum);
5020 mono_mb_emit_ldloc (mb, conv_arg);
5021 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
5022 mono_mb_emit_byte (mb, stind_op);
5023 need_free = TRUE;
5026 if (need_free) {
5027 mono_mb_emit_ldloc (mb, conv_arg);
5028 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
5029 mono_mb_emit_icall (mb, mono_free_bstr);
5030 else
5031 mono_mb_emit_icall (mb, mono_marshal_free);
5033 break;
5035 case MARSHAL_ACTION_PUSH:
5036 if (t->byref && encoding != MONO_NATIVE_VBBYREFSTR)
5037 mono_mb_emit_ldloc_addr (mb, conv_arg);
5038 else
5039 mono_mb_emit_ldloc (mb, conv_arg);
5040 break;
5042 case MARSHAL_ACTION_CONV_RESULT:
5043 mono_mb_emit_stloc (mb, 0);
5045 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
5046 if (conv == MONO_MARSHAL_CONV_INVALID) {
5047 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5048 mono_mb_emit_exception_marshal_directive (mb, msg);
5049 break;
5052 mono_mb_emit_ldloc (mb, 0);
5053 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
5054 mono_mb_emit_stloc (mb, 3);
5056 /* free the string */
5057 mono_mb_emit_ldloc (mb, 0);
5058 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
5059 mono_mb_emit_icall (mb, mono_free_bstr);
5060 else
5061 mono_mb_emit_icall (mb, mono_marshal_free);
5062 break;
5064 case MARSHAL_ACTION_MANAGED_CONV_IN:
5065 conv_arg = mono_mb_add_local (mb, object_type);
5067 *conv_arg_type = int_type;
5069 if (t->byref) {
5070 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5071 break;
5074 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
5075 if (conv == MONO_MARSHAL_CONV_INVALID) {
5076 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5077 mono_mb_emit_exception_marshal_directive (mb, msg);
5078 break;
5081 mono_mb_emit_ldarg (mb, argnum);
5082 if (t->byref)
5083 mono_mb_emit_byte (mb, CEE_LDIND_I);
5084 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
5085 mono_mb_emit_stloc (mb, conv_arg);
5086 break;
5088 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5089 if (t->byref) {
5090 if (conv_arg) {
5091 int stind_op;
5092 mono_mb_emit_ldarg (mb, argnum);
5093 mono_mb_emit_ldloc (mb, conv_arg);
5094 mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op));
5095 mono_mb_emit_byte (mb, stind_op);
5098 break;
5100 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5101 if (conv_to_icall (conv, NULL) == MONO_JIT_ICALL_mono_marshal_string_to_utf16)
5102 /* We need to make a copy so the caller is able to free it */
5103 mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
5104 else
5105 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
5106 mono_mb_emit_stloc (mb, 3);
5107 break;
5109 default:
5110 g_assert_not_reached ();
5112 return conv_arg;
5116 static int
5117 emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
5118 MonoMarshalSpec *spec, int conv_arg,
5119 MonoType **conv_arg_type, MarshalAction action)
5121 MonoMethodBuilder *mb = m->mb;
5122 MonoType *int_type = mono_get_int_type ();
5123 MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
5125 switch (action){
5126 case MARSHAL_ACTION_CONV_IN: {
5127 int dar_release_slot, pos;
5129 conv_arg = mono_mb_add_local (mb, int_type);
5130 *conv_arg_type = int_type;
5132 if (!sh_dangerous_add_ref)
5133 init_safe_handle ();
5135 mono_mb_emit_ldarg (mb, argnum);
5136 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
5137 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
5139 mono_mb_patch_branch (mb, pos);
5141 /* Create local to hold the ref parameter to DangerousAddRef */
5142 dar_release_slot = mono_mb_add_local (mb, boolean_type);
5144 /* set release = false; */
5145 mono_mb_emit_icon (mb, 0);
5146 mono_mb_emit_stloc (mb, dar_release_slot);
5148 if (t->byref) {
5149 int old_handle_value_slot = mono_mb_add_local (mb, int_type);
5151 if (!IS_IN (t)) {
5152 mono_mb_emit_icon (mb, 0);
5153 mono_mb_emit_stloc (mb, conv_arg);
5154 } else {
5155 /* safehandle.DangerousAddRef (ref release) */
5156 mono_mb_emit_ldarg (mb, argnum);
5157 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5158 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
5159 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
5161 /* Pull the handle field from SafeHandle */
5162 mono_mb_emit_ldarg (mb, argnum);
5163 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5164 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5165 mono_mb_emit_byte (mb, CEE_LDIND_I);
5166 mono_mb_emit_byte (mb, CEE_DUP);
5167 mono_mb_emit_stloc (mb, conv_arg);
5168 mono_mb_emit_stloc (mb, old_handle_value_slot);
5170 } else {
5171 /* safehandle.DangerousAddRef (ref release) */
5172 mono_mb_emit_ldarg (mb, argnum);
5173 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
5174 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
5176 /* Pull the handle field from SafeHandle */
5177 mono_mb_emit_ldarg (mb, argnum);
5178 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5179 mono_mb_emit_byte (mb, CEE_LDIND_I);
5180 mono_mb_emit_stloc (mb, conv_arg);
5183 break;
5186 case MARSHAL_ACTION_PUSH:
5187 if (t->byref)
5188 mono_mb_emit_ldloc_addr (mb, conv_arg);
5189 else
5190 mono_mb_emit_ldloc (mb, conv_arg);
5191 break;
5193 case MARSHAL_ACTION_CONV_OUT: {
5194 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5195 int dar_release_slot = conv_arg + 1;
5196 int label_next;
5198 if (!sh_dangerous_release)
5199 init_safe_handle ();
5201 if (t->byref){
5202 /* If there was SafeHandle on input we have to release the reference to it */
5203 if (IS_IN (t)) {
5204 mono_mb_emit_ldloc (mb, dar_release_slot);
5205 label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
5206 mono_mb_emit_ldarg (mb, argnum);
5207 mono_mb_emit_byte (mb, CEE_LDIND_I);
5208 mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
5209 mono_mb_patch_branch (mb, label_next);
5212 if (IS_OUT (t)) {
5213 ERROR_DECL (local_error);
5214 MonoMethod *ctor;
5217 * If the SafeHandle was marshalled on input we can skip the marshalling on
5218 * output if the handle value is identical.
5220 if (IS_IN (t)) {
5221 int old_handle_value_slot = dar_release_slot + 1;
5222 mono_mb_emit_ldloc (mb, old_handle_value_slot);
5223 mono_mb_emit_ldloc (mb, conv_arg);
5224 label_next = mono_mb_emit_branch (mb, CEE_BEQ);
5228 * Create an empty SafeHandle (of correct derived type).
5230 * FIXME: If an out-of-memory situation or exception happens here we will
5231 * leak the handle. We should move the allocation of the SafeHandle to the
5232 * input marshalling code to prevent that.
5234 ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, local_error);
5235 if (ctor == NULL || !is_ok (local_error)){
5236 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
5237 mono_error_cleanup (local_error);
5238 break;
5241 /* refval = new SafeHandleDerived ()*/
5242 mono_mb_emit_ldarg (mb, argnum);
5243 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
5244 mono_mb_emit_byte (mb, CEE_STIND_REF);
5246 /* refval.handle = returned_handle */
5247 mono_mb_emit_ldarg (mb, argnum);
5248 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5249 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5250 mono_mb_emit_ldloc (mb, conv_arg);
5251 mono_mb_emit_byte (mb, CEE_STIND_I);
5253 if (IS_IN (t)) {
5254 mono_mb_patch_branch (mb, label_next);
5257 } else {
5258 mono_mb_emit_ldloc (mb, dar_release_slot);
5259 label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
5260 mono_mb_emit_ldarg (mb, argnum);
5261 mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
5262 mono_mb_patch_branch (mb, label_next);
5264 break;
5267 case MARSHAL_ACTION_CONV_RESULT: {
5268 ERROR_DECL (error);
5269 MonoMethod *ctor = NULL;
5270 int intptr_handle_slot;
5272 if (mono_class_is_abstract (t->data.klass)) {
5273 mono_mb_emit_byte (mb, CEE_POP);
5274 mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
5275 break;
5278 ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, error);
5279 if (ctor == NULL || !is_ok (error)){
5280 mono_error_cleanup (error);
5281 mono_mb_emit_byte (mb, CEE_POP);
5282 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
5283 break;
5285 /* Store the IntPtr results into a local */
5286 intptr_handle_slot = mono_mb_add_local (mb, int_type);
5287 mono_mb_emit_stloc (mb, intptr_handle_slot);
5289 /* Create return value */
5290 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
5291 mono_mb_emit_stloc (mb, 3);
5293 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5294 mono_mb_emit_ldloc (mb, 3);
5295 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5296 mono_mb_emit_ldloc (mb, intptr_handle_slot);
5297 mono_mb_emit_byte (mb, CEE_STIND_I);
5298 break;
5301 case MARSHAL_ACTION_MANAGED_CONV_IN:
5302 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5303 break;
5305 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5306 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5307 break;
5309 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5310 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5311 break;
5312 default:
5313 printf ("Unhandled case for MarshalAction: %d\n", action);
5315 return conv_arg;
5319 static int
5320 emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
5321 MonoMarshalSpec *spec, int conv_arg,
5322 MonoType **conv_arg_type, MarshalAction action)
5324 MonoMethodBuilder *mb = m->mb;
5326 MonoType *int_type = mono_get_int_type ();
5327 switch (action){
5328 case MARSHAL_ACTION_CONV_IN: {
5329 conv_arg = mono_mb_add_local (mb, int_type);
5330 *conv_arg_type = int_type;
5332 if (t->byref){
5333 char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5334 mono_mb_emit_exception_marshal_directive (mb, msg);
5335 break;
5337 mono_mb_emit_ldarg_addr (mb, argnum);
5338 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle));
5339 mono_mb_emit_byte (mb, CEE_ADD);
5340 mono_mb_emit_byte (mb, CEE_LDIND_I);
5341 mono_mb_emit_stloc (mb, conv_arg);
5342 break;
5345 case MARSHAL_ACTION_PUSH:
5346 mono_mb_emit_ldloc (mb, conv_arg);
5347 break;
5349 case MARSHAL_ACTION_CONV_OUT: {
5350 /* no resource release required */
5351 break;
5354 case MARSHAL_ACTION_CONV_RESULT: {
5355 char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5356 mono_mb_emit_exception_marshal_directive (mb, msg);
5357 break;
5360 case MARSHAL_ACTION_MANAGED_CONV_IN:
5361 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5362 break;
5364 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5365 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5366 break;
5368 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5369 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5370 break;
5371 default:
5372 fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
5374 return conv_arg;
5378 static int
5379 emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
5380 MonoMarshalSpec *spec,
5381 int conv_arg, MonoType **conv_arg_type,
5382 MarshalAction action)
5384 MonoMethodBuilder *mb = m->mb;
5385 MonoClass *klass = mono_class_from_mono_type_internal (t);
5386 int pos, pos2, loc;
5388 MonoType *int_type = mono_get_int_type ();
5389 switch (action) {
5390 case MARSHAL_ACTION_CONV_IN:
5391 *conv_arg_type = int_type;
5392 conv_arg = mono_mb_add_local (mb, int_type);
5394 m->orig_conv_args [argnum] = 0;
5396 if (mono_class_from_mono_type_internal (t) == mono_defaults.object_class) {
5397 char *msg = g_strdup_printf ("Marshalling of type object is not implemented");
5398 mono_mb_emit_exception_marshal_directive (mb, msg);
5399 break;
5402 if (m_class_is_delegate (klass)) {
5403 if (t->byref) {
5404 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
5405 char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5406 mono_mb_emit_exception_marshal_directive (mb, msg);
5408 mono_mb_emit_byte (mb, CEE_LDNULL);
5409 mono_mb_emit_stloc (mb, conv_arg);
5410 } else {
5411 mono_mb_emit_ldarg (mb, argnum);
5412 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
5413 mono_mb_emit_stloc (mb, conv_arg);
5415 } else if (klass == mono_class_try_get_stringbuilder_class ()) {
5416 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5417 MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
5419 #if 0
5420 if (t->byref) {
5421 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
5422 char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5423 mono_mb_emit_exception_marshal_directive (mb, msg);
5425 break;
5427 #endif
5429 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
5430 break;
5432 if (conv == MONO_MARSHAL_CONV_INVALID) {
5433 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
5434 mono_mb_emit_exception_marshal_directive (mb, msg);
5435 break;
5438 mono_mb_emit_ldarg (mb, argnum);
5439 if (t->byref)
5440 mono_mb_emit_byte (mb, CEE_LDIND_I);
5442 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
5443 mono_mb_emit_stloc (mb, conv_arg);
5444 } else if (m_class_is_blittable (klass)) {
5445 mono_mb_emit_byte (mb, CEE_LDNULL);
5446 mono_mb_emit_stloc (mb, conv_arg);
5448 mono_mb_emit_ldarg (mb, argnum);
5449 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5451 mono_mb_emit_ldarg (mb, argnum);
5452 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5453 mono_mb_emit_stloc (mb, conv_arg);
5455 mono_mb_patch_branch (mb, pos);
5456 break;
5457 } else {
5458 mono_mb_emit_byte (mb, CEE_LDNULL);
5459 mono_mb_emit_stloc (mb, conv_arg);
5461 if (t->byref) {
5462 /* we dont need any conversions for out parameters */
5463 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5464 break;
5466 mono_mb_emit_ldarg (mb, argnum);
5467 mono_mb_emit_byte (mb, CEE_LDIND_I);
5469 } else {
5470 mono_mb_emit_ldarg (mb, argnum);
5471 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5472 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5475 /* store the address of the source into local variable 0 */
5476 mono_mb_emit_stloc (mb, 0);
5477 mono_mb_emit_ldloc (mb, 0);
5478 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5480 /* allocate space for the native struct and store the address */
5481 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5482 mono_mb_emit_byte (mb, CEE_PREFIX1);
5483 mono_mb_emit_byte (mb, CEE_LOCALLOC);
5484 mono_mb_emit_stloc (mb, conv_arg);
5486 if (t->byref) {
5487 /* Need to store the original buffer so we can free it later */
5488 m->orig_conv_args [argnum] = mono_mb_add_local (mb, int_type);
5489 mono_mb_emit_ldloc (mb, conv_arg);
5490 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
5493 /* set the src_ptr */
5494 mono_mb_emit_ldloc (mb, 0);
5495 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5496 mono_mb_emit_stloc (mb, 0);
5498 /* set dst_ptr */
5499 mono_mb_emit_ldloc (mb, conv_arg);
5500 mono_mb_emit_stloc (mb, 1);
5502 /* emit valuetype conversion code */
5503 emit_struct_conv (mb, klass, FALSE);
5505 mono_mb_patch_branch (mb, pos);
5507 break;
5509 case MARSHAL_ACTION_CONV_OUT:
5510 if (klass == mono_class_try_get_stringbuilder_class ()) {
5511 gboolean need_free;
5512 MonoMarshalNative encoding;
5513 MonoMarshalConv conv;
5515 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5516 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
5518 g_assert (encoding != -1);
5520 if (t->byref) {
5521 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5523 need_free = TRUE;
5525 mono_mb_emit_ldarg (mb, argnum);
5526 mono_mb_emit_ldloc (mb, conv_arg);
5528 switch (encoding) {
5529 case MONO_NATIVE_LPWSTR:
5530 mono_mb_emit_icall (mb, mono_string_utf16_to_builder2);
5531 break;
5532 case MONO_NATIVE_LPSTR:
5533 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
5534 break;
5535 case MONO_NATIVE_UTF8STR:
5536 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
5537 break;
5538 default:
5539 g_assert_not_reached ();
5542 mono_mb_emit_byte (mb, CEE_STIND_REF);
5543 } else if (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN)) {
5544 mono_mb_emit_ldarg (mb, argnum);
5545 mono_mb_emit_ldloc (mb, conv_arg);
5547 mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL));
5550 if (need_free) {
5551 mono_mb_emit_ldloc (mb, conv_arg);
5552 mono_mb_emit_icall (mb, mono_marshal_free);
5554 break;
5557 if (m_class_is_delegate (klass)) {
5558 if (t->byref) {
5559 mono_mb_emit_ldarg (mb, argnum);
5560 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5561 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
5562 mono_mb_emit_ldloc (mb, conv_arg);
5563 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
5564 mono_mb_emit_byte (mb, CEE_STIND_REF);
5566 break;
5569 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
5570 /* allocate a new object */
5571 mono_mb_emit_ldarg (mb, argnum);
5572 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5573 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
5574 mono_mb_emit_byte (mb, CEE_STIND_REF);
5577 /* dst = *argument */
5578 mono_mb_emit_ldarg (mb, argnum);
5580 if (t->byref)
5581 mono_mb_emit_byte (mb, CEE_LDIND_I);
5583 mono_mb_emit_stloc (mb, 1);
5585 mono_mb_emit_ldloc (mb, 1);
5586 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5588 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
5589 mono_mb_emit_ldloc (mb, 1);
5590 mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject));
5591 mono_mb_emit_byte (mb, CEE_ADD);
5592 mono_mb_emit_stloc (mb, 1);
5594 /* src = tmp_locals [i] */
5595 mono_mb_emit_ldloc (mb, conv_arg);
5596 mono_mb_emit_stloc (mb, 0);
5598 /* emit valuetype conversion code */
5599 emit_struct_conv (mb, klass, TRUE);
5601 /* Free the structure returned by the native code */
5602 emit_struct_free (mb, klass, conv_arg);
5604 if (m->orig_conv_args [argnum]) {
5606 * If the native function changed the pointer, then free
5607 * the original structure plus the new pointer.
5609 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
5610 mono_mb_emit_ldloc (mb, conv_arg);
5611 pos2 = mono_mb_emit_branch (mb, CEE_BEQ);
5613 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
5614 g_assert (m->orig_conv_args [argnum]);
5616 emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
5619 mono_mb_emit_ldloc (mb, conv_arg);
5620 mono_mb_emit_icall (mb, mono_marshal_free);
5622 mono_mb_patch_branch (mb, pos2);
5625 else
5626 /* Free the original structure passed to native code */
5627 emit_struct_free (mb, klass, conv_arg);
5629 mono_mb_patch_branch (mb, pos);
5630 break;
5632 case MARSHAL_ACTION_PUSH:
5633 if (t->byref)
5634 mono_mb_emit_ldloc_addr (mb, conv_arg);
5635 else
5636 mono_mb_emit_ldloc (mb, conv_arg);
5637 break;
5639 case MARSHAL_ACTION_CONV_RESULT:
5640 if (m_class_is_delegate (klass)) {
5641 g_assert (!t->byref);
5642 mono_mb_emit_stloc (mb, 0);
5643 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5644 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
5645 mono_mb_emit_ldloc (mb, 0);
5646 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
5647 mono_mb_emit_stloc (mb, 3);
5648 } else if (klass == mono_class_try_get_stringbuilder_class ()) {
5649 // FIXME:
5650 char *msg = g_strdup_printf ("Return marshalling of stringbuilders is not implemented.");
5651 mono_mb_emit_exception_marshal_directive (mb, msg);
5652 } else {
5653 /* set src */
5654 mono_mb_emit_stloc (mb, 0);
5656 /* Make a copy since emit_conv modifies local 0 */
5657 loc = mono_mb_add_local (mb, int_type);
5658 mono_mb_emit_ldloc (mb, 0);
5659 mono_mb_emit_stloc (mb, loc);
5661 mono_mb_emit_byte (mb, CEE_LDNULL);
5662 mono_mb_emit_stloc (mb, 3);
5664 mono_mb_emit_ldloc (mb, 0);
5665 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5667 /* allocate result object */
5669 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5670 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
5671 mono_mb_emit_stloc (mb, 3);
5673 /* set dst */
5675 mono_mb_emit_ldloc (mb, 3);
5676 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5677 mono_mb_emit_stloc (mb, 1);
5679 /* emit conversion code */
5680 emit_struct_conv (mb, klass, TRUE);
5682 emit_struct_free (mb, klass, loc);
5684 /* Free the pointer allocated by unmanaged code */
5685 mono_mb_emit_ldloc (mb, loc);
5686 mono_mb_emit_icall (mb, mono_marshal_free);
5687 mono_mb_patch_branch (mb, pos);
5689 break;
5691 case MARSHAL_ACTION_MANAGED_CONV_IN:
5692 conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass));
5694 if (m_class_is_delegate (klass)) {
5695 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5696 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
5697 mono_mb_emit_ldarg (mb, argnum);
5698 if (t->byref)
5699 mono_mb_emit_byte (mb, CEE_LDIND_I);
5700 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
5701 mono_mb_emit_stloc (mb, conv_arg);
5702 break;
5705 if (klass == mono_class_try_get_stringbuilder_class ()) {
5706 MonoMarshalNative encoding;
5708 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5710 // FIXME:
5711 g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR);
5713 g_assert (!t->byref);
5714 g_assert (encoding != -1);
5716 mono_mb_emit_ldarg (mb, argnum);
5717 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
5718 mono_mb_emit_stloc (mb, conv_arg);
5719 break;
5722 /* The class can not have an automatic layout */
5723 if (mono_class_is_auto_layout (klass)) {
5724 mono_mb_emit_auto_layout_exception (mb, klass);
5725 break;
5728 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
5729 mono_mb_emit_byte (mb, CEE_LDNULL);
5730 mono_mb_emit_stloc (mb, conv_arg);
5731 break;
5734 /* Set src */
5735 mono_mb_emit_ldarg (mb, argnum);
5736 if (t->byref) {
5737 int pos2;
5739 /* Check for NULL and raise an exception */
5740 pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
5742 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
5744 mono_mb_patch_branch (mb, pos2);
5745 mono_mb_emit_ldarg (mb, argnum);
5746 mono_mb_emit_byte (mb, CEE_LDIND_I);
5749 mono_mb_emit_stloc (mb, 0);
5751 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5752 mono_mb_emit_stloc (mb, conv_arg);
5754 mono_mb_emit_ldloc (mb, 0);
5755 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5757 /* Create and set dst */
5758 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5759 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
5760 mono_mb_emit_stloc (mb, conv_arg);
5761 mono_mb_emit_ldloc (mb, conv_arg);
5762 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5763 mono_mb_emit_stloc (mb, 1);
5765 /* emit valuetype conversion code */
5766 emit_struct_conv (mb, klass, TRUE);
5768 mono_mb_patch_branch (mb, pos);
5769 break;
5771 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5772 if (m_class_is_delegate (klass)) {
5773 if (t->byref) {
5774 int stind_op;
5775 mono_mb_emit_ldarg (mb, argnum);
5776 mono_mb_emit_ldloc (mb, conv_arg);
5777 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
5778 mono_mb_emit_byte (mb, stind_op);
5779 break;
5783 if (t->byref) {
5784 /* Check for null */
5785 mono_mb_emit_ldloc (mb, conv_arg);
5786 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
5787 mono_mb_emit_ldarg (mb, argnum);
5788 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
5789 mono_mb_emit_byte (mb, CEE_STIND_I);
5790 pos2 = mono_mb_emit_branch (mb, CEE_BR);
5792 mono_mb_patch_branch (mb, pos);
5794 /* Set src */
5795 mono_mb_emit_ldloc (mb, conv_arg);
5796 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5797 mono_mb_emit_stloc (mb, 0);
5799 /* Allocate and set dest */
5800 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5801 mono_mb_emit_byte (mb, CEE_CONV_I);
5802 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
5803 mono_mb_emit_stloc (mb, 1);
5805 /* Update argument pointer */
5806 mono_mb_emit_ldarg (mb, argnum);
5807 mono_mb_emit_ldloc (mb, 1);
5808 mono_mb_emit_byte (mb, CEE_STIND_I);
5810 /* emit valuetype conversion code */
5811 emit_struct_conv (mb, klass, FALSE);
5813 mono_mb_patch_branch (mb, pos2);
5814 } else if (klass == mono_class_try_get_stringbuilder_class ()) {
5815 // FIXME: What to do here ?
5816 } else {
5817 /* byval [Out] marshalling */
5819 /* FIXME: Handle null */
5821 /* Set src */
5822 mono_mb_emit_ldloc (mb, conv_arg);
5823 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5824 mono_mb_emit_stloc (mb, 0);
5826 /* Set dest */
5827 mono_mb_emit_ldarg (mb, argnum);
5828 mono_mb_emit_stloc (mb, 1);
5830 /* emit valuetype conversion code */
5831 emit_struct_conv (mb, klass, FALSE);
5833 break;
5835 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5836 if (m_class_is_delegate (klass)) {
5837 mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
5838 mono_mb_emit_stloc (mb, 3);
5839 break;
5842 /* The class can not have an automatic layout */
5843 if (mono_class_is_auto_layout (klass)) {
5844 mono_mb_emit_auto_layout_exception (mb, klass);
5845 break;
5848 mono_mb_emit_stloc (mb, 0);
5849 /* Check for null */
5850 mono_mb_emit_ldloc (mb, 0);
5851 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
5852 mono_mb_emit_byte (mb, CEE_LDNULL);
5853 mono_mb_emit_stloc (mb, 3);
5854 pos2 = mono_mb_emit_branch (mb, CEE_BR);
5856 mono_mb_patch_branch (mb, pos);
5858 /* Set src */
5859 mono_mb_emit_ldloc (mb, 0);
5860 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
5861 mono_mb_emit_stloc (mb, 0);
5863 /* Allocate and set dest */
5864 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5865 mono_mb_emit_byte (mb, CEE_CONV_I);
5866 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
5867 mono_mb_emit_byte (mb, CEE_DUP);
5868 mono_mb_emit_stloc (mb, 1);
5869 mono_mb_emit_stloc (mb, 3);
5871 emit_struct_conv (mb, klass, FALSE);
5873 mono_mb_patch_branch (mb, pos2);
5874 break;
5876 default:
5877 g_assert_not_reached ();
5879 return conv_arg;
5883 static int
5884 emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
5885 MonoMarshalSpec *spec,
5886 int conv_arg, MonoType **conv_arg_type,
5887 MarshalAction action)
5889 #ifndef DISABLE_COM
5890 MonoMethodBuilder *mb = m->mb;
5891 static MonoMethod *get_object_for_native_variant = NULL;
5892 static MonoMethod *get_native_variant_for_object = NULL;
5893 MonoType *variant_type = m_class_get_byval_arg (mono_class_get_variant_class ());
5894 MonoType *variant_type_byref = m_class_get_this_arg (mono_class_get_variant_class ());
5895 MonoType *object_type = mono_get_object_type ();
5897 if (!get_object_for_native_variant)
5898 get_object_for_native_variant = get_method_nofail (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0);
5899 g_assert (get_object_for_native_variant);
5901 if (!get_native_variant_for_object)
5902 get_native_variant_for_object = get_method_nofail (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0);
5903 g_assert (get_native_variant_for_object);
5905 switch (action) {
5906 case MARSHAL_ACTION_CONV_IN: {
5907 conv_arg = mono_mb_add_local (mb, variant_type);
5909 if (t->byref)
5910 *conv_arg_type = variant_type_byref;
5911 else
5912 *conv_arg_type = variant_type;
5914 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
5915 break;
5917 mono_mb_emit_ldarg (mb, argnum);
5918 if (t->byref)
5919 mono_mb_emit_byte(mb, CEE_LDIND_REF);
5920 mono_mb_emit_ldloc_addr (mb, conv_arg);
5921 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
5922 break;
5925 case MARSHAL_ACTION_CONV_OUT: {
5926 static MonoMethod *variant_clear = NULL;
5928 if (!variant_clear)
5929 variant_clear = get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0);
5930 g_assert (variant_clear);
5933 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
5934 mono_mb_emit_ldarg (mb, argnum);
5935 mono_mb_emit_ldloc_addr (mb, conv_arg);
5936 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
5937 mono_mb_emit_byte (mb, CEE_STIND_REF);
5940 mono_mb_emit_ldloc_addr (mb, conv_arg);
5941 mono_mb_emit_managed_call (mb, variant_clear, NULL);
5942 break;
5945 case MARSHAL_ACTION_PUSH:
5946 if (t->byref)
5947 mono_mb_emit_ldloc_addr (mb, conv_arg);
5948 else
5949 mono_mb_emit_ldloc (mb, conv_arg);
5950 break;
5952 case MARSHAL_ACTION_CONV_RESULT: {
5953 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
5954 mono_mb_emit_exception_marshal_directive (mb, msg);
5955 break;
5958 case MARSHAL_ACTION_MANAGED_CONV_IN: {
5959 conv_arg = mono_mb_add_local (mb, object_type);
5961 if (t->byref)
5962 *conv_arg_type = variant_type_byref;
5963 else
5964 *conv_arg_type = variant_type;
5966 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
5967 break;
5969 if (t->byref)
5970 mono_mb_emit_ldarg (mb, argnum);
5971 else
5972 mono_mb_emit_ldarg_addr (mb, argnum);
5973 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
5974 mono_mb_emit_stloc (mb, conv_arg);
5975 break;
5978 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
5979 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
5980 mono_mb_emit_ldloc (mb, conv_arg);
5981 mono_mb_emit_ldarg (mb, argnum);
5982 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
5984 break;
5987 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
5988 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
5989 mono_mb_emit_exception_marshal_directive (mb, msg);
5990 break;
5993 default:
5994 g_assert_not_reached ();
5996 #endif /* DISABLE_COM */
5998 return conv_arg;
6001 static void
6002 emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle)
6004 MonoMethodSignature *sig, *csig;
6005 int i, *tmp_locals, orig_domain, attach_cookie;
6006 gboolean closed = FALSE;
6008 sig = m->sig;
6009 csig = m->csig;
6011 MonoType *int_type = mono_get_int_type ();
6012 MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
6013 /* allocate local 0 (pointer) src_ptr */
6014 mono_mb_add_local (mb, int_type);
6015 /* allocate local 1 (pointer) dst_ptr */
6016 mono_mb_add_local (mb, int_type);
6017 /* allocate local 2 (boolean) delete_old */
6018 mono_mb_add_local (mb, boolean_type);
6020 if (!sig->hasthis && sig->param_count != invoke_sig->param_count) {
6021 /* Closed delegate */
6022 g_assert (sig->param_count == invoke_sig->param_count + 1);
6023 closed = TRUE;
6024 /* Use a new signature without the first argument */
6025 sig = mono_metadata_signature_dup (sig);
6026 memmove (&sig->params [0], &sig->params [1], (sig->param_count - 1) * sizeof (MonoType*));
6027 sig->param_count --;
6030 if (!MONO_TYPE_IS_VOID(sig->ret)) {
6031 /* allocate local 3 to store the return value */
6032 mono_mb_add_local (mb, sig->ret);
6035 if (MONO_TYPE_ISSTRUCT (sig->ret))
6036 m->vtaddr_var = mono_mb_add_local (mb, int_type);
6038 orig_domain = mono_mb_add_local (mb, int_type);
6039 attach_cookie = mono_mb_add_local (mb, int_type);
6042 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
6043 * intptr_t attach_cookie;
6044 * intptr_t orig_domain = mono_threads_attach_coop (domain, &attach_cookie);
6045 * <interrupt check>
6047 * ret = method (...);
6048 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
6049 * mono_threads_detach_coop (orig_domain, &attach_cookie);
6051 * return ret;
6054 mono_mb_emit_icon (mb, 0);
6055 mono_mb_emit_stloc (mb, 2);
6057 /* orig_domain = mono_threads_attach_coop (domain, &attach_cookie); */
6058 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6059 mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
6060 mono_mb_emit_ldloc_addr (mb, attach_cookie);
6062 * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads.
6063 * Keep this in sync with the CEE_JIT_ICALL code in the JIT.
6065 * Special cased in interpreter, keep in sync.
6067 mono_mb_emit_icall (mb, mono_threads_attach_coop);
6068 mono_mb_emit_stloc (mb, orig_domain);
6070 /* <interrupt check> */
6071 emit_thread_interrupt_checkpoint (mb);
6073 /* we first do all conversions */
6074 tmp_locals = g_newa (int, sig->param_count);
6075 for (i = 0; i < sig->param_count; i ++) {
6076 MonoType *t = sig->params [i];
6078 switch (t->type) {
6079 case MONO_TYPE_OBJECT:
6080 case MONO_TYPE_CLASS:
6081 case MONO_TYPE_VALUETYPE:
6082 case MONO_TYPE_ARRAY:
6083 case MONO_TYPE_SZARRAY:
6084 case MONO_TYPE_STRING:
6085 case MONO_TYPE_BOOLEAN:
6086 tmp_locals [i] = mono_emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
6087 break;
6088 default:
6089 tmp_locals [i] = 0;
6090 break;
6094 if (sig->hasthis) {
6095 if (target_handle) {
6096 mono_mb_emit_icon (mb, (gint32)target_handle);
6097 mono_mb_emit_icall (mb, mono_gchandle_get_target_internal);
6098 } else {
6099 /* fixme: */
6100 g_assert_not_reached ();
6102 } else if (closed) {
6103 mono_mb_emit_icon (mb, (gint32)target_handle);
6104 mono_mb_emit_icall (mb, mono_gchandle_get_target_internal);
6107 for (i = 0; i < sig->param_count; i++) {
6108 MonoType *t = sig->params [i];
6110 if (tmp_locals [i]) {
6111 if (t->byref)
6112 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
6113 else
6114 mono_mb_emit_ldloc (mb, tmp_locals [i]);
6116 else
6117 mono_mb_emit_ldarg (mb, i);
6120 /* ret = method (...) */
6121 mono_mb_emit_managed_call (mb, method, NULL);
6123 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
6124 MonoClass *klass = mono_class_from_mono_type_internal (sig->ret);
6125 mono_class_init_internal (klass);
6126 if (!(mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass))) {
6127 /* This is used by get_marshal_cb ()->emit_marshal_vtype (), but it needs to go right before the call */
6128 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6129 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
6130 mono_mb_emit_stloc (mb, m->vtaddr_var);
6134 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
6135 mono_emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
6136 } else if (!sig->ret->byref) {
6137 switch (sig->ret->type) {
6138 case MONO_TYPE_VOID:
6139 break;
6140 case MONO_TYPE_BOOLEAN:
6141 case MONO_TYPE_I1:
6142 case MONO_TYPE_U1:
6143 case MONO_TYPE_CHAR:
6144 case MONO_TYPE_I2:
6145 case MONO_TYPE_U2:
6146 case MONO_TYPE_I4:
6147 case MONO_TYPE_U4:
6148 case MONO_TYPE_I:
6149 case MONO_TYPE_U:
6150 case MONO_TYPE_PTR:
6151 case MONO_TYPE_R4:
6152 case MONO_TYPE_R8:
6153 case MONO_TYPE_I8:
6154 case MONO_TYPE_U8:
6155 case MONO_TYPE_OBJECT:
6156 mono_mb_emit_stloc (mb, 3);
6157 break;
6158 case MONO_TYPE_STRING:
6159 csig->ret = int_type;
6160 mono_emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
6161 break;
6162 case MONO_TYPE_VALUETYPE:
6163 case MONO_TYPE_CLASS:
6164 case MONO_TYPE_SZARRAY:
6165 mono_emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
6166 break;
6167 default:
6168 g_warning ("return type 0x%02x unknown", sig->ret->type);
6169 g_assert_not_reached ();
6171 } else {
6172 mono_mb_emit_stloc (mb, 3);
6175 /* Convert byref arguments back */
6176 for (i = 0; i < sig->param_count; i ++) {
6177 MonoType *t = sig->params [i];
6178 MonoMarshalSpec *spec = mspecs [i + 1];
6180 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
6181 mono_emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
6183 else if (t->byref) {
6184 switch (t->type) {
6185 case MONO_TYPE_CLASS:
6186 case MONO_TYPE_VALUETYPE:
6187 case MONO_TYPE_OBJECT:
6188 case MONO_TYPE_STRING:
6189 case MONO_TYPE_BOOLEAN:
6190 mono_emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
6191 break;
6192 default:
6193 break;
6196 else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
6197 /* The [Out] information is encoded in the delegate signature */
6198 switch (t->type) {
6199 case MONO_TYPE_SZARRAY:
6200 case MONO_TYPE_CLASS:
6201 case MONO_TYPE_VALUETYPE:
6202 mono_emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
6203 break;
6204 default:
6205 g_assert_not_reached ();
6210 /* mono_threads_detach_coop (orig_domain, &attach_cookie); */
6211 mono_mb_emit_ldloc (mb, orig_domain);
6212 mono_mb_emit_ldloc_addr (mb, attach_cookie);
6213 /* Special cased in interpreter, keep in sync */
6214 mono_mb_emit_icall (mb, mono_threads_detach_coop);
6216 /* return ret; */
6217 if (m->retobj_var) {
6218 mono_mb_emit_ldloc (mb, m->retobj_var);
6219 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6220 mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
6222 else {
6223 if (!MONO_TYPE_IS_VOID (sig->ret))
6224 mono_mb_emit_ldloc (mb, 3);
6225 mono_mb_emit_byte (mb, CEE_RET);
6228 if (closed)
6229 g_free (sig);
6232 static void
6233 emit_struct_to_ptr_ilgen (MonoMethodBuilder *mb, MonoClass *klass)
6235 MonoType *int_type = mono_get_int_type ();
6236 MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
6237 if (m_class_is_blittable (klass)) {
6238 mono_mb_emit_byte (mb, CEE_LDARG_1);
6239 mono_mb_emit_byte (mb, CEE_LDARG_0);
6240 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
6241 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
6242 mono_mb_emit_byte (mb, CEE_PREFIX1);
6243 mono_mb_emit_byte (mb, CEE_CPBLK);
6244 } else {
6246 /* allocate local 0 (pointer) src_ptr */
6247 mono_mb_add_local (mb, int_type);
6248 /* allocate local 1 (pointer) dst_ptr */
6249 mono_mb_add_local (mb, int_type);
6250 /* allocate local 2 (boolean) delete_old */
6251 mono_mb_add_local (mb, boolean_type);
6252 mono_mb_emit_byte (mb, CEE_LDARG_2);
6253 mono_mb_emit_stloc (mb, 2);
6255 /* initialize src_ptr to point to the start of object data */
6256 mono_mb_emit_byte (mb, CEE_LDARG_0);
6257 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
6258 mono_mb_emit_stloc (mb, 0);
6260 /* initialize dst_ptr */
6261 mono_mb_emit_byte (mb, CEE_LDARG_1);
6262 mono_mb_emit_stloc (mb, 1);
6264 emit_struct_conv (mb, klass, FALSE);
6267 mono_mb_emit_byte (mb, CEE_RET);
6270 static void
6271 emit_ptr_to_struct_ilgen (MonoMethodBuilder *mb, MonoClass *klass)
6273 MonoType *int_type = mono_get_int_type ();
6274 if (m_class_is_blittable (klass)) {
6275 mono_mb_emit_byte (mb, CEE_LDARG_1);
6276 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
6277 mono_mb_emit_byte (mb, CEE_LDARG_0);
6278 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
6279 mono_mb_emit_byte (mb, CEE_PREFIX1);
6280 mono_mb_emit_byte (mb, CEE_CPBLK);
6281 } else {
6283 /* allocate local 0 (pointer) src_ptr */
6284 mono_mb_add_local (mb, int_type);
6285 /* allocate local 1 (pointer) dst_ptr */
6286 mono_mb_add_local (mb, m_class_get_this_arg (klass));
6288 /* initialize src_ptr to point to the start of object data */
6289 mono_mb_emit_byte (mb, CEE_LDARG_0);
6290 mono_mb_emit_stloc (mb, 0);
6292 /* initialize dst_ptr */
6293 mono_mb_emit_byte (mb, CEE_LDARG_1);
6294 mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject));
6295 mono_mb_emit_stloc (mb, 1);
6297 emit_struct_conv (mb, klass, TRUE);
6300 mono_mb_emit_byte (mb, CEE_RET);
6303 static void
6304 emit_create_string_hack_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *csig, MonoMethod *res)
6306 int i;
6307 mono_mb_emit_byte (mb, CEE_LDARG_0);
6308 for (i = 1; i <= csig->param_count; i++)
6309 mono_mb_emit_ldarg (mb, i);
6310 mono_mb_emit_managed_call (mb, res, NULL);
6311 mono_mb_emit_byte (mb, CEE_RET);
6314 /* How the arguments of an icall should be wrapped */
6315 typedef enum {
6316 /* Don't wrap at all, pass the argument as is */
6317 ICALL_HANDLES_WRAP_NONE,
6318 /* Wrap the argument in an object handle, pass the handle to the icall */
6319 ICALL_HANDLES_WRAP_OBJ,
6320 /* Wrap the argument in an object handle, pass the handle to the icall,
6321 write the value out from the handle when the icall returns */
6322 ICALL_HANDLES_WRAP_OBJ_INOUT,
6323 /* Initialized an object handle to null, pass to the icalls,
6324 write the value out from the handle when the icall returns */
6325 ICALL_HANDLES_WRAP_OBJ_OUT,
6326 /* Wrap the argument (a valuetype reference) in a handle to pin its
6327 enclosing object, but pass the raw reference to the icall. This is
6328 also how we pass byref generic parameter arguments to generic method
6329 icalls (e.g. System.Array:GetGenericValue_icall<T>(int idx, T out value)) */
6330 ICALL_HANDLES_WRAP_VALUETYPE_REF,
6331 } IcallHandlesWrap;
6333 typedef struct {
6334 IcallHandlesWrap wrap;
6335 // If wrap is OBJ_OUT or OBJ_INOUT this is >= 0 and holds the referenced managed object,
6336 // in case the actual parameter refers to a native frame.
6337 // Otherwise it is -1.
6338 int handle;
6339 } IcallHandlesLocal;
6342 * Describes how to wrap the given parameter.
6345 static IcallHandlesWrap
6346 signature_param_uses_handles (MonoMethodSignature *sig, MonoMethodSignature *generic_sig, int param)
6348 /* If there is a generic parameter that isn't passed byref, we don't
6349 * know how to pass it to an icall that expects some arguments to be
6350 * wrapped in handles: if the actual argument type is a reference type
6351 * we'd need to wrap it in a handle, otherwise we'd want to pass it as is.
6353 /* FIXME: We should eventually relax the assertion, below, to
6354 * allow generic parameters that are constrained to be reference types.
6356 g_assert (!generic_sig || !mono_type_is_generic_parameter (generic_sig->params [param]));
6358 /* If the parameter in the generic version of the method signature is a
6359 * byref type variable T&, pass the corresponding argument by pinning
6360 * the memory and passing the raw pointer to the icall. Note that we
6361 * do this even if the actual instantiation is a byref reference type
6362 * like string& since the C code for the icall has to work uniformly
6363 * for both valuetypes and reference types.
6365 if (generic_sig && mono_type_is_byref_internal (generic_sig->params [param]) &&
6366 (generic_sig->params [param]->type == MONO_TYPE_VAR || generic_sig->params [param]->type == MONO_TYPE_MVAR))
6367 return ICALL_HANDLES_WRAP_VALUETYPE_REF;
6369 if (MONO_TYPE_IS_REFERENCE (sig->params [param])) {
6370 if (mono_signature_param_is_out (sig, param))
6371 return ICALL_HANDLES_WRAP_OBJ_OUT;
6372 else if (mono_type_is_byref_internal (sig->params [param]))
6373 return ICALL_HANDLES_WRAP_OBJ_INOUT;
6374 else
6375 return ICALL_HANDLES_WRAP_OBJ;
6376 } else if (mono_type_is_byref_internal (sig->params [param]))
6377 return ICALL_HANDLES_WRAP_VALUETYPE_REF;
6378 else
6379 return ICALL_HANDLES_WRAP_NONE;
6382 static void
6383 emit_native_icall_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig, gboolean check_exceptions, gboolean aot, MonoMethodPInvoke *piinfo)
6385 // FIXME:
6386 MonoMethodSignature *call_sig = csig;
6387 gboolean uses_handles = FALSE;
6388 gboolean foreign_icall = FALSE;
6389 IcallHandlesLocal *handles_locals = NULL;
6390 MonoMethodSignature *sig = mono_method_signature_internal (method);
6391 gboolean need_gc_safe = FALSE;
6392 GCSafeTransitionBuilder gc_safe_transition_builder;
6394 (void) mono_lookup_internal_call_full (method, FALSE, &uses_handles, &foreign_icall);
6396 if (G_UNLIKELY (foreign_icall)) {
6397 /* FIXME: we only want the transitions for hybrid suspend. Q: What to do about AOT? */
6398 need_gc_safe = gc_safe_transition_builder_init (&gc_safe_transition_builder, mb, FALSE);
6400 if (need_gc_safe)
6401 gc_safe_transition_builder_add_locals (&gc_safe_transition_builder);
6404 if (sig->hasthis) {
6406 * Add a null check since public icalls can be called with 'call' which
6407 * does no such check.
6409 mono_mb_emit_byte (mb, CEE_LDARG_0);
6410 const int pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6411 mono_mb_emit_exception (mb, "NullReferenceException", NULL);
6412 mono_mb_patch_branch (mb, pos);
6415 if (uses_handles) {
6416 MonoMethodSignature *generic_sig = NULL;
6418 if (method->is_inflated) {
6419 ERROR_DECL (error);
6420 MonoMethod *generic_method = ((MonoMethodInflated*)method)->declaring;
6421 generic_sig = mono_method_signature_checked (generic_method, error);
6422 mono_error_assert_ok (error);
6425 // Add a MonoError argument (due to a fragile test external/coreclr/tests/src/CoreMangLib/cti/system/weakreference/weakreferenceisaliveb.exe),
6426 // vs. on the native side.
6427 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
6428 call_sig = mono_metadata_signature_alloc (get_method_image (method), csig->param_count + 1);
6429 call_sig->param_count = csig->param_count + 1;
6430 call_sig->ret = csig->ret;
6431 call_sig->pinvoke = csig->pinvoke;
6433 /* TODO support adding wrappers to non-static struct methods */
6434 g_assert (!sig->hasthis || !m_class_is_valuetype (mono_method_get_class (method)));
6436 /* Add MonoError* param */
6437 MonoClass * const error_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
6438 int const error_var = mono_mb_add_local (mb, m_class_get_byval_arg (error_class));
6439 call_sig->params [csig->param_count] = mono_class_get_byref_type (error_class);
6441 handles_locals = g_new0 (IcallHandlesLocal, csig->param_count);
6443 for (int i = 0; i < csig->param_count; ++i) {
6444 // Determine which args need to be wrapped in handles and adjust icall signature.
6445 // Here, a handle is a pointer to a volatile local in a managed frame -- which is sufficient and efficient.
6446 const IcallHandlesWrap w = signature_param_uses_handles (csig, generic_sig, i);
6447 handles_locals [i].wrap = w;
6448 int local = -1;
6450 switch (w) {
6451 case ICALL_HANDLES_WRAP_OBJ:
6452 case ICALL_HANDLES_WRAP_OBJ_INOUT:
6453 case ICALL_HANDLES_WRAP_OBJ_OUT:
6454 call_sig->params [i] = mono_class_get_byref_type (mono_class_from_mono_type_internal (csig->params[i]));
6455 break;
6456 case ICALL_HANDLES_WRAP_NONE:
6457 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
6458 call_sig->params [i] = csig->params [i];
6459 break;
6460 default:
6461 g_assert_not_reached ();
6464 // Add a local var to hold the references for each out arg.
6465 switch (w) {
6466 case ICALL_HANDLES_WRAP_OBJ_INOUT:
6467 case ICALL_HANDLES_WRAP_OBJ_OUT:
6468 // FIXME better type
6469 local = mono_mb_add_local (mb, mono_get_object_type ());
6471 if (!mb->volatile_locals) {
6472 gpointer mem = mono_image_alloc0 (get_method_image (method), mono_bitset_alloc_size (csig->param_count + 1, 0));
6473 mb->volatile_locals = mono_bitset_mem_new (mem, csig->param_count + 1, 0);
6475 mono_bitset_set (mb->volatile_locals, local);
6476 break;
6477 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
6478 case ICALL_HANDLES_WRAP_OBJ:
6479 if (!mb->volatile_args) {
6480 gpointer mem = mono_image_alloc0 (get_method_image (method), mono_bitset_alloc_size (csig->param_count + 1, 0));
6481 mb->volatile_args = mono_bitset_mem_new (mem, csig->param_count + 1, 0);
6483 mono_bitset_set (mb->volatile_args, i);
6484 break;
6485 case ICALL_HANDLES_WRAP_NONE:
6486 break;
6487 default:
6488 g_assert_not_reached ();
6490 handles_locals [i].handle = local;
6492 // Load each argument. References into the managed heap get wrapped in handles.
6493 // Handles here are just pointers to managed volatile locals.
6494 switch (w) {
6495 case ICALL_HANDLES_WRAP_NONE:
6496 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
6497 // argI = argI
6498 mono_mb_emit_ldarg (mb, i);
6499 break;
6500 case ICALL_HANDLES_WRAP_OBJ:
6501 // argI = &argI_raw
6502 mono_mb_emit_ldarg_addr (mb, i);
6503 break;
6504 case ICALL_HANDLES_WRAP_OBJ_INOUT:
6505 case ICALL_HANDLES_WRAP_OBJ_OUT:
6506 // If parameter guaranteeably referred to a managed frame,
6507 // then could just be passthrough and volatile. Since
6508 // that cannot be guaranteed, use a managed volatile local intermediate.
6509 // ObjOut:
6510 // localI = NULL
6511 // ObjInOut:
6512 // localI = *argI_raw
6513 // &localI
6514 if (w == ICALL_HANDLES_WRAP_OBJ_OUT) {
6515 mono_mb_emit_byte (mb, CEE_LDNULL);
6516 } else {
6517 mono_mb_emit_ldarg (mb, i);
6518 mono_mb_emit_byte (mb, CEE_LDIND_REF);
6520 mono_mb_emit_stloc (mb, local);
6521 mono_mb_emit_ldloc_addr (mb, local);
6522 break;
6523 default:
6524 g_assert_not_reached ();
6527 mono_mb_emit_ldloc_addr (mb, error_var);
6528 } else {
6529 for (int i = 0; i < csig->param_count; i++)
6530 mono_mb_emit_ldarg (mb, i);
6533 if (need_gc_safe)
6534 gc_safe_transition_builder_emit_enter (&gc_safe_transition_builder, &piinfo->method, aot);
6536 if (aot) {
6537 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6538 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
6539 mono_mb_emit_calli (mb, call_sig);
6540 } else {
6541 g_assert (piinfo->addr);
6542 mono_mb_emit_native_call (mb, call_sig, piinfo->addr);
6545 if (need_gc_safe)
6546 gc_safe_transition_builder_emit_exit (&gc_safe_transition_builder);
6548 // Copy back ObjOut and ObjInOut from locals through parameters.
6549 if (mb->volatile_locals) {
6550 g_assert (handles_locals);
6551 for (int i = 0; i < csig->param_count; i++) {
6552 const int local = handles_locals [i].handle;
6553 if (local >= 0) {
6554 // *argI_raw = localI
6555 mono_mb_emit_ldarg (mb, i);
6556 mono_mb_emit_ldloc (mb, local);
6557 mono_mb_emit_byte (mb, CEE_STIND_REF);
6561 g_free (handles_locals);
6563 if (need_gc_safe)
6564 gc_safe_transition_builder_cleanup (&gc_safe_transition_builder);
6566 if (check_exceptions)
6567 emit_thread_interrupt_checkpoint (mb);
6568 mono_mb_emit_byte (mb, CEE_RET);
6571 static void
6572 mb_emit_exception_ilgen (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
6574 mono_mb_emit_exception_full (mb, exc_nspace, exc_name, msg);
6577 static void
6578 mb_emit_exception_for_error_ilgen (MonoMethodBuilder *mb, const MonoError *error)
6580 mono_mb_emit_exception_for_error (mb, (MonoError*)error);
6583 static void
6584 emit_vtfixup_ftnptr_ilgen (MonoMethodBuilder *mb, MonoMethod *method, int param_count, guint16 type)
6586 for (int i = 0; i < param_count; i++)
6587 mono_mb_emit_ldarg (mb, i);
6589 if (type & VTFIXUP_TYPE_CALL_MOST_DERIVED)
6590 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
6591 else
6592 mono_mb_emit_op (mb, CEE_CALL, method);
6593 mono_mb_emit_byte (mb, CEE_RET);
6596 static void
6597 emit_icall_wrapper_ilgen (MonoMethodBuilder *mb, MonoJitICallInfo *callinfo, MonoMethodSignature *csig2, gboolean check_exceptions)
6599 MonoMethodSignature *const sig = callinfo->sig;
6601 if (sig->hasthis)
6602 mono_mb_emit_byte (mb, CEE_LDARG_0);
6604 for (int i = 0; i < sig->param_count; i++)
6605 mono_mb_emit_ldarg (mb, i + sig->hasthis);
6607 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6608 mono_mb_emit_byte (mb, CEE_MONO_JIT_ICALL_ADDR);
6609 mono_mb_emit_i4 (mb, mono_jit_icall_info_index (callinfo));
6610 mono_mb_emit_calli (mb, csig2);
6611 if (check_exceptions)
6612 emit_thread_interrupt_checkpoint (mb);
6613 mono_mb_emit_byte (mb, CEE_RET);
6616 static void
6617 emit_return_ilgen (MonoMethodBuilder *mb)
6619 mono_mb_emit_byte (mb, CEE_RET);
6622 void
6623 mono_marshal_ilgen_init (void)
6625 MonoMarshalCallbacks cb;
6626 cb.version = MONO_MARSHAL_CALLBACKS_VERSION;
6627 cb.emit_marshal_array = emit_marshal_array_ilgen;
6628 cb.emit_marshal_boolean = emit_marshal_boolean_ilgen;
6629 cb.emit_marshal_ptr = emit_marshal_ptr_ilgen;
6630 cb.emit_marshal_char = emit_marshal_char_ilgen;
6631 cb.emit_marshal_scalar = emit_marshal_scalar_ilgen;
6632 cb.emit_marshal_custom = emit_marshal_custom_ilgen;
6633 cb.emit_marshal_asany = emit_marshal_asany_ilgen;
6634 cb.emit_marshal_vtype = emit_marshal_vtype_ilgen;
6635 cb.emit_marshal_string = emit_marshal_string_ilgen;
6636 cb.emit_marshal_safehandle = emit_marshal_safehandle_ilgen;
6637 cb.emit_marshal_handleref = emit_marshal_handleref_ilgen;
6638 cb.emit_marshal_object = emit_marshal_object_ilgen;
6639 cb.emit_marshal_variant = emit_marshal_variant_ilgen;
6640 cb.emit_castclass = emit_castclass_ilgen;
6641 cb.emit_struct_to_ptr = emit_struct_to_ptr_ilgen;
6642 cb.emit_ptr_to_struct = emit_ptr_to_struct_ilgen;
6643 cb.emit_isinst = emit_isinst_ilgen;
6644 cb.emit_virtual_stelemref = emit_virtual_stelemref_ilgen;
6645 cb.emit_stelemref = emit_stelemref_ilgen;
6646 cb.emit_array_address = emit_array_address_ilgen;
6647 cb.emit_native_wrapper = emit_native_wrapper_ilgen;
6648 cb.emit_managed_wrapper = emit_managed_wrapper_ilgen;
6649 cb.emit_runtime_invoke_body = emit_runtime_invoke_body_ilgen;
6650 cb.emit_runtime_invoke_dynamic = emit_runtime_invoke_dynamic_ilgen;
6651 cb.emit_delegate_begin_invoke = emit_delegate_begin_invoke_ilgen;
6652 cb.emit_delegate_end_invoke = emit_delegate_end_invoke_ilgen;
6653 cb.emit_delegate_invoke_internal = emit_delegate_invoke_internal_ilgen;
6654 cb.emit_synchronized_wrapper = emit_synchronized_wrapper_ilgen;
6655 cb.emit_unbox_wrapper = emit_unbox_wrapper_ilgen;
6656 cb.emit_array_accessor_wrapper = emit_array_accessor_wrapper_ilgen;
6657 cb.emit_generic_array_helper = emit_generic_array_helper_ilgen;
6658 cb.emit_thunk_invoke_wrapper = emit_thunk_invoke_wrapper_ilgen;
6659 cb.emit_create_string_hack = emit_create_string_hack_ilgen;
6660 cb.emit_native_icall_wrapper = emit_native_icall_wrapper_ilgen;
6661 cb.emit_icall_wrapper = emit_icall_wrapper_ilgen;
6662 cb.emit_return = emit_return_ilgen;
6663 cb.emit_vtfixup_ftnptr = emit_vtfixup_ftnptr_ilgen;
6664 cb.mb_skip_visibility = mb_skip_visibility_ilgen;
6665 cb.mb_set_dynamic = mb_set_dynamic_ilgen;
6666 cb.mb_emit_exception = mb_emit_exception_ilgen;
6667 cb.mb_emit_exception_for_error = mb_emit_exception_for_error_ilgen;
6668 cb.mb_emit_byte = mb_emit_byte_ilgen;
6669 mono_install_marshal_callbacks (&cb);