diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml index cf3c636bce337f..ee6d7863ebd6b1 100644 --- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml @@ -555,9 +555,9 @@ - + - + diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 29c420768b7d04..b3f5ecccb0f749 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -18,6 +18,8 @@ set(ilgen_base_sources method-builder-ilgen-internals.h marshal-ilgen.c marshal-ilgen.h + marshal-shared.c + marshal-shared.h sgen-mono-ilgen.c sgen-mono-ilgen.h) diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c index 9c391cf9ac76b7..974a5d1663dfc2 100644 --- a/src/mono/mono/metadata/marshal-ilgen.c +++ b/src/mono/mono/metadata/marshal-ilgen.c @@ -16,6 +16,7 @@ #include "metadata/marshal.h" #include "metadata/marshal-internals.h" #include "metadata/marshal-ilgen.h" +#include "metadata/marshal-shared.h" #include "metadata/tabledefs.h" #include #include @@ -56,983 +57,33 @@ enum { }; #undef OPDEF -static gboolean -is_in (const MonoType *t) -{ - const guint32 attrs = t->attrs; - return (attrs & PARAM_ATTRIBUTE_IN) || !(attrs & PARAM_ATTRIBUTE_OUT); -} - -static gboolean -is_out (const MonoType *t) -{ - const guint32 attrs = t->attrs; - return (attrs & PARAM_ATTRIBUTE_OUT) || !(attrs & PARAM_ATTRIBUTE_IN); -} - -static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute, "System.Runtime.CompilerServices", "FixedBufferAttribute"); -static GENERATE_GET_CLASS_WITH_CACHE (date_time, "System", "DateTime"); -static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler"); -static GENERATE_TRY_GET_CLASS_WITH_CACHE (marshal, "System.Runtime.InteropServices", "Marshal"); - -/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */ -static MonoMethod *sh_dangerous_add_ref; -static MonoMethod *sh_dangerous_release; - -// FIXME Consolidate the multiple functions named get_method_nofail. -static MonoMethod* -get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags) -{ - MonoMethod *method; - ERROR_DECL (error); - method = mono_class_get_method_from_name_checked (klass, method_name, num_params, flags, error); - mono_error_assert_ok (error); - g_assertf (method, "Could not lookup method %s in %s", method_name, m_class_get_name (klass)); - return method; -} - -static void -init_safe_handle (void) -{ - mono_atomic_store_seq (&sh_dangerous_add_ref, get_method_nofail (mono_class_try_get_safehandle_class (), "DangerousAddRef", 1, 0)); - mono_atomic_store_seq (&sh_dangerous_release, get_method_nofail (mono_class_try_get_safehandle_class (), "DangerousRelease", 0, 0)); -} - -static MonoImage* -get_method_image (MonoMethod *method) -{ - return m_class_get_image (method->klass); -} - -static void -emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object); - -static void -emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding); - -static MonoJitICallId -conv_to_icall (MonoMarshalConv conv, int *ind_store_type); - -static MonoMarshalConv -conv_str_inverse (MonoMarshalConv conv); - -/** - * mono_mb_strdup: - * \param mb the MethodBuilder - * \param s a string - * - * Creates a copy of the string \p s that can be referenced from the IL of \c mb. - * - * \returns a pointer to the new string which is owned by the method builder - */ -char* -mono_mb_strdup (MonoMethodBuilder *mb, const char *s) -{ - char *res; - if (!mb->dynamic) - res = mono_image_strdup (get_method_image (mb->method), s); - else - res = g_strdup (s); - return res; -} - - - -/* - * mono_mb_emit_exception_marshal_directive: - * - * This function assumes ownership of MSG, which should be malloc-ed. - */ -static void -mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg) -{ - char *s = mono_mb_strdup (mb, msg); - g_free (msg); - mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", s); -} - -static int -offset_of_first_nonstatic_field (MonoClass *klass) -{ - mono_class_setup_fields (klass); - gpointer iter = NULL; - MonoClassField *field; - while ((field = mono_class_get_fields_internal (klass, &iter))) { - if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (field)) { - /* - * metadata-update: adding fields to existing structs isn't supported. In - * newly-added structs, the "from update" field won't be set. - */ - g_assert (!m_field_is_from_update (field)); - return m_field_get_offset (field) - MONO_ABI_SIZEOF (MonoObject); - } - } - - return 0; -} - -static gboolean -get_fixed_buffer_attr (MonoClassField *field, MonoType **out_etype, int *out_len) -{ - ERROR_DECL (error); - MonoCustomAttrInfo *cinfo; - MonoCustomAttrEntry *attr; - int aindex; - - cinfo = mono_custom_attrs_from_field_checked (m_field_get_parent (field), field, error); - if (!is_ok (error)) - return FALSE; - attr = NULL; - if (cinfo) { - for (aindex = 0; aindex < cinfo->num_attrs; ++aindex) { - MonoClass *ctor_class = cinfo->attrs [aindex].ctor->klass; - if (mono_class_has_parent (ctor_class, mono_class_get_fixed_buffer_attribute_class ())) { - attr = &cinfo->attrs [aindex]; - break; - } - } - } - if (attr) { - gpointer *typed_args, *named_args; - CattrNamedArg *arginfo; - int num_named_args; - - mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, - &typed_args, &named_args, &num_named_args, &arginfo, error); - if (!is_ok (error)) - return FALSE; - *out_etype = (MonoType*)typed_args [0]; - *out_len = *(gint32*)typed_args [1]; - g_free (typed_args [1]); - g_free (typed_args); - g_free (named_args); - g_free (arginfo); - } - if (cinfo && !cinfo->cached) - mono_custom_attrs_free (cinfo); - return attr != NULL; -} - -static void -emit_fixed_buf_conv (MonoMethodBuilder *mb, MonoType *type, MonoType *etype, int len, gboolean to_object, int *out_usize) -{ - MonoClass *klass = mono_class_from_mono_type_internal (type); - MonoClass *eklass = mono_class_from_mono_type_internal (etype); - int esize; - - esize = mono_class_native_size (eklass, NULL); - - MonoMarshalNative string_encoding = m_class_is_unicode (klass) ? MONO_NATIVE_LPWSTR : MONO_NATIVE_LPSTR; - int usize = mono_class_value_size (eklass, NULL); - int msize = mono_class_value_size (eklass, NULL); - - //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), em_class_is_blittable (klass), string_encoding); - - if (m_class_is_blittable (eklass)) { - /* copy the elements */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, len * esize); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - } else { - int index_var; - guint32 label2, label3; - - /* Emit marshalling loop */ - MonoType *int_type = mono_get_int_type (); - index_var = mono_mb_add_local (mb, int_type); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_stloc (mb, index_var); - - /* Loop header */ - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_icon (mb, len); - label3 = mono_mb_emit_branch (mb, CEE_BGE); - - /* src/dst is already set */ - - /* Do the conversion */ - MonoTypeEnum t = etype->type; - switch (t) { - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_PTR: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - if (t == MONO_TYPE_CHAR && string_encoding != MONO_NATIVE_LPWSTR) { - if (to_object) { - mono_mb_emit_byte (mb, CEE_LDIND_U1); - mono_mb_emit_byte (mb, CEE_STIND_I2); - } else { - mono_mb_emit_byte (mb, CEE_LDIND_U2); - mono_mb_emit_byte (mb, CEE_STIND_I1); - } - usize = 1; - } else { - mono_mb_emit_byte (mb, mono_type_to_ldind (etype)); - mono_mb_emit_byte (mb, mono_type_to_stind (etype)); - } - break; - default: - g_assert_not_reached (); - break; - } - - if (to_object) { - mono_mb_emit_add_to_local (mb, 0, usize); - mono_mb_emit_add_to_local (mb, 1, msize); - } else { - mono_mb_emit_add_to_local (mb, 0, msize); - mono_mb_emit_add_to_local (mb, 1, usize); - } - - /* Loop footer */ - mono_mb_emit_add_to_local (mb, index_var, 1); - - mono_mb_emit_branch_label (mb, CEE_BR, label2); - - mono_mb_patch_branch (mb, label3); - } - - *out_usize = usize * len; -} - -static void -emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec) -{ - switch (conv) { - case MONO_MARSHAL_CONV_BOOL_I4: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - mono_mb_emit_byte (mb, 3); - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - mono_mb_emit_byte (mb, CEE_BR_S); - mono_mb_emit_byte (mb, 1); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_byte (mb, CEE_STIND_I1); - break; - case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I2); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - mono_mb_emit_byte (mb, 3); - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - mono_mb_emit_byte (mb, CEE_BR_S); - mono_mb_emit_byte (mb, 1); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_byte (mb, CEE_STIND_I1); - break; - case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: { - MonoClass *eklass = NULL; - int esize; - - if (type->type == MONO_TYPE_SZARRAY) { - eklass = type->data.klass; - } else { - g_assert_not_reached (); - } - - esize = mono_class_native_size (eklass, NULL); - - /* create a new array */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_op (mb, CEE_NEWARR, eklass); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - if (m_class_is_blittable (eklass)) { - /* copy the elements */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - } - else { - int array_var, src_var, dst_var, index_var; - guint32 label2, label3; - - MonoType *int_type = mono_get_int_type (); - array_var = mono_mb_add_local (mb, mono_get_object_type ()); - src_var = mono_mb_add_local (mb, int_type); - dst_var = mono_mb_add_local (mb, int_type); - - /* set array_var */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_stloc (mb, array_var); - - /* save the old src pointer */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, src_var); - /* save the old dst pointer */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, dst_var); - - /* Emit marshalling loop */ - index_var = mono_mb_add_local (mb, int_type); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_stloc (mb, index_var); - - /* Loop header */ - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldloc (mb, array_var); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); - - /* src is already set */ - - /* Set dst */ - mono_mb_emit_ldloc (mb, array_var); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_op (mb, CEE_LDELEMA, eklass); - mono_mb_emit_stloc (mb, 1); - - /* Do the conversion */ - emit_struct_conv (mb, eklass, TRUE); - - /* Loop footer */ - mono_mb_emit_add_to_local (mb, index_var, 1); - - mono_mb_emit_branch_label (mb, CEE_BR, label2); - - mono_mb_patch_branch (mb, label3); - - /* restore the old src pointer */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, 0); - /* restore the old dst pointer */ - mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_stloc (mb, 1); - } - break; - } - case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: { - MonoClass *eclass = mono_defaults.char_class; - - /* create a new array */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_op (mb, CEE_NEWARR, eclass); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_icall (mb, mono_byvalarray_to_byte_array); - break; - } - case MONO_MARSHAL_CONV_STR_BYVALSTR: - if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_icall (mb, mono_string_from_byvalstr); - } else { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icall (mb, ves_icall_string_new_wrapper); - } - mono_mb_emit_byte (mb, CEE_STIND_REF); - break; - case MONO_MARSHAL_CONV_STR_BYVALWSTR: - if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_icall (mb, mono_string_from_byvalwstr); - } else { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16); - } - mono_mb_emit_byte (mb, CEE_STIND_REF); - break; - - case MONO_MARSHAL_CONV_STR_ANSIBSTR: - case MONO_MARSHAL_CONV_STR_TBSTR: - case MONO_MARSHAL_CONV_STR_UTF8STR: - case MONO_MARSHAL_CONV_STR_LPWSTR: - case MONO_MARSHAL_CONV_STR_LPSTR: - case MONO_MARSHAL_CONV_STR_LPTSTR: - case MONO_MARSHAL_CONV_STR_BSTR: { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (conv_str_inverse (conv), NULL)); - mono_mb_emit_byte (mb, CEE_STIND_REF); - break; - } - - case MONO_MARSHAL_CONV_OBJECT_STRUCT: { - MonoClass *klass = mono_class_from_mono_type_internal (type); - int src_var, dst_var; - - MonoType *int_type = mono_get_int_type (); - src_var = mono_mb_add_local (mb, int_type); - dst_var = mono_mb_add_local (mb, int_type); - - /* *dst = new object */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - /* save the old src pointer */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, src_var); - /* save the old dst pointer */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, dst_var); - - /* dst = pointer to newly created object data */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, 1); - - emit_struct_conv (mb, klass, TRUE); - - /* restore the old src pointer */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, 0); - /* restore the old dst pointer */ - mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_stloc (mb, 1); - break; - } - case MONO_MARSHAL_CONV_DEL_FTN: { - MonoClass *klass = mono_class_from_mono_type_internal (type); - - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall (mb, mono_ftnptr_to_delegate); - mono_mb_emit_byte (mb, CEE_STIND_REF); - break; - } - case MONO_MARSHAL_CONV_ARRAY_LPARRAY: { - 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))); - mono_mb_emit_exception_marshal_directive (mb, msg); - break; - } - -#ifndef DISABLE_COM - case MONO_MARSHAL_CONV_OBJECT_INTERFACE: - case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: - case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: - mono_cominterop_emit_ptr_to_object_conv (mb, type, conv, mspec); - break; -#endif /* DISABLE_COM */ - - case MONO_MARSHAL_CONV_SAFEHANDLE: { - /* - * Passing SafeHandles as ref does not allow the unmanaged code - * to change the SafeHandle value. If the value is changed, - * we should issue a diagnostic exception (NotSupportedException) - * that informs the user that changes to handles in unmanaged code - * is not supported. - * - * Since we currently have no access to the original - * SafeHandle that was used during the marshalling, - * for now we just ignore this, and ignore/discard any - * changes that might have happened to the handle. - */ - break; - } - - case MONO_MARSHAL_CONV_HANDLEREF: { - /* - * Passing HandleRefs in a struct that is ref()ed does not - * copy the values back to the HandleRef - */ - break; - } - - case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: - default: { - char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv); - - mono_mb_emit_exception_marshal_directive (mb, msg); - break; - } - } -} - -// On legacy Mono, LPTSTR was either UTF16 or UTF8 depending on platform -static inline MonoJitICallId -mono_string_to_platform_unicode (void) -{ -#ifdef TARGET_WIN32 - return MONO_JIT_ICALL_mono_marshal_string_to_utf16; -#else - return MONO_JIT_ICALL_mono_string_to_utf8str; -#endif -} - -static inline MonoJitICallId -mono_string_from_platform_unicode (void) -{ -#ifdef TARGET_WIN32 - return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16; -#else - return MONO_JIT_ICALL_ves_icall_string_new_wrapper; -#endif -} - -static inline MonoJitICallId -mono_string_builder_to_platform_unicode (void) -{ -#ifdef TARGET_WIN32 - return MONO_JIT_ICALL_mono_string_builder_to_utf16; -#else - return MONO_JIT_ICALL_mono_string_builder_to_utf8; -#endif -} - -static inline MonoJitICallId -mono_string_builder_from_platform_unicode (void) -{ -#ifdef TARGET_WIN32 - return MONO_JIT_ICALL_mono_string_utf16_to_builder; -#else - return MONO_JIT_ICALL_mono_string_utf8_to_builder; -#endif -} - -static MonoMarshalConv -conv_str_inverse (MonoMarshalConv conv) -{ - switch (conv) { - // AnsiBStr - case MONO_MARSHAL_CONV_STR_ANSIBSTR: - return MONO_MARSHAL_CONV_ANSIBSTR_STR; - case MONO_MARSHAL_CONV_ANSIBSTR_STR: - return MONO_MARSHAL_CONV_STR_ANSIBSTR; - - // BStr - case MONO_MARSHAL_CONV_STR_BSTR: - return MONO_MARSHAL_CONV_BSTR_STR; - case MONO_MARSHAL_CONV_BSTR_STR: - return MONO_MARSHAL_CONV_STR_BSTR; - - // LPStr - case MONO_MARSHAL_CONV_STR_LPSTR: - return MONO_MARSHAL_CONV_LPSTR_STR; - case MONO_MARSHAL_CONV_LPSTR_STR: - return MONO_MARSHAL_CONV_STR_LPSTR; - - // LPTStr - case MONO_MARSHAL_CONV_STR_LPTSTR: - return MONO_MARSHAL_CONV_LPTSTR_STR; - case MONO_MARSHAL_CONV_LPTSTR_STR: - return MONO_MARSHAL_CONV_STR_LPTSTR; - - // LPUTF8Str - case MONO_MARSHAL_CONV_STR_UTF8STR: - return MONO_MARSHAL_CONV_UTF8STR_STR; - case MONO_MARSHAL_CONV_UTF8STR_STR: - return MONO_MARSHAL_CONV_STR_UTF8STR; - - // LPWStr - case MONO_MARSHAL_CONV_STR_LPWSTR: - return MONO_MARSHAL_CONV_LPWSTR_STR; - case MONO_MARSHAL_CONV_LPWSTR_STR: - return MONO_MARSHAL_CONV_STR_LPWSTR; - - // TBStr - case MONO_MARSHAL_CONV_STR_TBSTR: - return MONO_MARSHAL_CONV_TBSTR_STR; - case MONO_MARSHAL_CONV_TBSTR_STR: - return MONO_MARSHAL_CONV_STR_TBSTR; - - default: - g_assert_not_reached (); - } -} - -static MonoJitICallId -conv_to_icall (MonoMarshalConv conv, int *ind_store_type) -{ - // FIXME This or its caller might be a good place to inline some - // of the wrapper logic. In particular, to produce - // volatile stack-based handles. Being data-driven, - // from icall-def.h. - - int dummy; - if (!ind_store_type) - ind_store_type = &dummy; - *ind_store_type = CEE_STIND_I; - switch (conv) { - // AnsiBStr - case MONO_MARSHAL_CONV_STR_ANSIBSTR: - return MONO_JIT_ICALL_mono_string_to_ansibstr; - case MONO_MARSHAL_CONV_ANSIBSTR_STR: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_string_from_ansibstr; - - // BStr - case MONO_MARSHAL_CONV_STR_BSTR: - return MONO_JIT_ICALL_mono_string_to_bstr; - case MONO_MARSHAL_CONV_BSTR_STR: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_string_from_bstr_icall; - - // LPStr - // In Mono, LPSTR was historically treated as UTF8STR - case MONO_MARSHAL_CONV_STR_LPSTR: - return MONO_JIT_ICALL_mono_string_to_utf8str; - case MONO_MARSHAL_CONV_LPSTR_STR: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_ves_icall_string_new_wrapper; - case MONO_MARSHAL_CONV_SB_LPSTR: - return MONO_JIT_ICALL_mono_string_builder_to_utf8; - case MONO_MARSHAL_CONV_LPSTR_SB: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_string_utf8_to_builder; - - // LPTStr - // FIXME: This is how LPTStr was handled on legacy, but it's not correct and for netcore we should implement this more properly. - // This type is supposed to detect ANSI or UTF16 (as LPTStr can be either depending on _UNICODE) and handle it accordingly. - // The CoreCLR test for this type only tests as LPWSTR regardless of platform. - case MONO_MARSHAL_CONV_STR_LPTSTR: - return mono_string_to_platform_unicode (); - case MONO_MARSHAL_CONV_LPTSTR_STR: - *ind_store_type = CEE_STIND_REF; - return mono_string_from_platform_unicode (); - case MONO_MARSHAL_CONV_SB_LPTSTR: - return mono_string_builder_to_platform_unicode (); - case MONO_MARSHAL_CONV_LPTSTR_SB: - *ind_store_type = CEE_STIND_REF; - return mono_string_builder_from_platform_unicode (); - - // LPUTF8Str - case MONO_MARSHAL_CONV_STR_UTF8STR: - return MONO_JIT_ICALL_mono_string_to_utf8str; - case MONO_MARSHAL_CONV_UTF8STR_STR: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_ves_icall_string_new_wrapper; - case MONO_MARSHAL_CONV_SB_UTF8STR: - return MONO_JIT_ICALL_mono_string_builder_to_utf8; - case MONO_MARSHAL_CONV_UTF8STR_SB: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_string_utf8_to_builder; - - // LPWStr - case MONO_MARSHAL_CONV_STR_LPWSTR: - return MONO_JIT_ICALL_mono_marshal_string_to_utf16; - case MONO_MARSHAL_CONV_LPWSTR_STR: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16; - case MONO_MARSHAL_CONV_SB_LPWSTR: - return MONO_JIT_ICALL_mono_string_builder_to_utf16; - case MONO_MARSHAL_CONV_LPWSTR_SB: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_string_utf16_to_builder; - - // TBStr - case MONO_MARSHAL_CONV_STR_TBSTR: - return MONO_JIT_ICALL_mono_string_to_tbstr; - case MONO_MARSHAL_CONV_TBSTR_STR: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_string_from_tbstr; - - case MONO_MARSHAL_CONV_STR_BYVALSTR: - return MONO_JIT_ICALL_mono_string_to_byvalstr; - case MONO_MARSHAL_CONV_STR_BYVALWSTR: - return MONO_JIT_ICALL_mono_string_to_byvalwstr; - - case MONO_MARSHAL_CONV_DEL_FTN: - return MONO_JIT_ICALL_mono_delegate_to_ftnptr; - case MONO_MARSHAL_CONV_FTN_DEL: - *ind_store_type = CEE_STIND_REF; - return MONO_JIT_ICALL_mono_ftnptr_to_delegate; - - case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: - return MONO_JIT_ICALL_mono_array_to_savearray; - case MONO_MARSHAL_FREE_ARRAY: - return MONO_JIT_ICALL_mono_marshal_free_array; - - case MONO_MARSHAL_CONV_ARRAY_LPARRAY: - return MONO_JIT_ICALL_mono_array_to_lparray; - case MONO_MARSHAL_FREE_LPARRAY: - return MONO_JIT_ICALL_mono_free_lparray; - - default: - g_assert_not_reached (); - } - - return MONO_JIT_ICALL_ZeroIsReserved; -} - -static void -emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec) -{ - int pos; - int stind_op; - - switch (conv) { - case MONO_MARSHAL_CONV_BOOL_I4: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_U1); - mono_mb_emit_byte (mb, CEE_STIND_I4); - break; - case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_U1); - mono_mb_emit_byte (mb, CEE_NEG); - mono_mb_emit_byte (mb, CEE_STIND_I2); - break; - case MONO_MARSHAL_CONV_STR_UTF8STR: - case MONO_MARSHAL_CONV_STR_LPWSTR: - case MONO_MARSHAL_CONV_STR_LPSTR: - case MONO_MARSHAL_CONV_STR_LPTSTR: - case MONO_MARSHAL_CONV_STR_BSTR: - case MONO_MARSHAL_CONV_STR_ANSIBSTR: - case MONO_MARSHAL_CONV_STR_TBSTR: { - /* free space if free == true */ - mono_mb_emit_ldloc (mb, 2); - pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall (mb, g_free); // aka monoeg_g_free - mono_mb_patch_short_branch (mb, pos); - - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); - mono_mb_emit_byte (mb, stind_op); - break; - } - case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: - case MONO_MARSHAL_CONV_ARRAY_LPARRAY: - case MONO_MARSHAL_CONV_DEL_FTN: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); - mono_mb_emit_byte (mb, stind_op); - break; - case MONO_MARSHAL_CONV_STR_BYVALSTR: - case MONO_MARSHAL_CONV_STR_BYVALWSTR: { - g_assert (mspec); - - mono_mb_emit_ldloc (mb, 1); /* dst */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */ - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); - break; - } - case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: { - MonoClass *eklass = NULL; - int esize; - - if (type->type == MONO_TYPE_SZARRAY) { - eklass = type->data.klass; - } else if (type->type == MONO_TYPE_ARRAY) { - eklass = type->data.array->eklass; - g_assert(m_class_is_blittable (eklass)); - } else { - g_assert_not_reached (); - } - - if (m_class_is_valuetype (eklass)) - esize = mono_class_native_size (eklass, NULL); - else - esize = TARGET_SIZEOF_VOID_P; - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - - if (m_class_is_blittable (eklass)) { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - } else { - int array_var, src_var, dst_var, index_var; - guint32 label2, label3; - - MonoType *int_type = mono_get_int_type (); - MonoType *object_type = mono_get_object_type (); - array_var = mono_mb_add_local (mb, object_type); - src_var = mono_mb_add_local (mb, int_type); - dst_var = mono_mb_add_local (mb, int_type); - - /* set array_var */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_stloc (mb, array_var); - - /* save the old src pointer */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, src_var); - /* save the old dst pointer */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, dst_var); - - /* Emit marshalling loop */ - index_var = mono_mb_add_local (mb, int_type); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_stloc (mb, index_var); - - /* Loop header */ - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldloc (mb, array_var); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); - - /* Set src */ - mono_mb_emit_ldloc (mb, array_var); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_op (mb, CEE_LDELEMA, eklass); - mono_mb_emit_stloc (mb, 0); - - /* dst is already set */ - - /* Do the conversion */ - emit_struct_conv (mb, eklass, FALSE); - - /* Loop footer */ - mono_mb_emit_add_to_local (mb, index_var, 1); - - mono_mb_emit_branch_label (mb, CEE_BR, label2); - - mono_mb_patch_branch (mb, label3); - - /* restore the old src pointer */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, 0); - /* restore the old dst pointer */ - mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_stloc (mb, 1); - } - - mono_mb_patch_branch (mb, pos); - break; - } - case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: { - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_icall (mb, mono_array_to_byte_byvalarray); - mono_mb_patch_short_branch (mb, pos); - break; - } - case MONO_MARSHAL_CONV_OBJECT_STRUCT: { - int src_var, dst_var; - - MonoType *int_type = mono_get_int_type (); - src_var = mono_mb_add_local (mb, int_type); - dst_var = mono_mb_add_local (mb, int_type); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* save the old src pointer */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, src_var); - /* save the old dst pointer */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, dst_var); - - /* src = pointer to object data */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, 0); - - emit_struct_conv (mb, mono_class_from_mono_type_internal (type), FALSE); - - /* restore the old src pointer */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, 0); - /* restore the old dst pointer */ - mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_stloc (mb, 1); - - mono_mb_patch_branch (mb, pos); - break; - } - -#ifndef DISABLE_COM - case MONO_MARSHAL_CONV_OBJECT_INTERFACE: - case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: - case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: - mono_cominterop_emit_object_to_ptr_conv (mb, type, conv, mspec); - break; -#endif /* DISABLE_COM */ - - case MONO_MARSHAL_CONV_SAFEHANDLE: { - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - pos = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_emit_exception (mb, "ArgumentNullException", NULL); - mono_mb_patch_branch (mb, pos); - - /* Pull the handle field from SafeHandle */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_STIND_I); - break; - } +static GENERATE_GET_CLASS_WITH_CACHE (date_time, "System", "DateTime"); +static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler"); - case MONO_MARSHAL_CONV_HANDLEREF: { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_STIND_I); - break; - } +static MonoImage* +get_method_image (MonoMethod *method) +{ + return m_class_get_image (method->klass); +} - default: { - g_error ("marshalling conversion %d not implemented", conv); - } - } +/** + * mono_mb_strdup: + * \param mb the MethodBuilder + * \param s a string + * + * Creates a copy of the string \p s that can be referenced from the IL of \c mb. + * + * \returns a pointer to the new string which is owned by the method builder + */ +char* +mono_mb_strdup (MonoMethodBuilder *mb, const char *s) +{ + char *res; + if (!mb->dynamic) + res = mono_image_strdup (get_method_image (mb->method), s); + else + res = g_strdup (s); + return res; } #ifndef DISABLE_COM @@ -1043,7 +94,7 @@ static MonoMethod* mono_get_Variant_Clear (void) { MONO_STATIC_POINTER_INIT (MonoMethod, variant_clear) - variant_clear = get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0); + variant_clear = mono_marshal_shared_get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0); MONO_STATIC_POINTER_INIT_END (MonoMethod, variant_clear) g_assert (variant_clear); @@ -1058,7 +109,7 @@ static MonoMethod* mono_get_Marshal_GetObjectForNativeVariant (void) { MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_native_variant) - get_object_for_native_variant = get_method_nofail (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0); + get_object_for_native_variant = mono_marshal_shared_get_method_nofail (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0); MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_native_variant) g_assert (get_object_for_native_variant); @@ -1071,254 +122,13 @@ static MonoMethod* mono_get_Marshal_GetNativeVariantForObject (void) { MONO_STATIC_POINTER_INIT (MonoMethod, get_native_variant_for_object) - get_native_variant_for_object = get_method_nofail (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0); + get_native_variant_for_object = mono_marshal_shared_get_method_nofail (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0); MONO_STATIC_POINTER_INIT_END (MonoMethod, get_native_variant_for_object) g_assert (get_native_variant_for_object); return get_native_variant_for_object; } -static void -emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, - int offset_of_first_child_field, MonoMarshalNative string_encoding) -{ - MonoMarshalType *info; - int i; - - if (m_class_get_parent (klass)) - emit_struct_conv_full (mb, m_class_get_parent (klass), to_object, offset_of_first_nonstatic_field (klass), string_encoding); - - info = mono_marshal_load_type_info (klass); - - if (info->native_size == 0) - return; - - if (m_class_is_blittable (klass)) { - int usize = mono_class_value_size (klass, NULL); - g_assert (usize == info->native_size); - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, usize); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - - if (to_object) { - mono_mb_emit_add_to_local (mb, 0, usize); - mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field); - } else { - mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field); - mono_mb_emit_add_to_local (mb, 1, usize); - } - return; - } - - if (klass != mono_class_try_get_safehandle_class ()) { - if (mono_class_is_auto_layout (klass)) { - char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.", - mono_type_full_name (m_class_get_byval_arg (klass))); - mono_mb_emit_exception_marshal_directive (mb, msg); - return; - } - } - - for (i = 0; i < info->num_fields; i++) { - MonoMarshalNative ntype; - MonoMarshalConv conv; - MonoType *ftype = info->fields [i].field->type; - int msize = 0; - int usize = 0; - gboolean last_field = i < (info->num_fields -1) ? 0 : 1; - - if (ftype->attrs & FIELD_ATTRIBUTE_STATIC) - continue; - - ntype = (MonoMarshalNative)mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, m_class_is_unicode (klass), &conv); - - if (last_field) { - msize = m_class_get_instance_size (klass) - m_field_get_offset (info->fields [i].field); - usize = info->native_size - info->fields [i].offset; - } else { - msize = m_field_get_offset (info->fields [i + 1].field) - m_field_get_offset (info->fields [i].field); - usize = info->fields [i + 1].offset - info->fields [i].offset; - } - - if (klass != mono_class_try_get_safehandle_class ()){ - /* - * FIXME: Should really check for usize==0 and msize>0, but we apply - * the layout to the managed structure as well. - */ - - if (mono_class_is_explicit_layout (klass) && (usize == 0)) { - if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || - ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) - g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a " - "reference field at the same offset as another field.", - mono_type_full_name (m_class_get_byval_arg (klass))); - } - } - - switch (conv) { - case MONO_MARSHAL_CONV_NONE: { - int t; - - //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB - g_assert (!m_type_is_byref (ftype)); - if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_STIND_I); - break; - } - - handle_enum: - t = ftype->type; - switch (t) { - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_CHAR: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_PTR: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - if (t == MONO_TYPE_CHAR && ntype == MONO_NATIVE_U1 && string_encoding != MONO_NATIVE_LPWSTR) { - if (to_object) { - mono_mb_emit_byte (mb, CEE_LDIND_U1); - mono_mb_emit_byte (mb, CEE_STIND_I2); - } else { - mono_mb_emit_byte (mb, CEE_LDIND_U2); - mono_mb_emit_byte (mb, CEE_STIND_I1); - } - } else { - mono_mb_emit_byte (mb, mono_type_to_ldind (ftype)); - mono_mb_emit_byte (mb, mono_type_to_stind (ftype)); - } - break; - case MONO_TYPE_GENERICINST: - if (!mono_type_generic_inst_is_valuetype (ftype)) { - char *msg = g_strdup_printf ("Generic type %s cannot be marshaled as field in a struct.", - mono_type_full_name (ftype)); - mono_mb_emit_exception_marshal_directive (mb, msg); - break; - } - /* fall through */ - case MONO_TYPE_VALUETYPE: { - int src_var, dst_var; - MonoType *etype; - int len; - - if (t == MONO_TYPE_VALUETYPE && m_class_is_enumtype (ftype->data.klass)) { - ftype = mono_class_enum_basetype_internal (ftype->data.klass); - goto handle_enum; - } - - MonoType *int_type = mono_get_int_type (); - src_var = mono_mb_add_local (mb, int_type); - dst_var = mono_mb_add_local (mb, int_type); - - /* save the old src pointer */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, src_var); - /* save the old dst pointer */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, dst_var); - - if (get_fixed_buffer_attr (info->fields [i].field, &etype, &len)) { - emit_fixed_buf_conv (mb, ftype, etype, len, to_object, &usize); - } else { - emit_struct_conv (mb, mono_class_from_mono_type_internal (ftype), to_object); - } - - /* restore the old src pointer */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, 0); - /* restore the old dst pointer */ - mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_stloc (mb, 1); - break; - } - case MONO_TYPE_OBJECT: { -#ifndef DISABLE_COM - if (to_object) { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL); - } - else { - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte(mb, CEE_LDIND_REF); - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); - } -#else - char *msg = g_strdup_printf ("COM support was disabled at compilation time."); - mono_mb_emit_exception_marshal_directive (mb, msg); -#endif - break; - } - - default: - g_warning ("marshaling type %02x not implemented", ftype->type); - g_assert_not_reached (); - } - break; - } - default: { - int src_var, dst_var; - - MonoType *int_type = mono_get_int_type (); - src_var = mono_mb_add_local (mb, int_type); - dst_var = mono_mb_add_local (mb, int_type); - - /* save the old src pointer */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, src_var); - /* save the old dst pointer */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, dst_var); - - if (to_object) - emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec); - else - emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec); - - /* restore the old src pointer */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, 0); - /* restore the old dst pointer */ - mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_stloc (mb, 1); - } - } - - if (to_object) { - mono_mb_emit_add_to_local (mb, 0, usize); - mono_mb_emit_add_to_local (mb, 1, msize); - } else { - mono_mb_emit_add_to_local (mb, 0, msize); - mono_mb_emit_add_to_local (mb, 1, usize); - } - } -} - -static void -emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) -{ - emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1); -} - static void emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var) { @@ -1330,40 +140,6 @@ emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var) mono_mb_emit_icall (mb, mono_struct_delete_old); } -static void -emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, MonoJitICallId checkpoint_icall_id) -{ - int pos_noabort, pos_noex; - - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_LDPTR_INT_REQ_FLAG); - mono_mb_emit_no_nullcheck (mb); - mono_mb_emit_byte (mb, CEE_LDIND_U4); - pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE); - - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN); - - mono_mb_emit_icall_id (mb, checkpoint_icall_id); - /* Throw the exception returned by the checkpoint function, if any */ - mono_mb_emit_byte (mb, CEE_DUP); - pos_noex = mono_mb_emit_branch (mb, CEE_BRFALSE); - - mono_mb_emit_byte (mb, CEE_DUP); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoException, caught_in_unmanaged)); - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - mono_mb_emit_no_nullcheck (mb); - mono_mb_emit_byte (mb, CEE_STIND_I4); - - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_RETHROW); - - mono_mb_patch_branch (mb, pos_noex); - mono_mb_emit_byte (mb, CEE_POP); - - mono_mb_patch_branch (mb, pos_noabort); -} - static void emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb) { @@ -1371,13 +147,13 @@ emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb) if (strstr (mb->name, "mono_thread_interruption_checkpoint")) return; - emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_interruption_checkpoint); + mono_marshal_shared_emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_interruption_checkpoint); } static void emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb) { - emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise); + mono_marshal_shared_emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_force_interruption_checkpoint_noraise); } void @@ -1866,13 +642,6 @@ emit_runtime_invoke_dynamic_ilgen (MonoMethodBuilder *mb) mono_mb_emit_byte (mb, CEE_RET); } -static void -mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass) -{ - 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)); - mono_mb_emit_exception_marshal_directive (mb, msg); -} - typedef struct EmitGCSafeTransitionBuilder { MonoMethodBuilder *mb; gboolean func_param; @@ -2071,7 +840,7 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi MonoType *int_type = mono_get_int_type (); MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); - /* we allocate local for use with emit_struct_conv() */ + /* we allocate local for use with mono_marshal_shared_emit_struct_conv() */ /* allocate local 0 (pointer) src_ptr */ mono_mb_add_local (mb, int_type); /* allocate local 1 (pointer) dst_ptr */ @@ -2151,7 +920,7 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi // Check if SetLastError usage is valid early so we don't try to throw an exception after transitioning GC modes. if (piinfo && (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) && !m.runtime_marshalling_enabled) - mono_mb_emit_exception_marshal_directive(mb, g_strdup("Setting SetLastError=true is not supported when runtime marshalling is disabled.")); + mono_marshal_shared_mb_emit_exception_marshal_directive(mb, g_strdup("Setting SetLastError=true is not supported when runtime marshalling is disabled.")); /* we first do all conversions */ tmp_locals = g_newa (int, sig->param_count); @@ -2499,12 +1268,12 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL)); mono_mb_emit_stloc (mb, conv_arg); } else { #ifdef DISABLE_NONBLITTABLE char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); #else guint32 label1, label2, label3; int index_var, src_var, dest_ptr, esize; @@ -2526,7 +1295,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (is_string && conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -2585,7 +1354,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_ldloc (mb, index_var); mono_mb_emit_byte (mb, CEE_LDELEM_REF); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); mono_mb_emit_byte (mb, stind_op); } else { /* set the src_ptr */ @@ -2599,7 +1368,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); + mono_marshal_shared_emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); } mono_mb_emit_add_to_local (mb, index_var, 1); @@ -2637,7 +1406,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (param_type) && param_type->type != MONO_TYPE_I4) { char *msg = g_strdup ("Not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -2710,7 +1479,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, src_ptr); mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); if (need_free) { /* src */ @@ -2744,7 +1513,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); + mono_marshal_shared_emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); } if (need_free) { @@ -2772,7 +1541,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL)); } break; @@ -2788,7 +1557,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_CONV_RESULT: { mono_mb_emit_byte (mb, CEE_POP); char *msg = g_strdup_printf ("Cannot marshal 'return value': Invalid managed/unmanaged type combination."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -2803,12 +1572,12 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { char *msg = g_strdup ("Byref array marshalling to managed code is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } if (!spec) { char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } @@ -2819,14 +1588,14 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, #ifndef DISABLE_COM if (spec->data.safearray_data.elem_type != MONO_VARIANT_VARIANT) { char *msg = g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); #endif default: { char *msg = g_strdup ("Unsupported array type marshalling to managed code."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } } @@ -2843,7 +1612,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (param_num == -1) { if (num_elem <= 0) { char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } } @@ -2880,7 +1649,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (param_num != -1) { if (param_num >= m->sig->param_count) { char *msg = g_strdup ("Array size control parameter index is out of range."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } switch (m->sig->params [param_num]->type) { @@ -2897,7 +1666,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, break; default: { char *msg = g_strdup ("Array size control parameter must be an integral type."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } } @@ -2949,7 +1718,7 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, #ifdef DISABLE_NONBLITTABLE else { char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); } #else /* Emit marshalling loop */ @@ -2972,12 +1741,12 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, src_ptr); mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); mono_mb_emit_byte (mb, CEE_STELEM_REF); } else { char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } @@ -3095,12 +1864,12 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_LDELEM_REF); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); mono_mb_emit_byte (mb, stind_op); } else { char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } @@ -3192,12 +1961,12 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_LDELEM_REF); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); mono_mb_emit_byte (mb, stind_op); } else { char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; } @@ -3230,7 +1999,7 @@ emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type_internal (t->data.type)->blittable) { char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1); - mono_mb_emit_exception_marshal_directive (m->mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (m->mb, msg); } */ break; @@ -4577,26 +3346,6 @@ emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, Mono mono_mb_emit_byte (mb, CEE_RET); } -static void -emit_marshal_custom_get_instance (MonoMethodBuilder *mb, MonoClass *klass, MonoMarshalSpec *spec) -{ - MONO_STATIC_POINTER_INIT (MonoMethod, get_instance) - - MonoClass *Marshal = mono_class_try_get_marshal_class (); - g_assert (Marshal); - get_instance = get_method_nofail (Marshal, "GetCustomMarshalerInstance", 2, 0); - g_assert (get_instance); - - MONO_STATIC_POINTER_INIT_END (MonoClass, get_instance) - - // HACK: We cannot use ldtoken in this type of wrapper. - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - mono_mb_emit_icall (mb, mono_marshal_get_type_object); - mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - - mono_mb_emit_op (mb, CEE_CALL, get_instance); -} static int emit_marshal_custom_ilgen_throw_exception (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg, MarshalAction action) @@ -4648,16 +3397,16 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (!klass) return emit_marshal_custom_ilgen_throw_exception (mb, "System", "ApplicationException", g_strdup ("Current profile doesn't support ICustomMarshaler"), action); - cleanup_native = get_method_nofail (klass, "CleanUpNativeData", 1, 0); + cleanup_native = mono_marshal_shared_get_method_nofail (klass, "CleanUpNativeData", 1, 0); g_assert (cleanup_native); - cleanup_managed = get_method_nofail (klass, "CleanUpManagedData", 1, 0); + cleanup_managed = mono_marshal_shared_get_method_nofail (klass, "CleanUpManagedData", 1, 0); g_assert (cleanup_managed); - marshal_managed_to_native = get_method_nofail (klass, "MarshalManagedToNative", 1, 0); + marshal_managed_to_native = mono_marshal_shared_get_method_nofail (klass, "MarshalManagedToNative", 1, 0); g_assert (marshal_managed_to_native); - marshal_native_to_managed = get_method_nofail (klass, "MarshalNativeToManaged", 1, 0); + marshal_native_to_managed = mono_marshal_shared_get_method_nofail (klass, "MarshalNativeToManaged", 1, 0); g_assert (marshal_native_to_managed); mono_memory_barrier (); @@ -4710,7 +3459,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_LDIND_I); pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) @@ -4740,7 +3489,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) { mono_mb_emit_ldarg (mb, argnum); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_byte (mb, CEE_DUP); mono_mb_emit_ldarg (mb, argnum); @@ -4753,13 +3502,13 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { mono_mb_emit_ldarg (mb, argnum); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); mono_mb_emit_byte (mb, CEE_STIND_REF); } else if (t->attrs & PARAM_ATTRIBUTE_OUT) { - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); @@ -4770,7 +3519,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, // Only call cleanup_native if MARSHAL_ACTION_CONV_IN called marshal_managed_to_native. if (!(m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) && !(!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))) { - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldloc (mb, conv_arg); @@ -4794,7 +3543,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, 3); pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldloc (mb, 3); mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); @@ -4834,7 +3583,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_LDIND_I); pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) @@ -4860,7 +3609,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, 3); pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_byte (mb, CEE_DUP); mono_mb_emit_ldloc (mb, 3); @@ -4882,7 +3631,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { mono_mb_emit_ldarg (mb, argnum); - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); @@ -4891,7 +3640,7 @@ emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, // Only call cleanup_managed if MARSHAL_ACTION_MANAGED_CONV_IN called marshal_native_to_managed. if (!(m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { - emit_marshal_custom_get_instance (mb, mklass, spec); + mono_marshal_shared_emit_marshal_custom_get_instance (mb, mklass, spec); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); } @@ -4985,7 +3734,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, m->csig->params [argnum - m->csig->hasthis] = double_type; MONO_STATIC_POINTER_INIT (MonoMethod, to_oadate) - to_oadate = get_method_nofail (date_time_class, "ToOADate", 0, 0); + to_oadate = mono_marshal_shared_get_method_nofail (date_time_class, "ToOADate", 0, 0); g_assert (to_oadate); MONO_STATIC_POINTER_INIT_END (MonoMethod, to_oadate) @@ -5030,7 +3779,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); } if (m_type_is_byref (t)) @@ -5081,7 +3830,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { MONO_STATIC_POINTER_INIT (MonoMethod, from_oadate) - from_oadate = get_method_nofail (date_time_class, "FromOADate", 1, 0); + from_oadate = mono_marshal_shared_get_method_nofail (date_time_class, "FromOADate", 1, 0); MONO_STATIC_POINTER_INIT_END (MonoMethod, from_oadate) g_assert (from_oadate); @@ -5111,7 +3860,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 0); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); } } @@ -5137,7 +3886,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); break; case MARSHAL_ACTION_MANAGED_CONV_IN: @@ -5166,7 +3915,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); if (m_type_is_byref (t)) mono_mb_patch_branch (mb, pos); @@ -5191,7 +3940,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); mono_mb_patch_branch (mb, pos2); break; @@ -5222,7 +3971,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, m->retobj_var); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); break; default: @@ -5231,7 +3980,7 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, return conv_arg; } -static inline void +static void emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv) { if (conv == MONO_MARSHAL_CONV_BSTR_STR || conv == MONO_MARSHAL_CONV_ANSIBSTR_STR || conv == MONO_MARSHAL_CONV_TBSTR_STR) @@ -5270,9 +4019,9 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); } else { - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); mono_mb_emit_stloc (mb, conv_arg); } @@ -5282,7 +4031,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); if (conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -5290,13 +4039,13 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (!m_type_is_byref (t)) { char *msg = g_strdup ("VBByRefStr marshalling requires a ref parameter."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } MONO_STATIC_POINTER_INIT (MonoMethod, method) - method = get_method_nofail (mono_defaults.string_class, "get_Length", -1, 0); + method = mono_marshal_shared_get_method_nofail (mono_defaults.string_class, "get_Length", -1, 0); MONO_STATIC_POINTER_INIT_END (MonoMethod, method) @@ -5316,7 +4065,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, int stind_op; mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); mono_mb_emit_byte (mb, stind_op); need_free = TRUE; } @@ -5340,12 +4089,12 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); if (conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); mono_mb_emit_stloc (mb, 3); /* free the string */ @@ -5366,14 +4115,14 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); if (conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); mono_mb_emit_stloc (mb, conv_arg); break; @@ -5383,18 +4132,18 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, int stind_op; mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, &stind_op)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); mono_mb_emit_byte (mb, stind_op); } } break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if (conv_to_icall (conv, NULL) == MONO_JIT_ICALL_mono_marshal_string_to_utf16) + if (mono_marshal_shared_conv_to_icall (conv, NULL) == MONO_JIT_ICALL_mono_marshal_string_to_utf16) /* We need to make a copy so the caller is able to free it */ mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy); else - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); mono_mb_emit_stloc (mb, 3); break; @@ -5421,8 +4170,8 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, conv_arg = mono_mb_add_local (mb, int_type); *conv_arg_type = int_type; - if (!sh_dangerous_add_ref) - init_safe_handle (); + if (!*mono_marshal_shared_get_sh_dangerous_add_ref()) + mono_marshal_shared_init_safe_handle (); mono_mb_emit_ldarg (mb, argnum); pos = mono_mb_emit_branch (mb, CEE_BRTRUE); @@ -5440,7 +4189,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { int old_handle_value_slot = mono_mb_add_local (mb, int_type); - if (!is_in (t)) { + if (!mono_marshal_shared_is_in (t)) { mono_mb_emit_icon (mb, 0); mono_mb_emit_stloc (mb, conv_arg); } else { @@ -5448,7 +4197,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_ldloc_addr (mb, dar_release_slot); - mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_add_ref(), NULL); /* Pull the handle field from SafeHandle */ mono_mb_emit_ldarg (mb, argnum); @@ -5463,7 +4212,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, /* safehandle.DangerousAddRef (ref release) */ mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc_addr (mb, dar_release_slot); - mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_add_ref(), NULL); /* Pull the handle field from SafeHandle */ mono_mb_emit_ldarg (mb, argnum); @@ -5487,21 +4236,21 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, int dar_release_slot = conv_arg + 1; int label_next = 0; - if (!sh_dangerous_release) - init_safe_handle (); + if (!*mono_marshal_shared_get_sh_dangerous_release()) + mono_marshal_shared_init_safe_handle (); if (m_type_is_byref (t)) { /* If there was SafeHandle on input we have to release the reference to it */ - if (is_in (t)) { + if (mono_marshal_shared_is_in (t)) { mono_mb_emit_ldloc (mb, dar_release_slot); label_next = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_release (), NULL); mono_mb_patch_branch (mb, label_next); } - if (is_out (t)) { + if (mono_marshal_shared_is_out (t)) { ERROR_DECL (local_error); MonoMethod *ctor; @@ -5509,7 +4258,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, * If the SafeHandle was marshalled on input we can skip the marshalling on * output if the handle value is identical. */ - if (is_in (t)) { + if (mono_marshal_shared_is_in (t)) { int old_handle_value_slot = dar_release_slot + 1; mono_mb_emit_ldloc (mb, old_handle_value_slot); mono_mb_emit_ldloc (mb, conv_arg); @@ -5542,7 +4291,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_byte (mb, CEE_STIND_I); - if (is_in (t) && label_next) { + if (mono_marshal_shared_is_in (t) && label_next) { mono_mb_patch_branch (mb, label_next); } } @@ -5550,7 +4299,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, dar_release_slot); label_next = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL); + mono_mb_emit_managed_call (mb, *mono_marshal_shared_get_sh_dangerous_release (), NULL); mono_mb_patch_branch (mb, label_next); } break; @@ -5563,7 +4312,7 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (mono_class_is_abstract (t->data.klass)) { mono_mb_emit_byte (mb, CEE_POP); - mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); break; } @@ -5607,7 +4356,6 @@ emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, return conv_arg; } - static int emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, @@ -5623,7 +4371,7 @@ emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } mono_mb_emit_ldarg_addr (mb, argnum); @@ -5645,7 +4393,7 @@ emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_CONV_RESULT: { char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -5666,7 +4414,6 @@ emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, return conv_arg; } - static int emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, @@ -5687,7 +4434,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (mono_class_from_mono_type_internal (t) == mono_defaults.object_class) { char *msg = g_strdup_printf ("Marshalling of type object is not implemented"); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -5695,13 +4442,13 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); } mono_mb_emit_byte (mb, CEE_LDNULL); mono_mb_emit_stloc (mb, conv_arg); } else { mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); mono_mb_emit_stloc (mb, conv_arg); } } else if (klass == mono_class_try_get_stringbuilder_class ()) { @@ -5712,7 +4459,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) { if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); } break; } @@ -5723,7 +4470,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (conv == MONO_MARSHAL_CONV_INVALID) { char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -5731,7 +4478,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); mono_mb_emit_stloc (mb, conv_arg); } else if (m_class_is_blittable (klass)) { mono_mb_emit_byte (mb, CEE_LDNULL); @@ -5792,7 +4539,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); mono_mb_patch_branch (mb, pos); } @@ -5836,7 +4583,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); } if (need_free) { @@ -5852,7 +4599,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); mono_mb_emit_byte (mb, CEE_STIND_REF); } break; @@ -5888,7 +4635,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 0); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); /* Free the structure returned by the native code */ emit_struct_free (mb, klass, conv_arg); @@ -5935,12 +4682,12 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); mono_mb_emit_stloc (mb, 3); } else if (klass == mono_class_try_get_stringbuilder_class ()) { // FIXME: char *msg = g_strdup_printf ("Return marshalling of stringbuilders is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); } else { /* set src */ mono_mb_emit_stloc (mb, 0); @@ -5969,7 +4716,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit conversion code */ - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); emit_struct_free (mb, klass, loc); @@ -5989,7 +4736,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); if (m_type_is_byref (t)) mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); mono_mb_emit_stloc (mb, conv_arg); break; } @@ -6053,7 +4800,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); mono_mb_patch_branch (mb, pos); break; @@ -6064,7 +4811,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, int stind_op; mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op)); mono_mb_emit_byte (mb, stind_op); break; } @@ -6098,7 +4845,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_STIND_I); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); mono_mb_patch_branch (mb, pos2); } else if (klass == mono_class_try_get_stringbuilder_class ()) { @@ -6118,13 +4865,13 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); } break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: if (m_class_is_delegate (klass)) { - mono_mb_emit_icall_id (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); mono_mb_emit_stloc (mb, 3); break; } @@ -6158,7 +4905,7 @@ emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 1); mono_mb_emit_stloc (mb, 3); - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); mono_mb_patch_branch (mb, pos2); break; @@ -6223,7 +4970,7 @@ emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_CONV_RESULT: { char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -6258,7 +5005,7 @@ emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, case MARSHAL_ACTION_MANAGED_CONV_RESULT: { char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); break; } @@ -6587,7 +5334,7 @@ emit_struct_to_ptr_ilgen (MonoMethodBuilder *mb, MonoClass *klass) mono_mb_emit_byte (mb, CEE_LDARG_1); mono_mb_emit_stloc (mb, 1); - emit_struct_conv (mb, klass, FALSE); + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); } mono_mb_emit_byte (mb, CEE_RET); @@ -6620,7 +5367,7 @@ emit_ptr_to_struct_ilgen (MonoMethodBuilder *mb, MonoClass *klass) mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); mono_mb_emit_stloc (mb, 1); - emit_struct_conv (mb, klass, TRUE); + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); } mono_mb_emit_byte (mb, CEE_RET); @@ -6908,7 +5655,7 @@ emit_marshal_directive_exception_ilgen (EmitMarshalContext *m, int argnum, const else fullmsg = g_strdup_printf("Error marshalling parameter #%d: %s", argnum, msg); - mono_mb_emit_exception_marshal_directive (m->mb, fullmsg); + mono_marshal_shared_mb_emit_exception_marshal_directive (m->mb, fullmsg); } static void diff --git a/src/mono/mono/metadata/marshal-shared.c b/src/mono/mono/metadata/marshal-shared.c new file mode 100644 index 00000000000000..9d8f37bfa86346 --- /dev/null +++ b/src/mono/mono/metadata/marshal-shared.c @@ -0,0 +1,1276 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include "metadata/marshal-shared.h" +#include "mono/metadata/debug-helpers.h" +#include "metadata/marshal.h" +#include "metadata/marshal-shared.h" +#include "metadata/method-builder-ilgen.h" +#include "metadata/custom-attrs-internals.h" +#include "metadata/class-init.h" +#include "mono/metadata/class-internals.h" +#include "metadata/reflection-internals.h" +#include "mono/metadata/handle.h" + + +#define OPDEF(a,b,c,d,e,f,g,h,i,j) \ + a = i, + +enum { +#include "mono/cil/opcode.def" + LAST = 0xff +}; +#undef OPDEF + +static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute, "System.Runtime.CompilerServices", "FixedBufferAttribute"); +static GENERATE_TRY_GET_CLASS_WITH_CACHE (marshal, "System.Runtime.InteropServices", "Marshal"); + +/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */ +static MonoMethod *sh_dangerous_add_ref; +static MonoMethod *sh_dangerous_release; + + +MonoMethod** + mono_marshal_shared_get_sh_dangerous_add_ref (void) +{ + return &sh_dangerous_add_ref; +} + +MonoMethod** mono_marshal_shared_get_sh_dangerous_release (void) +{ + return &sh_dangerous_release; +} + +// On legacy Mono, LPTSTR was either UTF16 or UTF8 depending on platform +static inline MonoJitICallId +mono_string_to_platform_unicode (void) +{ +#ifdef TARGET_WIN32 + return MONO_JIT_ICALL_mono_marshal_string_to_utf16; +#else + return MONO_JIT_ICALL_mono_string_to_utf8str; +#endif +} + +static inline MonoJitICallId +mono_string_from_platform_unicode (void) +{ +#ifdef TARGET_WIN32 + return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16; +#else + return MONO_JIT_ICALL_ves_icall_string_new_wrapper; +#endif +} + +static inline MonoJitICallId +mono_string_builder_to_platform_unicode (void) +{ +#ifdef TARGET_WIN32 + return MONO_JIT_ICALL_mono_string_builder_to_utf16; +#else + return MONO_JIT_ICALL_mono_string_builder_to_utf8; +#endif +} + +static inline MonoJitICallId +mono_string_builder_from_platform_unicode (void) +{ +#ifdef TARGET_WIN32 + return MONO_JIT_ICALL_mono_string_utf16_to_builder; +#else + return MONO_JIT_ICALL_mono_string_utf8_to_builder; +#endif +} + +void +mono_marshal_shared_emit_marshal_custom_get_instance (MonoMethodBuilder *mb, MonoClass *klass, MonoMarshalSpec *spec) +{ + MONO_STATIC_POINTER_INIT (MonoMethod, get_instance) + + MonoClass *Marshal = mono_class_try_get_marshal_class (); + g_assert (Marshal); + get_instance = mono_marshal_shared_get_method_nofail (Marshal, "GetCustomMarshalerInstance", 2, 0); + g_assert (get_instance); + + MONO_STATIC_POINTER_INIT_END (MonoClass, get_instance) + + // HACK: We cannot use ldtoken in this type of wrapper. + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_icall (mb, mono_marshal_get_type_object); + mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); + + mono_mb_emit_op (mb, CEE_CALL, get_instance); +} + +void +mono_marshal_shared_init_safe_handle (void) +{ + mono_atomic_store_seq (mono_marshal_shared_get_sh_dangerous_add_ref(), mono_marshal_shared_get_method_nofail (mono_class_try_get_safehandle_class (), "DangerousAddRef", 1, 0)); + mono_atomic_store_seq (mono_marshal_shared_get_sh_dangerous_release(), mono_marshal_shared_get_method_nofail (mono_class_try_get_safehandle_class (), "DangerousRelease", 0, 0)); +} + +void +mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass) +{ + 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)); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); +} + +gboolean +mono_marshal_shared_is_in (const MonoType *t) +{ + const guint32 attrs = t->attrs; + return (attrs & PARAM_ATTRIBUTE_IN) || !(attrs & PARAM_ATTRIBUTE_OUT); +} + +gboolean +mono_marshal_shared_is_out (const MonoType *t) +{ + const guint32 attrs = t->attrs; + return (attrs & PARAM_ATTRIBUTE_OUT) || !(attrs & PARAM_ATTRIBUTE_IN); +} + +MonoMarshalConv +mono_marshal_shared_conv_str_inverse (MonoMarshalConv conv) +{ + switch (conv) { + // AnsiBStr + case MONO_MARSHAL_CONV_STR_ANSIBSTR: + return MONO_MARSHAL_CONV_ANSIBSTR_STR; + case MONO_MARSHAL_CONV_ANSIBSTR_STR: + return MONO_MARSHAL_CONV_STR_ANSIBSTR; + + // BStr + case MONO_MARSHAL_CONV_STR_BSTR: + return MONO_MARSHAL_CONV_BSTR_STR; + case MONO_MARSHAL_CONV_BSTR_STR: + return MONO_MARSHAL_CONV_STR_BSTR; + + // LPStr + case MONO_MARSHAL_CONV_STR_LPSTR: + return MONO_MARSHAL_CONV_LPSTR_STR; + case MONO_MARSHAL_CONV_LPSTR_STR: + return MONO_MARSHAL_CONV_STR_LPSTR; + + // LPTStr + case MONO_MARSHAL_CONV_STR_LPTSTR: + return MONO_MARSHAL_CONV_LPTSTR_STR; + case MONO_MARSHAL_CONV_LPTSTR_STR: + return MONO_MARSHAL_CONV_STR_LPTSTR; + + // LPUTF8Str + case MONO_MARSHAL_CONV_STR_UTF8STR: + return MONO_MARSHAL_CONV_UTF8STR_STR; + case MONO_MARSHAL_CONV_UTF8STR_STR: + return MONO_MARSHAL_CONV_STR_UTF8STR; + + // LPWStr + case MONO_MARSHAL_CONV_STR_LPWSTR: + return MONO_MARSHAL_CONV_LPWSTR_STR; + case MONO_MARSHAL_CONV_LPWSTR_STR: + return MONO_MARSHAL_CONV_STR_LPWSTR; + + // TBStr + case MONO_MARSHAL_CONV_STR_TBSTR: + return MONO_MARSHAL_CONV_TBSTR_STR; + case MONO_MARSHAL_CONV_TBSTR_STR: + return MONO_MARSHAL_CONV_STR_TBSTR; + + default: + g_assert_not_reached (); + } +} + +/* + * mono_marshal_shared_mb_emit_exception_marshal_directive: + * + * This function assumes ownership of MSG, which should be malloc-ed. + */ +void +mono_marshal_shared_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg) +{ + char *s = mono_mb_strdup (mb, msg); + g_free (msg); + mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", s); +} + +gboolean +mono_marshal_shared_get_fixed_buffer_attr (MonoClassField *field, MonoType **out_etype, int *out_len) +{ + ERROR_DECL (error); + MonoCustomAttrInfo *cinfo; + MonoCustomAttrEntry *attr; + int aindex; + + cinfo = mono_custom_attrs_from_field_checked (m_field_get_parent (field), field, error); + if (!is_ok (error)) + return FALSE; + attr = NULL; + if (cinfo) { + for (aindex = 0; aindex < cinfo->num_attrs; ++aindex) { + MonoClass *ctor_class = cinfo->attrs [aindex].ctor->klass; + if (mono_class_has_parent (ctor_class, mono_class_get_fixed_buffer_attribute_class ())) { + attr = &cinfo->attrs [aindex]; + break; + } + } + } + if (attr) { + gpointer *typed_args, *named_args; + CattrNamedArg *arginfo; + int num_named_args; + + mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, + &typed_args, &named_args, &num_named_args, &arginfo, error); + if (!is_ok (error)) + return FALSE; + *out_etype = (MonoType*)typed_args [0]; + *out_len = *(gint32*)typed_args [1]; + g_free (typed_args [1]); + g_free (typed_args); + g_free (named_args); + g_free (arginfo); + } + if (cinfo && !cinfo->cached) + mono_custom_attrs_free (cinfo); + return attr != NULL; +} + +void +mono_marshal_shared_emit_fixed_buf_conv (MonoMethodBuilder *mb, MonoType *type, MonoType *etype, int len, gboolean to_object, int *out_usize) +{ + MonoClass *klass = mono_class_from_mono_type_internal (type); + MonoClass *eklass = mono_class_from_mono_type_internal (etype); + int esize; + + esize = mono_class_native_size (eklass, NULL); + + MonoMarshalNative string_encoding = m_class_is_unicode (klass) ? MONO_NATIVE_LPWSTR : MONO_NATIVE_LPSTR; + int usize = mono_class_value_size (eklass, NULL); + int msize = mono_class_value_size (eklass, NULL); + + //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), em_class_is_blittable (klass), string_encoding); + + if (m_class_is_blittable (eklass)) { + /* copy the elements */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, len * esize); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + } else { + int index_var; + guint32 label2, label3; + + /* Emit marshalling loop */ + MonoType *int_type = mono_get_int_type (); + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + + /* Loop header */ + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_icon (mb, len); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* src/dst is already set */ + + /* Do the conversion */ + MonoTypeEnum t = etype->type; + switch (t) { + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_CHAR: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_PTR: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + if (t == MONO_TYPE_CHAR && string_encoding != MONO_NATIVE_LPWSTR) { + if (to_object) { + mono_mb_emit_byte (mb, CEE_LDIND_U1); + mono_mb_emit_byte (mb, CEE_STIND_I2); + } else { + mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_byte (mb, CEE_STIND_I1); + } + usize = 1; + } else { + mono_mb_emit_byte (mb, mono_type_to_ldind (etype)); + mono_mb_emit_byte (mb, mono_type_to_stind (etype)); + } + break; + default: + g_assert_not_reached (); + break; + } + + if (to_object) { + mono_mb_emit_add_to_local (mb, 0, usize); + mono_mb_emit_add_to_local (mb, 1, msize); + } else { + mono_mb_emit_add_to_local (mb, 0, msize); + mono_mb_emit_add_to_local (mb, 1, usize); + } + + /* Loop footer */ + mono_mb_emit_add_to_local (mb, index_var, 1); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + } + + *out_usize = usize * len; +} + +int +mono_marshal_shared_offset_of_first_nonstatic_field (MonoClass *klass) +{ + mono_class_setup_fields (klass); + gpointer iter = NULL; + MonoClassField *field; + while ((field = mono_class_get_fields_internal (klass, &iter))) { + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (field)) { + /* + * metadata-update: adding fields to existing structs isn't supported. In + * newly-added structs, the "from update" field won't be set. + */ + g_assert (!m_field_is_from_update (field)); + return m_field_get_offset (field) - MONO_ABI_SIZEOF (MonoObject); + } + } + + return 0; +} + +// FIXME Consolidate the multiple functions named get_method_nofail. +MonoMethod* +mono_marshal_shared_get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags) +{ + MonoMethod *method; + ERROR_DECL (error); + method = mono_class_get_method_from_name_checked (klass, method_name, num_params, flags, error); + mono_error_assert_ok (error); + g_assertf (method, "Could not lookup method %s in %s", method_name, m_class_get_name (klass)); + return method; +} + +MonoJitICallId +mono_marshal_shared_conv_to_icall (MonoMarshalConv conv, int *ind_store_type) +{ + // FIXME This or its caller might be a good place to inline some + // of the wrapper logic. In particular, to produce + // volatile stack-based handles. Being data-driven, + // from icall-def.h. + + int dummy; + if (!ind_store_type) + ind_store_type = &dummy; + *ind_store_type = CEE_STIND_I; + switch (conv) { + // AnsiBStr + case MONO_MARSHAL_CONV_STR_ANSIBSTR: + return MONO_JIT_ICALL_mono_string_to_ansibstr; + case MONO_MARSHAL_CONV_ANSIBSTR_STR: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_string_from_ansibstr; + + // BStr + case MONO_MARSHAL_CONV_STR_BSTR: + return MONO_JIT_ICALL_mono_string_to_bstr; + case MONO_MARSHAL_CONV_BSTR_STR: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_string_from_bstr_icall; + + // LPStr + // In Mono, LPSTR was historically treated as UTF8STR + case MONO_MARSHAL_CONV_STR_LPSTR: + return MONO_JIT_ICALL_mono_string_to_utf8str; + case MONO_MARSHAL_CONV_LPSTR_STR: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_ves_icall_string_new_wrapper; + case MONO_MARSHAL_CONV_SB_LPSTR: + return MONO_JIT_ICALL_mono_string_builder_to_utf8; + case MONO_MARSHAL_CONV_LPSTR_SB: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_string_utf8_to_builder; + + // LPTStr + // FIXME: This is how LPTStr was handled on legacy, but it's not correct and for netcore we should implement this more properly. + // This type is supposed to detect ANSI or UTF16 (as LPTStr can be either depending on _UNICODE) and handle it accordingly. + // The CoreCLR test for this type only tests as LPWSTR regardless of platform. + case MONO_MARSHAL_CONV_STR_LPTSTR: + return mono_string_to_platform_unicode (); + case MONO_MARSHAL_CONV_LPTSTR_STR: + *ind_store_type = CEE_STIND_REF; + return mono_string_from_platform_unicode (); + case MONO_MARSHAL_CONV_SB_LPTSTR: + return mono_string_builder_to_platform_unicode (); + case MONO_MARSHAL_CONV_LPTSTR_SB: + *ind_store_type = CEE_STIND_REF; + return mono_string_builder_from_platform_unicode (); + + // LPUTF8Str + case MONO_MARSHAL_CONV_STR_UTF8STR: + return MONO_JIT_ICALL_mono_string_to_utf8str; + case MONO_MARSHAL_CONV_UTF8STR_STR: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_ves_icall_string_new_wrapper; + case MONO_MARSHAL_CONV_SB_UTF8STR: + return MONO_JIT_ICALL_mono_string_builder_to_utf8; + case MONO_MARSHAL_CONV_UTF8STR_SB: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_string_utf8_to_builder; + + // LPWStr + case MONO_MARSHAL_CONV_STR_LPWSTR: + return MONO_JIT_ICALL_mono_marshal_string_to_utf16; + case MONO_MARSHAL_CONV_LPWSTR_STR: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16; + case MONO_MARSHAL_CONV_SB_LPWSTR: + return MONO_JIT_ICALL_mono_string_builder_to_utf16; + case MONO_MARSHAL_CONV_LPWSTR_SB: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_string_utf16_to_builder; + + // TBStr + case MONO_MARSHAL_CONV_STR_TBSTR: + return MONO_JIT_ICALL_mono_string_to_tbstr; + case MONO_MARSHAL_CONV_TBSTR_STR: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_string_from_tbstr; + + case MONO_MARSHAL_CONV_STR_BYVALSTR: + return MONO_JIT_ICALL_mono_string_to_byvalstr; + case MONO_MARSHAL_CONV_STR_BYVALWSTR: + return MONO_JIT_ICALL_mono_string_to_byvalwstr; + + case MONO_MARSHAL_CONV_DEL_FTN: + return MONO_JIT_ICALL_mono_delegate_to_ftnptr; + case MONO_MARSHAL_CONV_FTN_DEL: + *ind_store_type = CEE_STIND_REF; + return MONO_JIT_ICALL_mono_ftnptr_to_delegate; + + case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: + return MONO_JIT_ICALL_mono_array_to_savearray; + case MONO_MARSHAL_FREE_ARRAY: + return MONO_JIT_ICALL_mono_marshal_free_array; + + case MONO_MARSHAL_CONV_ARRAY_LPARRAY: + return MONO_JIT_ICALL_mono_array_to_lparray; + case MONO_MARSHAL_FREE_LPARRAY: + return MONO_JIT_ICALL_mono_free_lparray; + + default: + g_assert_not_reached (); + } + + return MONO_JIT_ICALL_ZeroIsReserved; +} + +void +mono_marshal_shared_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec) +{ + switch (conv) { + case MONO_MARSHAL_CONV_BOOL_I4: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_BRFALSE_S); + mono_mb_emit_byte (mb, 3); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_BR_S); + mono_mb_emit_byte (mb, 1); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_STIND_I1); + break; + case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I2); + mono_mb_emit_byte (mb, CEE_BRFALSE_S); + mono_mb_emit_byte (mb, 3); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_BR_S); + mono_mb_emit_byte (mb, 1); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_STIND_I1); + break; + case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: { + MonoClass *eklass = NULL; + int esize; + + if (type->type == MONO_TYPE_SZARRAY) { + eklass = type->data.klass; + } else { + g_assert_not_reached (); + } + + esize = mono_class_native_size (eklass, NULL); + + /* create a new array */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_op (mb, CEE_NEWARR, eklass); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + if (m_class_is_blittable (eklass)) { + /* copy the elements */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + } + else { + int array_var, src_var, dst_var, index_var; + guint32 label2, label3; + + MonoType *int_type = mono_get_int_type (); + array_var = mono_mb_add_local (mb, mono_get_object_type ()); + src_var = mono_mb_add_local (mb, int_type); + dst_var = mono_mb_add_local (mb, int_type); + + /* set array_var */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_stloc (mb, array_var); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + + /* Loop header */ + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* src is already set */ + + /* Set dst */ + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 1); + + /* Do the conversion */ + mono_marshal_shared_emit_struct_conv (mb, eklass, TRUE); + + /* Loop footer */ + mono_mb_emit_add_to_local (mb, index_var, 1); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + } + break; + } + case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: { + MonoClass *eclass = mono_defaults.char_class; + + /* create a new array */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_op (mb, CEE_NEWARR, eclass); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_icall (mb, mono_byvalarray_to_byte_array); + break; + } + case MONO_MARSHAL_CONV_STR_BYVALSTR: + if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_icall (mb, mono_string_from_byvalstr); + } else { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icall (mb, ves_icall_string_new_wrapper); + } + mono_mb_emit_byte (mb, CEE_STIND_REF); + break; + case MONO_MARSHAL_CONV_STR_BYVALWSTR: + if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_icall (mb, mono_string_from_byvalwstr); + } else { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16); + } + mono_mb_emit_byte (mb, CEE_STIND_REF); + break; + + case MONO_MARSHAL_CONV_STR_ANSIBSTR: + case MONO_MARSHAL_CONV_STR_TBSTR: + case MONO_MARSHAL_CONV_STR_UTF8STR: + case MONO_MARSHAL_CONV_STR_LPWSTR: + case MONO_MARSHAL_CONV_STR_LPSTR: + case MONO_MARSHAL_CONV_STR_LPTSTR: + case MONO_MARSHAL_CONV_STR_BSTR: { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (mono_marshal_shared_conv_str_inverse (conv), NULL)); + mono_mb_emit_byte (mb, CEE_STIND_REF); + break; + } + + case MONO_MARSHAL_CONV_OBJECT_STRUCT: { + MonoClass *klass = mono_class_from_mono_type_internal (type); + int src_var, dst_var; + + MonoType *int_type = mono_get_int_type (); + src_var = mono_mb_add_local (mb, int_type); + dst_var = mono_mb_add_local (mb, int_type); + + /* *dst = new object */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + /* dst = pointer to newly created object data */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_stloc (mb, 1); + + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + break; + } + case MONO_MARSHAL_CONV_DEL_FTN: { + MonoClass *klass = mono_class_from_mono_type_internal (type); + + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icall (mb, mono_ftnptr_to_delegate); + mono_mb_emit_byte (mb, CEE_STIND_REF); + break; + } + case MONO_MARSHAL_CONV_ARRAY_LPARRAY: { + 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))); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + +#ifndef DISABLE_COM + case MONO_MARSHAL_CONV_OBJECT_INTERFACE: + case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: + case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: + mono_cominterop_emit_ptr_to_object_conv (mb, type, conv, mspec); + break; +#endif /* DISABLE_COM */ + + case MONO_MARSHAL_CONV_SAFEHANDLE: { + /* + * Passing SafeHandles as ref does not allow the unmanaged code + * to change the SafeHandle value. If the value is changed, + * we should issue a diagnostic exception (NotSupportedException) + * that informs the user that changes to handles in unmanaged code + * is not supported. + * + * Since we currently have no access to the original + * SafeHandle that was used during the marshalling, + * for now we just ignore this, and ignore/discard any + * changes that might have happened to the handle. + */ + break; + } + + case MONO_MARSHAL_CONV_HANDLEREF: { + /* + * Passing HandleRefs in a struct that is ref()ed does not + * copy the values back to the HandleRef + */ + break; + } + + case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: + default: { + char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv); + + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + } +} + +void +mono_marshal_shared_emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, + int offset_of_first_child_field, MonoMarshalNative string_encoding) +{ + MonoMarshalType *info; + int i; + + if (m_class_get_parent (klass)) + mono_marshal_shared_emit_struct_conv_full (mb, m_class_get_parent (klass), to_object, mono_marshal_shared_offset_of_first_nonstatic_field (klass), string_encoding); + + info = mono_marshal_load_type_info (klass); + + if (info->native_size == 0) + return; + + if (m_class_is_blittable (klass)) { + int usize = mono_class_value_size (klass, NULL); + g_assert (usize == info->native_size); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, usize); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + + if (to_object) { + mono_mb_emit_add_to_local (mb, 0, usize); + mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field); + } else { + mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field); + mono_mb_emit_add_to_local (mb, 1, usize); + } + return; + } + + if (klass != mono_class_try_get_safehandle_class ()) { + if (mono_class_is_auto_layout (klass)) { + char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.", + mono_type_full_name (m_class_get_byval_arg (klass))); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return; + } + } + + for (i = 0; i < info->num_fields; i++) { + MonoMarshalNative ntype; + MonoMarshalConv conv; + MonoType *ftype = info->fields [i].field->type; + int msize = 0; + int usize = 0; + gboolean last_field = i < (info->num_fields -1) ? 0 : 1; + + if (ftype->attrs & FIELD_ATTRIBUTE_STATIC) + continue; + + ntype = (MonoMarshalNative)mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, m_class_is_unicode (klass), &conv); + + if (last_field) { + msize = m_class_get_instance_size (klass) - m_field_get_offset (info->fields [i].field); + usize = info->native_size - info->fields [i].offset; + } else { + msize = m_field_get_offset (info->fields [i + 1].field) - m_field_get_offset (info->fields [i].field); + usize = info->fields [i + 1].offset - info->fields [i].offset; + } + + if (klass != mono_class_try_get_safehandle_class ()){ + /* + * FIXME: Should really check for usize==0 and msize>0, but we apply + * the layout to the managed structure as well. + */ + + if (mono_class_is_explicit_layout (klass) && (usize == 0)) { + if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || + ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) + g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a " + "reference field at the same offset as another field.", + mono_type_full_name (m_class_get_byval_arg (klass))); + } + } + + switch (conv) { + case MONO_MARSHAL_CONV_NONE: { + int t; + + //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB + g_assert (!m_type_is_byref (ftype)); + if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + handle_enum: + t = ftype->type; + switch (t) { + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_CHAR: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_PTR: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + if (t == MONO_TYPE_CHAR && ntype == MONO_NATIVE_U1 && string_encoding != MONO_NATIVE_LPWSTR) { + if (to_object) { + mono_mb_emit_byte (mb, CEE_LDIND_U1); + mono_mb_emit_byte (mb, CEE_STIND_I2); + } else { + mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_byte (mb, CEE_STIND_I1); + } + } else { + mono_mb_emit_byte (mb, mono_type_to_ldind (ftype)); + mono_mb_emit_byte (mb, mono_type_to_stind (ftype)); + } + break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (ftype)) { + char *msg = g_strdup_printf ("Generic type %s cannot be marshaled as field in a struct.", + mono_type_full_name (ftype)); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + /* fall through */ + case MONO_TYPE_VALUETYPE: { + int src_var, dst_var; + MonoType *etype; + int len; + + if (t == MONO_TYPE_VALUETYPE && m_class_is_enumtype (ftype->data.klass)) { + ftype = mono_class_enum_basetype_internal (ftype->data.klass); + goto handle_enum; + } + + MonoType *int_type = mono_get_int_type (); + src_var = mono_mb_add_local (mb, int_type); + dst_var = mono_mb_add_local (mb, int_type); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + if (mono_marshal_shared_get_fixed_buffer_attr (info->fields [i].field, &etype, &len)) { + mono_marshal_shared_emit_fixed_buf_conv (mb, ftype, etype, len, to_object, &usize); + } else { + mono_marshal_shared_emit_struct_conv (mb, mono_class_from_mono_type_internal (ftype), to_object); + } + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + break; + } + case MONO_TYPE_OBJECT: { +#ifndef DISABLE_COM + if (to_object) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL); + } + else { + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte(mb, CEE_LDIND_REF); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); + } +#else + char *msg = g_strdup_printf ("COM support was disabled at compilation time."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); +#endif + break; + } + + default: + g_warning ("marshaling type %02x not implemented", ftype->type); + g_assert_not_reached (); + } + break; + } + default: { + int src_var, dst_var; + + MonoType *int_type = mono_get_int_type (); + src_var = mono_mb_add_local (mb, int_type); + dst_var = mono_mb_add_local (mb, int_type); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + if (to_object) + mono_marshal_shared_emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec); + else + mono_marshal_shared_emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + } + } + + if (to_object) { + mono_mb_emit_add_to_local (mb, 0, usize); + mono_mb_emit_add_to_local (mb, 1, msize); + } else { + mono_mb_emit_add_to_local (mb, 0, msize); + mono_mb_emit_add_to_local (mb, 1, usize); + } + } +} + +void +mono_marshal_shared_emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) +{ + mono_marshal_shared_emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1); +} + +void +mono_marshal_shared_emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, MonoJitICallId checkpoint_icall_id) +{ + int pos_noabort, pos_noex; + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_LDPTR_INT_REQ_FLAG); + mono_mb_emit_no_nullcheck (mb); + mono_mb_emit_byte (mb, CEE_LDIND_U4); + pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN); + + mono_mb_emit_icall_id (mb, checkpoint_icall_id); + /* Throw the exception returned by the checkpoint function, if any */ + mono_mb_emit_byte (mb, CEE_DUP); + pos_noex = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoException, caught_in_unmanaged)); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_no_nullcheck (mb); + mono_mb_emit_byte (mb, CEE_STIND_I4); + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_RETHROW); + + mono_mb_patch_branch (mb, pos_noex); + mono_mb_emit_byte (mb, CEE_POP); + + mono_mb_patch_branch (mb, pos_noabort); +} + +void +mono_marshal_shared_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec) +{ + int pos; + int stind_op; + + switch (conv) { + case MONO_MARSHAL_CONV_BOOL_I4: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_U1); + mono_mb_emit_byte (mb, CEE_STIND_I4); + break; + case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_U1); + mono_mb_emit_byte (mb, CEE_NEG); + mono_mb_emit_byte (mb, CEE_STIND_I2); + break; + case MONO_MARSHAL_CONV_STR_UTF8STR: + case MONO_MARSHAL_CONV_STR_LPWSTR: + case MONO_MARSHAL_CONV_STR_LPSTR: + case MONO_MARSHAL_CONV_STR_LPTSTR: + case MONO_MARSHAL_CONV_STR_BSTR: + case MONO_MARSHAL_CONV_STR_ANSIBSTR: + case MONO_MARSHAL_CONV_STR_TBSTR: { + /* free space if free == true */ + mono_mb_emit_ldloc (mb, 2); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icall (mb, g_free); // aka monoeg_g_free + mono_mb_patch_short_branch (mb, pos); + + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, stind_op); + break; + } + case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: + case MONO_MARSHAL_CONV_ARRAY_LPARRAY: + case MONO_MARSHAL_CONV_DEL_FTN: + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, &stind_op)); + mono_mb_emit_byte (mb, stind_op); + break; + case MONO_MARSHAL_CONV_STR_BYVALSTR: + case MONO_MARSHAL_CONV_STR_BYVALWSTR: { + g_assert (mspec); + + mono_mb_emit_ldloc (mb, 1); /* dst */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */ + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + break; + } + case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: { + MonoClass *eklass = NULL; + int esize; + + if (type->type == MONO_TYPE_SZARRAY) { + eklass = type->data.klass; + } else if (type->type == MONO_TYPE_ARRAY) { + eklass = type->data.array->eklass; + g_assert(m_class_is_blittable (eklass)); + } else { + g_assert_not_reached (); + } + + if (m_class_is_valuetype (eklass)) + esize = mono_class_native_size (eklass, NULL); + else + esize = TARGET_SIZEOF_VOID_P; + + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (m_class_is_blittable (eklass)) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + } else { + int array_var, src_var, dst_var, index_var; + guint32 label2, label3; + + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + array_var = mono_mb_add_local (mb, object_type); + src_var = mono_mb_add_local (mb, int_type); + dst_var = mono_mb_add_local (mb, int_type); + + /* set array_var */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_stloc (mb, array_var); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + + /* Loop header */ + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Set src */ + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 0); + + /* dst is already set */ + + /* Do the conversion */ + mono_marshal_shared_emit_struct_conv (mb, eklass, FALSE); + + /* Loop footer */ + mono_mb_emit_add_to_local (mb, index_var, 1); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + } + + mono_mb_patch_branch (mb, pos); + break; + } + case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: { + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); + mono_mb_emit_icall (mb, mono_array_to_byte_byvalarray); + mono_mb_patch_short_branch (mb, pos); + break; + } + case MONO_MARSHAL_CONV_OBJECT_STRUCT: { + int src_var, dst_var; + + MonoType *int_type = mono_get_int_type (); + src_var = mono_mb_add_local (mb, int_type); + dst_var = mono_mb_add_local (mb, int_type); + + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + /* src = pointer to object data */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_stloc (mb, 0); + + mono_marshal_shared_emit_struct_conv (mb, mono_class_from_mono_type_internal (type), FALSE); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + + mono_mb_patch_branch (mb, pos); + break; + } + +#ifndef DISABLE_COM + case MONO_MARSHAL_CONV_OBJECT_INTERFACE: + case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: + case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: + mono_cominterop_emit_object_to_ptr_conv (mb, type, conv, mspec); + break; +#endif /* DISABLE_COM */ + + case MONO_MARSHAL_CONV_SAFEHANDLE: { + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + mono_mb_patch_branch (mb, pos); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + case MONO_MARSHAL_CONV_HANDLEREF: { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + default: { + g_error ("marshalling conversion %d not implemented", conv); + } + } +} diff --git a/src/mono/mono/metadata/marshal-shared.h b/src/mono/mono/metadata/marshal-shared.h new file mode 100644 index 00000000000000..964b12bcda5c5f --- /dev/null +++ b/src/mono/mono/metadata/marshal-shared.h @@ -0,0 +1,77 @@ +/** +* \file +* Functionality shared between the legacy and DisableRuntimeMarshaling marshaling subsystems. +* +* Licensed to the .NET Foundation under one or more agreements. +* The .NET Foundation licenses this file to you under the MIT license. +*/ + +#include "mono/metadata/debug-helpers.h" +#include "metadata/marshal.h" +#include "metadata/method-builder-ilgen.h" +#include "metadata/custom-attrs-internals.h" +#include "metadata/class-init.h" +#include "mono/metadata/class-internals.h" +#include "metadata/reflection-internals.h" +#include "mono/metadata/handle.h" + +#ifndef _MONO_METADATA_MARSHAL_SHARED_H_ +#define _MONO_METADATA_MARSHAL_SHARED_H_ + +MonoMethod** mono_marshal_shared_get_sh_dangerous_add_ref (void); +MonoMethod** mono_marshal_shared_get_sh_dangerous_release (void); + +void +mono_marshal_shared_emit_marshal_custom_get_instance(MonoMethodBuilder *mb, MonoClass *klass, MonoMarshalSpec *spec); + +void +mono_marshal_shared_init_safe_handle (void); + +void +mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass); + +gboolean mono_marshal_shared_is_in (const MonoType *t); + +gboolean mono_marshal_shared_is_out (const MonoType *t); + +MonoMarshalConv +mono_marshal_shared_conv_str_inverse (MonoMarshalConv conv); + +void +mono_marshal_shared_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg); + +void +mono_marshal_shared_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec); + +gboolean +mono_marshal_shared_get_fixed_buffer_attr (MonoClassField *field, MonoType **out_etype, int *out_len); + +void +mono_marshal_shared_emit_fixed_buf_conv (MonoMethodBuilder *mb, MonoType *type, MonoType *etype, int len, gboolean to_object, int *out_usize); + +int +mono_marshal_shared_offset_of_first_nonstatic_field (MonoClass *klass); + +MonoMethod* +mono_marshal_shared_get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags); + +MonoJitICallId +mono_marshal_shared_conv_to_icall (MonoMarshalConv conv, int *ind_store_type); + +void +mono_marshal_shared_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec); + +void +mono_marshal_shared_emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, + int offset_of_first_child_field, MonoMarshalNative string_encoding); + +void +mono_marshal_shared_emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object); + +void +mono_marshal_shared_emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, MonoJitICallId checkpoint_icall_id); + +void +mono_marshal_shared_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec); + +#endif /* _MONO_METADATA_MARSHAL_SHARED_H_ */ \ No newline at end of file