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