diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 8bfc74906a06b..3f55fba76982e 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -91,8 +91,13 @@ set(metadata_common_sources lock-tracer.h marshal.c marshal.h + marshal-legacy.c + marshal-legacy.h + marshal-legacy-noilgen.c marshal-internals.h marshal-noilgen.c + marshal-shared.h + marshal-shared.c mempool.c mempool.h mempool-internals.h diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c index 9c391cf9ac76b..30bcf944fa3ba 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 @@ -75,44 +76,12 @@ 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); @@ -136,452 +105,6 @@ mono_mb_strdup (MonoMethodBuilder *mb, const char *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) @@ -674,711 +197,64 @@ conv_str_inverse (MonoMarshalConv conv) } } -static MonoJitICallId -conv_to_icall (MonoMarshalConv conv, int *ind_store_type) +#ifndef DISABLE_COM + +// FIXME There are multiple caches of "Clear". +G_GNUC_UNUSED +static MonoMethod* +mono_get_Variant_Clear (void) { - // 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; + MONO_STATIC_POINTER_INIT (MonoMethod, variant_clear) + variant_clear = mono_marshal_shared_get_method_nofail (mono_class_get_variant_class (), "Clear", 0, 0); + MONO_STATIC_POINTER_INIT_END (MonoMethod, variant_clear) - // 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; + g_assert (variant_clear); + return variant_clear; +} - // 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; +#endif - // 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 (); +// FIXME There are multiple caches of "GetObjectForNativeVariant". +G_GNUC_UNUSED +static MonoMethod* +mono_get_Marshal_GetObjectForNativeVariant (void) +{ + MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_native_variant) + 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) - // 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; + g_assert (get_object_for_native_variant); + return get_object_for_native_variant; +} - // 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; +// FIXME There are multiple caches of "GetNativeVariantForObject". +G_GNUC_UNUSED +static MonoMethod* +mono_get_Marshal_GetNativeVariantForObject (void) +{ + MONO_STATIC_POINTER_INIT (MonoMethod, get_native_variant_for_object) + 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) - // 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; + g_assert (get_native_variant_for_object); + return get_native_variant_for_object; +} - default: - g_assert_not_reached (); - } +static void +emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb) +{ + // FIXME Put a boolean in MonoMethodBuilder instead. + if (strstr (mb->name, "mono_thread_interruption_checkpoint")) + return; - return MONO_JIT_ICALL_ZeroIsReserved; + mono_marshal_shared_emit_thread_interrupt_checkpoint_call (mb, MONO_JIT_ICALL_mono_thread_interruption_checkpoint); } static void -emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec) +emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb) { - 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; - } - - 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); - } - } -} - -#ifndef DISABLE_COM - -// FIXME There are multiple caches of "Clear". -G_GNUC_UNUSED -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); - MONO_STATIC_POINTER_INIT_END (MonoMethod, variant_clear) - - g_assert (variant_clear); - return variant_clear; -} - -#endif - -// FIXME There are multiple caches of "GetObjectForNativeVariant". -G_GNUC_UNUSED -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); - MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_native_variant) - - g_assert (get_object_for_native_variant); - return get_object_for_native_variant; -} - -// FIXME There are multiple caches of "GetNativeVariantForObject". -G_GNUC_UNUSED -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); - 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) -{ - /* Call DestroyStructure */ - /* FIXME: Only do this if needed */ - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - mono_mb_emit_ldloc (mb, 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) -{ - // FIXME Put a boolean in MonoMethodBuilder instead. - if (strstr (mb->name, "mono_thread_interruption_checkpoint")) - return; - - 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 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb) @@ -1866,13 +742,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; @@ -2151,7 +1020,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); @@ -2475,3799 +1344,1153 @@ load_value_class (MonoMethodBuilder *mb, int vklass) } static int -emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) +emit_marshal_scalar_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; - MonoClass *klass = mono_class_from_mono_type_internal (t); - MonoMarshalNative encoding; - encoding = mono_marshal_get_string_encoding (m->piinfo, spec); - MonoType *int_type = mono_get_int_type (); - MonoType *object_type = mono_get_object_type (); + switch (action) { + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldarg (mb, argnum); + break; - MonoClass *eklass = m_class_get_element_class (klass); + case MARSHAL_ACTION_CONV_RESULT: + /* no conversions necessary */ + mono_mb_emit_stloc (mb, 3); + break; - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = object_type; - conv_arg = mono_mb_add_local (mb, object_type); + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + mono_mb_emit_stloc (mb, 3); + break; - if (m_class_is_blittable (eklass)) { - 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_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); -#else - guint32 label1, label2, label3; - int index_var, src_var, dest_ptr, esize; - MonoMarshalConv conv; - gboolean is_string = FALSE; - - dest_ptr = mono_mb_add_local (mb, int_type); - - if (eklass == mono_defaults.string_class) { - is_string = TRUE; - conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); - } - else if (eklass == mono_class_try_get_stringbuilder_class ()) { - is_string = TRUE; - conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); - } - else - conv = MONO_MARSHAL_CONV_INVALID; - - 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); - break; - } + default: + break; + } + return conv_arg; +} - src_var = mono_mb_add_local (mb, object_type); - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_stloc (mb, src_var); - - /* Check null */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_stloc (mb, conv_arg); - mono_mb_emit_ldloc (mb, src_var); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/ - esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; - else - esize = mono_class_native_size (eklass, NULL); +static void +emit_virtual_stelemref_ilgen (MonoMethodBuilder *mb, const char **param_names, MonoStelemrefKind kind) +{ + guint32 b1, b2, b3, b4; + int aklass, vklass, vtable, uiid; + int array_slot_addr; - /* allocate space for the native struct and store the address */ - mono_mb_emit_icon (mb, esize); - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_byte (mb, CEE_LDLEN); + mono_mb_set_param_names (mb, param_names); + MonoType *int_type = mono_get_int_type (); + MonoType *int32_type = m_class_get_byval_arg (mono_defaults.int32_class); + MonoType *object_type_byref = mono_class_get_byref_type (mono_defaults.object_class); - if (eklass == mono_defaults.string_class) { - /* Make the array bigger for the terminating null */ - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - mono_mb_emit_byte (mb, CEE_ADD); - } - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_LOCALLOC); - mono_mb_emit_stloc (mb, conv_arg); - - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, dest_ptr); - - /* 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); - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - - if (is_string) { - int stind_op; - mono_mb_emit_ldloc (mb, dest_ptr); - 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_byte (mb, stind_op); - } else { - /* set the src_ptr */ - mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_op (mb, CEE_LDELEMA, eklass); - mono_mb_emit_stloc (mb, 0); - - /* set dst_ptr */ - mono_mb_emit_ldloc (mb, dest_ptr); - 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); - } + /*For now simply call plain old stelemref*/ + switch (kind) { + case STELEMREF_OBJECT: + /* ldelema (implicit bound check) */ + load_array_element_address (mb); + /* do_store */ + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_RET); + break; - mono_mb_emit_add_to_local (mb, index_var, 1); - mono_mb_emit_add_to_local (mb, dest_ptr, esize); + case STELEMREF_COMPLEX: { + int b_fast; + /* + + if (!value) + goto store; + if (!mono_object_isinst (value, aklass)) + goto do_exception; - mono_mb_emit_branch_label (mb, CEE_BR, label2); + do_store: + *array_slot_addr = value; - mono_mb_patch_branch (mb, label3); + do_exception: + throw new ArrayTypeMismatchException (); + */ - if (eklass == mono_defaults.string_class) { - /* Null terminate */ - mono_mb_emit_ldloc (mb, dest_ptr); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_byte (mb, CEE_STIND_I); - } + aklass = mono_mb_add_local (mb, int_type); + vklass = mono_mb_add_local (mb, int_type); + array_slot_addr = mono_mb_add_local (mb, object_type_byref); - mono_mb_patch_branch (mb, label1); -#endif +#if 0 + { + /*Use this to debug/record stores that are going thru the slow path*/ + MonoMethodSignature *csig; + csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3); + csig->ret = mono_get_void_type (); + csig->params [0] = object_type; + csig->params [1] = int_type; /* this is a natural sized int */ + csig->params [2] = object_type; + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_native_call (mb, csig, record_slot_vstore); } +#endif - break; + /* ldelema (implicit bound check) */ + load_array_element_address (mb); + mono_mb_emit_stloc (mb, array_slot_addr); - case MARSHAL_ACTION_CONV_OUT: { -#ifndef DISABLE_NONBLITTABLE - gboolean need_convert, need_free; - /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */ - need_convert = ((eklass == mono_defaults.char_class) && (encoding == MONO_NATIVE_LPWSTR)) || (eklass == mono_class_try_get_stringbuilder_class ()) || (t->attrs & PARAM_ATTRIBUTE_OUT); - need_free = mono_marshal_need_free (m_class_get_byval_arg (eklass), m->piinfo, spec); + /* if (!value) goto do_store */ + mono_mb_emit_ldarg (mb, 2); + b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - if ((t->attrs & PARAM_ATTRIBUTE_OUT) && spec && spec->native == MONO_NATIVE_LPARRAY && spec->data.array_data.param_num != -1) { - int param_num = spec->data.array_data.param_num; - MonoType *param_type; + /* aklass = array->vtable->klass->element_class */ + load_array_class (mb, aklass); + /* vklass = value->vtable->klass */ + load_value_class (mb, vklass); - param_type = m->sig->params [param_num]; + /* fastpath */ + mono_mb_emit_ldloc (mb, vklass); + mono_mb_emit_ldloc (mb, aklass); + b_fast = mono_mb_emit_branch (mb, CEE_BEQ); - 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); - break; - } + /*if (mono_object_isinst (value, aklass)) */ + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_icall (mb, mono_object_isinst_icall); + b2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - if (m_type_is_byref (t) ) { - mono_mb_emit_ldarg (mb, argnum); - - /* Create the managed array */ - mono_mb_emit_ldarg (mb, param_num); - if (m_type_is_byref (m->sig->params [param_num])) - // FIXME: Support other types - mono_mb_emit_byte (mb, CEE_LDIND_I4); - mono_mb_emit_byte (mb, CEE_CONV_OVF_I); - mono_mb_emit_op (mb, CEE_NEWARR, eklass); - /* Store into argument */ - mono_mb_emit_byte (mb, CEE_STIND_REF); - } - } + /* do_store: */ + mono_mb_patch_branch (mb, b1); + mono_mb_patch_branch (mb, b_fast); + mono_mb_emit_ldloc (mb, array_slot_addr); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_RET); - if (need_convert || need_free) { - /* FIXME: Optimize blittable case */ - guint32 label1, label2, label3; - int index_var, src_ptr, loc, esize; + /* do_exception: */ + mono_mb_patch_branch (mb, b2); - if ((eklass == mono_class_try_get_stringbuilder_class ()) || (eklass == mono_defaults.string_class)) - esize = TARGET_SIZEOF_VOID_P; - else if (eklass == mono_defaults.char_class) - esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; - else - esize = mono_class_native_size (eklass, NULL); - src_ptr = mono_mb_add_local (mb, int_type); - loc = mono_mb_add_local (mb, int_type); + mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); + break; + } + case STELEMREF_SEALED_CLASS: + /* + + if (!value) + goto store; - /* Check null */ - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_I); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, src_ptr); - - /* 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); - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); + aklass = array->vtable->m_class_get_element_class (klass); + vklass = value->vtable->klass; - /* Emit marshalling code */ + if (vklass != aklass) + goto do_exception; - if (eklass == mono_class_try_get_stringbuilder_class ()) { - gboolean need_free2; - MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2); + do_store: + *array_slot_addr = value; - g_assert (conv != MONO_MARSHAL_CONV_INVALID); + do_exception: + throw new ArrayTypeMismatchException (); + */ + aklass = mono_mb_add_local (mb, int_type); + vklass = mono_mb_add_local (mb, int_type); + array_slot_addr = mono_mb_add_local (mb, object_type_byref); - /* dest */ - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_byte (mb, CEE_LDELEM_REF); + /* ldelema (implicit bound check) */ + load_array_element_address (mb); + mono_mb_emit_stloc (mb, array_slot_addr); - /* src */ - mono_mb_emit_ldloc (mb, src_ptr); - mono_mb_emit_byte (mb, CEE_LDIND_I); + /* if (!value) goto do_store */ + mono_mb_emit_ldarg (mb, 2); + b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); + /* aklass = array->vtable->klass->element_class */ + load_array_class (mb, aklass); - if (need_free) { - /* src */ - mono_mb_emit_ldloc (mb, src_ptr); - mono_mb_emit_byte (mb, CEE_LDIND_I); + /* vklass = value->vtable->klass */ + load_value_class (mb, vklass); - mono_mb_emit_icall (mb, mono_marshal_free); - } - } - else if (eklass == mono_defaults.string_class) { - if (need_free) { - /* src */ - mono_mb_emit_ldloc (mb, src_ptr); - mono_mb_emit_byte (mb, CEE_LDIND_I); + /*if (vklass != aklass) goto do_exception; */ + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldloc (mb, vklass); + b2 = mono_mb_emit_branch (mb, CEE_BNE_UN); - mono_mb_emit_icall (mb, mono_marshal_free); - } - } - else { - if (need_convert) { - /* set the src_ptr */ - mono_mb_emit_ldloc (mb, src_ptr); - mono_mb_emit_stloc (mb, 0); - - /* set dst_ptr */ - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_op (mb, CEE_LDELEMA, eklass); - mono_mb_emit_stloc (mb, 1); + /* do_store: */ + mono_mb_patch_branch (mb, b1); + mono_mb_emit_ldloc (mb, array_slot_addr); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_RET); - /* emit valuetype conversion code */ - emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); - } + /* do_exception: */ + mono_mb_patch_branch (mb, b2); + mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); + break; - if (need_free) { - mono_mb_emit_ldloc (mb, src_ptr); - mono_mb_emit_stloc (mb, loc); + case STELEMREF_CLASS: { + /* + the method: + + if (!value) + goto do_store; - emit_struct_free (mb, eklass, loc); - } - } + aklass = array->vtable->m_class_get_element_class (klass); + vklass = value->vtable->klass; - mono_mb_emit_add_to_local (mb, index_var, 1); - mono_mb_emit_add_to_local (mb, src_ptr, esize); + if (vklass->idepth < aklass->idepth) + goto do_exception; - mono_mb_emit_branch_label (mb, CEE_BR, label2); + if (vklass->supertypes [aklass->idepth - 1] != aklass) + goto do_exception; - mono_mb_patch_branch (mb, label1); - mono_mb_patch_branch (mb, label3); - } -#endif + do_store: + *array_slot_addr = value; + return; - if (m_class_is_blittable (eklass)) { - /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */ + long: + throw new ArrayTypeMismatchException (); + */ + aklass = mono_mb_add_local (mb, int_type); + vklass = mono_mb_add_local (mb, int_type); + array_slot_addr = mono_mb_add_local (mb, object_type_byref); - mono_mb_emit_ldarg (mb, argnum); - 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)); - } + /* ldelema (implicit bound check) */ + load_array_element_address (mb); + mono_mb_emit_stloc (mb, array_slot_addr); - break; - } + /* if (!value) goto do_store */ + mono_mb_emit_ldarg (mb, 2); + b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; + /* aklass = array->vtable->klass->element_class */ + load_array_class (mb, aklass); - 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); - break; - } + /* vklass = value->vtable->klass */ + load_value_class (mb, vklass); - case MARSHAL_ACTION_MANAGED_CONV_IN: { - guint32 label1, label2, label3; - int index_var, src_ptr, esize, param_num, num_elem; - MonoMarshalConv conv; - gboolean is_string = FALSE; + /* if (vklass->idepth < aklass->idepth) goto failue */ + mono_mb_emit_ldloc (mb, vklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); - conv_arg = mono_mb_add_local (mb, object_type); - *conv_arg_type = int_type; + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); - 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); - 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); - return conv_arg; - } + b3 = mono_mb_emit_branch (mb, CEE_BLT_UN); - switch (spec->native) { - case MONO_NATIVE_LPARRAY: - break; - case MONO_NATIVE_SAFEARRAY: -#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); - 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); - return conv_arg; - } - } + /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ + mono_mb_emit_ldloc (mb, vklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); + mono_mb_emit_byte (mb, CEE_LDIND_I); - /* FIXME: t is from the method which is wrapped, not the delegate type */ - /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */ + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_icon (mb, 1); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); - param_num = spec->data.array_data.param_num; - num_elem = spec->data.array_data.num_elem; - if (spec->data.array_data.elem_mult == 0) - /* param_num is not specified */ - param_num = -1; + mono_mb_emit_ldloc (mb, aklass); + b4 = mono_mb_emit_branch (mb, CEE_BNE_UN); - 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); - return conv_arg; - } - } + /* do_store: */ + mono_mb_patch_branch (mb, b1); + mono_mb_emit_ldloc (mb, array_slot_addr); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_RET); - /* FIXME: Optimize blittable case */ + /* do_exception: */ + mono_mb_patch_branch (mb, b3); + mono_mb_patch_branch (mb, b4); -#ifndef DISABLE_NONBLITTABLE - if (eklass == mono_defaults.string_class) { - is_string = TRUE; - gboolean need_free; - conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); - } - else if (eklass == mono_class_try_get_stringbuilder_class ()) { - is_string = TRUE; - gboolean need_free; - conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); - } - else - conv = MONO_MARSHAL_CONV_INVALID; -#endif + mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); + break; + } - mono_marshal_load_type_info (eklass); + case STELEMREF_CLASS_SMALL_IDEPTH: + /* + the method: + + if (!value) + goto do_store; - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else - esize = mono_class_native_size (eklass, NULL); - src_ptr = mono_mb_add_local (mb, int_type); + aklass = array->vtable->m_class_get_element_class (klass); + vklass = value->vtable->klass; - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - - /* Check param index */ - 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); - return conv_arg; - } - switch (m->sig->params [param_num]->type) { - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - break; - default: { - char *msg = g_strdup ("Array size control parameter must be an integral type."); - mono_mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; - } - } - } + if (vklass->supertypes [aklass->idepth - 1] != aklass) + goto do_exception; - /* Check null */ - mono_mb_emit_ldarg (mb, argnum); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + do_store: + *array_slot_addr = value; + return; - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_stloc (mb, src_ptr); + long: + throw new ArrayTypeMismatchException (); + */ + aklass = mono_mb_add_local (mb, int_type); + vklass = mono_mb_add_local (mb, int_type); + array_slot_addr = mono_mb_add_local (mb, object_type_byref); - /* Create managed array */ - /* - * The LPArray marshalling spec says that sometimes param_num starts - * from 1, sometimes it starts from 0. But MS seems to allways start - * from 0. - */ + /* ldelema (implicit bound check) */ + load_array_element_address (mb); + mono_mb_emit_stloc (mb, array_slot_addr); - if (param_num == -1) { - mono_mb_emit_icon (mb, num_elem); - } else { - mono_mb_emit_ldarg (mb, param_num); - if (num_elem > 0) { - mono_mb_emit_icon (mb, num_elem); - mono_mb_emit_byte (mb, CEE_ADD); - } - mono_mb_emit_byte (mb, CEE_CONV_OVF_I); - } + /* if (!value) goto do_store */ + mono_mb_emit_ldarg (mb, 2); + b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_op (mb, CEE_NEWARR, eklass); - mono_mb_emit_stloc (mb, conv_arg); + /* aklass = array->vtable->klass->element_class */ + load_array_class (mb, aklass); - if (m_class_is_blittable (eklass)) { - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_icon (mb, esize); - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - mono_mb_patch_branch (mb, label1); - break; - } -#ifdef DISABLE_NONBLITTABLE - else { - char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); - mono_mb_emit_exception_marshal_directive (mb, msg); - } -#else - /* 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); - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - if (is_string) { - g_assert (conv != MONO_MARSHAL_CONV_INVALID); - - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ldloc (mb, index_var); - - mono_mb_emit_ldloc (mb, src_ptr); - mono_mb_emit_byte (mb, CEE_LDIND_I); + /* vklass = value->vtable->klass */ + load_value_class (mb, vklass); - mono_mb_emit_icall_id (mb, 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); - return conv_arg; - } + /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ + mono_mb_emit_ldloc (mb, vklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); + mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_add_to_local (mb, index_var, 1); - mono_mb_emit_add_to_local (mb, src_ptr, esize); + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_icon (mb, 1); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_branch_label (mb, CEE_BR, label2); + mono_mb_emit_ldloc (mb, aklass); + b4 = mono_mb_emit_branch (mb, CEE_BNE_UN); - mono_mb_patch_branch (mb, label1); - mono_mb_patch_branch (mb, label3); -#endif + /* do_store: */ + mono_mb_patch_branch (mb, b1); + mono_mb_emit_ldloc (mb, array_slot_addr); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_RET); + + /* do_exception: */ + mono_mb_patch_branch (mb, b4); + mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); break; - } - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - guint32 label1, label2, label3; - int index_var, dest_ptr, esize, param_num, num_elem; - MonoMarshalConv conv; - gboolean is_string = FALSE; - - if (!spec) - /* Already handled in CONV_IN */ - break; - /* These are already checked in CONV_IN */ - g_assert (!m_type_is_byref (t)); - g_assert (spec->native == MONO_NATIVE_LPARRAY); - g_assert (t->attrs & PARAM_ATTRIBUTE_OUT); + case STELEMREF_INTERFACE: + /*Mono *klass; + MonoVTable *vt; + unsigned uiid; + if (value == NULL) + goto store; - param_num = spec->data.array_data.param_num; - num_elem = spec->data.array_data.num_elem; + klass = array->obj.vtable->klass->element_class; + vt = value->vtable; + uiid = klass->interface_id; + if (uiid > vt->max_interface_id) + goto exception; + if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) + goto exception; + store: + mono_array_setref_internal (array, index, value); + return; + exception: + mono_raise_exception (mono_get_exception_array_type_mismatch ());*/ - if (spec->data.array_data.elem_mult == 0) - /* param_num is not specified */ - param_num = -1; + array_slot_addr = mono_mb_add_local (mb, object_type_byref); + aklass = mono_mb_add_local (mb, int_type); + vtable = mono_mb_add_local (mb, int_type); + uiid = mono_mb_add_local (mb, int32_type); - if (param_num == -1) { - if (num_elem <= 0) { - g_assert_not_reached (); - } - } + /* ldelema (implicit bound check) */ + load_array_element_address (mb); + mono_mb_emit_stloc (mb, array_slot_addr); - /* FIXME: Optimize blittable case */ + /* if (!value) goto do_store */ + mono_mb_emit_ldarg (mb, 2); + b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); -#ifndef DISABLE_NONBLITTABLE - if (eklass == mono_defaults.string_class) { - is_string = TRUE; - conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); - } - else if (eklass == mono_class_try_get_stringbuilder_class ()) { - is_string = TRUE; - conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); - } - else - conv = MONO_MARSHAL_CONV_INVALID; -#endif + /* klass = array->vtable->m_class_get_element_class (klass) */ + load_array_class (mb, aklass); - mono_marshal_load_type_info (eklass); + /* vt = value->vtable */ + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, vtable); - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else - esize = mono_class_native_size (eklass, NULL); + /* uiid = klass->interface_id; */ + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_interface_id ()); + mono_mb_emit_byte (mb, CEE_LDIND_U4); + mono_mb_emit_stloc (mb, uiid); - dest_ptr = mono_mb_add_local (mb, int_type); + /*if (uiid > vt->max_interface_id)*/ + mono_mb_emit_ldloc (mb, uiid); + mono_mb_emit_ldloc (mb, vtable); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); + mono_mb_emit_byte (mb, CEE_LDIND_U4); + b2 = mono_mb_emit_branch (mb, CEE_BGT_UN); - /* Check null */ - mono_mb_emit_ldloc (mb, conv_arg); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_stloc (mb, dest_ptr); + /*vt->interface_bitmap*/ + mono_mb_emit_ldloc (mb, vtable); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap)); + mono_mb_emit_byte (mb, CEE_LDIND_I); - if (m_class_is_blittable (eklass)) { - /* dest */ - mono_mb_emit_ldarg (mb, argnum); - /* src */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_byte (mb, CEE_ADD); - /* length */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_icon (mb, esize); - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - mono_mb_patch_branch (mb, label1); - break; - } + /*uiid >> 3*/ + mono_mb_emit_ldloc (mb, uiid); + mono_mb_emit_icon (mb, 3); + mono_mb_emit_byte (mb, CEE_SHR_UN); -#ifndef DISABLE_NONBLITTABLE - /* 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); - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); - - /* Emit marshalling code */ - if (is_string) { - int stind_op; - g_assert (conv != MONO_MARSHAL_CONV_INVALID); - - /* dest */ - mono_mb_emit_ldloc (mb, dest_ptr); - - /* src */ - mono_mb_emit_ldloc (mb, conv_arg); - 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_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); - return conv_arg; - } + /*vt->interface_bitmap [(uiid) >> 3]*/ + mono_mb_emit_byte (mb, CEE_ADD); /*interface_bitmap is a guint8 array*/ + mono_mb_emit_byte (mb, CEE_LDIND_U1); - mono_mb_emit_add_to_local (mb, index_var, 1); - mono_mb_emit_add_to_local (mb, dest_ptr, esize); + /*(1 << ((uiid)&7)))*/ + mono_mb_emit_icon (mb, 1); + mono_mb_emit_ldloc (mb, uiid); + mono_mb_emit_icon (mb, 7); + mono_mb_emit_byte (mb, CEE_AND); + mono_mb_emit_byte (mb, CEE_SHL); - mono_mb_emit_branch_label (mb, CEE_BR, label2); + /*bitwise and the whole thing*/ + mono_mb_emit_byte (mb, CEE_AND); + b3 = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_patch_branch (mb, label1); - mono_mb_patch_branch (mb, label3); -#endif + /* do_store: */ + mono_mb_patch_branch (mb, b1); + mono_mb_emit_ldloc (mb, array_slot_addr); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_byte (mb, CEE_RET); + /* do_exception: */ + mono_mb_patch_branch (mb, b2); + mono_mb_patch_branch (mb, b3); + mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); break; - } - case MARSHAL_ACTION_MANAGED_CONV_RESULT: { -#ifndef DISABLE_NONBLITTABLE - guint32 label1, label2, label3; - int index_var, src, dest, esize; - MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID; - gboolean is_string = FALSE; - - g_assert (!m_type_is_byref (t)); - - mono_marshal_load_type_info (eklass); - - if (eklass == mono_defaults.string_class) { - is_string = TRUE; - conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); - } - else { - g_assert_not_reached (); - } - if (is_string) - esize = TARGET_SIZEOF_VOID_P; - else if (eklass == mono_defaults.char_class) - esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; - else - esize = mono_class_native_size (eklass, NULL); + default: + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_managed_call (mb, mono_marshal_get_stelemref (), NULL); + mono_mb_emit_byte (mb, CEE_RET); + g_assert (0); + } +} - src = mono_mb_add_local (mb, object_type); - dest = mono_mb_add_local (mb, int_type); +static void +emit_stelemref_ilgen (MonoMethodBuilder *mb) +{ + guint32 b1, b2, b3, b4; + guint32 copy_pos; + int aklass, vklass; + int array_slot_addr; - mono_mb_emit_stloc (mb, src); - mono_mb_emit_ldloc (mb, src); - mono_mb_emit_stloc (mb, 3); + MonoType *int_type = mono_get_int_type (); + MonoType *object_type_byref = mono_class_get_byref_type (mono_defaults.object_class); - /* Check for null */ - mono_mb_emit_ldloc (mb, src); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + aklass = mono_mb_add_local (mb, int_type); + vklass = mono_mb_add_local (mb, int_type); + array_slot_addr = mono_mb_add_local (mb, object_type_byref); - /* Allocate native array */ - mono_mb_emit_icon (mb, esize); - mono_mb_emit_ldloc (mb, src); - mono_mb_emit_byte (mb, CEE_LDLEN); + /* + the method: + + if (!value) + goto store; - if (eklass == mono_defaults.string_class) { - /* Make the array bigger for the terminating null */ - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - mono_mb_emit_byte (mb, CEE_ADD); - } - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_icall (mb, ves_icall_marshal_alloc); - mono_mb_emit_stloc (mb, dest); - mono_mb_emit_ldloc (mb, dest); - mono_mb_emit_stloc (mb, 3); + aklass = array->vtable->m_class_get_element_class (klass); + vklass = value->vtable->klass; - /* 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); - label2 = mono_mb_get_label (mb); - mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_ldloc (mb, src); - mono_mb_emit_byte (mb, CEE_LDLEN); - label3 = mono_mb_emit_branch (mb, CEE_BGE); + if (vklass->idepth < aklass->idepth) + goto long; - /* Emit marshalling code */ - if (is_string) { - int stind_op; - g_assert (conv != MONO_MARSHAL_CONV_INVALID); + if (vklass->supertypes [aklass->idepth - 1] != aklass) + goto long; - /* dest */ - mono_mb_emit_ldloc (mb, dest); + store: + *array_slot_addr = value; + return; - /* src */ - mono_mb_emit_ldloc (mb, src); - mono_mb_emit_ldloc (mb, index_var); + long: + if (mono_object_isinst (value, aklass)) + goto store; - mono_mb_emit_byte (mb, CEE_LDELEM_REF); + throw new ArrayTypeMismatchException (); + */ - mono_mb_emit_icall_id (mb, 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); - return conv_arg; - } + /* ldelema (implicit bound check) */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class); + mono_mb_emit_stloc (mb, array_slot_addr); - mono_mb_emit_add_to_local (mb, index_var, 1); - mono_mb_emit_add_to_local (mb, dest, esize); + /* if (!value) goto do_store */ + mono_mb_emit_ldarg (mb, 2); + b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_branch_label (mb, CEE_BR, label2); + /* aklass = array->vtable->klass->element_class */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldflda (mb, m_class_offsetof_element_class ()); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, aklass); - mono_mb_patch_branch (mb, label3); - mono_mb_patch_branch (mb, label1); -#endif - break; - } - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - switch (action) { - case MARSHAL_ACTION_CONV_IN: - /* MS seems to allow this in some cases, ie. bxc #158 */ - /* - 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); - } - */ - break; - - case MARSHAL_ACTION_PUSH: - mono_mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* no conversions necessary */ - mono_mb_emit_stloc (mb, 3); - break; - - default: - break; - } - return conv_arg; -} - -static int -emit_marshal_scalar_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - switch (action) { - case MARSHAL_ACTION_PUSH: - mono_mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* no conversions necessary */ - mono_mb_emit_stloc (mb, 3); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - mono_mb_emit_stloc (mb, 3); - break; - - default: - break; - } - return conv_arg; -} - -static int -emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoType *int_type = mono_get_int_type (); - MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - MonoType *local_type; - int label_false; - guint8 ldc_op = CEE_LDC_I4_1; - - local_type = mono_marshal_boolean_conv_in_get_local_type (spec, &ldc_op); - if (m_type_is_byref (t)) - *conv_arg_type = int_type; - else - *conv_arg_type = local_type; - conv_arg = mono_mb_add_local (mb, local_type); - - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_I1); - label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_byte (mb, ldc_op); - mono_mb_emit_stloc (mb, conv_arg); - mono_mb_patch_branch (mb, label_false); - - break; - } - - case MARSHAL_ACTION_CONV_OUT: - { - int label_false, label_end; - if (!m_type_is_byref (t)) - break; - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - - label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - - label_end = mono_mb_emit_branch (mb, CEE_BR); - mono_mb_patch_branch (mb, label_false); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_patch_branch (mb, label_end); - - mono_mb_emit_byte (mb, CEE_STIND_I1); - break; - } - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else if (conv_arg) - mono_mb_emit_ldloc (mb, conv_arg); - else - mono_mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* maybe we need to make sure that it fits within 8 bits */ - mono_mb_emit_stloc (mb, 3); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - MonoClass* conv_arg_class = mono_defaults.int32_class; - guint8 ldop = CEE_LDIND_I4; - int label_null, label_false; - - conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, &ldop); - conv_arg = mono_mb_add_local (mb, boolean_type); - - if (m_type_is_byref (t)) - *conv_arg_type = m_class_get_this_arg (conv_arg_class); - else - *conv_arg_type = m_class_get_byval_arg (conv_arg_class); - - - mono_mb_emit_ldarg (mb, argnum); - - /* Check null */ - if (m_type_is_byref (t)) { - label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, ldop); - } else - label_null = 0; - - label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - mono_mb_emit_stloc (mb, conv_arg); - mono_mb_patch_branch (mb, label_false); - - if (m_type_is_byref (t)) - mono_mb_patch_branch (mb, label_null); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - guint8 stop = CEE_STIND_I4; - guint8 ldc_op = CEE_LDC_I4_1; - int label_null,label_false, label_end; - - if (!m_type_is_byref (t)) - break; - if (spec) { - switch (spec->native) { - case MONO_NATIVE_I1: - case MONO_NATIVE_U1: - stop = CEE_STIND_I1; - break; - case MONO_NATIVE_VARIANTBOOL: - stop = CEE_STIND_I2; - ldc_op = CEE_LDC_I4_M1; - break; - default: - break; - } - } - - /* Check null */ - mono_mb_emit_ldarg (mb, argnum); - label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - - label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_byte (mb, ldc_op); - label_end = mono_mb_emit_branch (mb, CEE_BR); - - mono_mb_patch_branch (mb, label_false); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_patch_branch (mb, label_end); - - mono_mb_emit_byte (mb, stop); - mono_mb_patch_branch (mb, label_null); - break; - } - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - switch (action) { - case MARSHAL_ACTION_PUSH: - /* fixme: dont know how to marshal that. We cant simply - * convert it to a one byte UTF8 character, because an - * unicode character may need more that one byte in UTF8 */ - mono_mb_emit_ldarg (mb, argnum); - break; - - case MARSHAL_ACTION_CONV_RESULT: - /* fixme: we need conversions here */ - mono_mb_emit_stloc (mb, 3); - break; - - default: - break; - } - return conv_arg; -} - -static void -emit_virtual_stelemref_ilgen (MonoMethodBuilder *mb, const char **param_names, MonoStelemrefKind kind) -{ - guint32 b1, b2, b3, b4; - int aklass, vklass, vtable, uiid; - int array_slot_addr; - - mono_mb_set_param_names (mb, param_names); - MonoType *int_type = mono_get_int_type (); - MonoType *int32_type = m_class_get_byval_arg (mono_defaults.int32_class); - MonoType *object_type_byref = mono_class_get_byref_type (mono_defaults.object_class); - - /*For now simply call plain old stelemref*/ - switch (kind) { - case STELEMREF_OBJECT: - /* ldelema (implicit bound check) */ - load_array_element_address (mb); - /* do_store */ - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_RET); - break; - - case STELEMREF_COMPLEX: { - int b_fast; - /* - - if (!value) - goto store; - if (!mono_object_isinst (value, aklass)) - goto do_exception; - - do_store: - *array_slot_addr = value; - - do_exception: - throw new ArrayTypeMismatchException (); - */ - - aklass = mono_mb_add_local (mb, int_type); - vklass = mono_mb_add_local (mb, int_type); - array_slot_addr = mono_mb_add_local (mb, object_type_byref); - -#if 0 - { - /*Use this to debug/record stores that are going thru the slow path*/ - MonoMethodSignature *csig; - csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3); - csig->ret = mono_get_void_type (); - csig->params [0] = object_type; - csig->params [1] = int_type; /* this is a natural sized int */ - csig->params [2] = object_type; - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_native_call (mb, csig, record_slot_vstore); - } -#endif - - /* ldelema (implicit bound check) */ - load_array_element_address (mb); - mono_mb_emit_stloc (mb, array_slot_addr); - - /* if (!value) goto do_store */ - mono_mb_emit_ldarg (mb, 2); - b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* aklass = array->vtable->klass->element_class */ - load_array_class (mb, aklass); - /* vklass = value->vtable->klass */ - load_value_class (mb, vklass); - - /* fastpath */ - mono_mb_emit_ldloc (mb, vklass); - mono_mb_emit_ldloc (mb, aklass); - b_fast = mono_mb_emit_branch (mb, CEE_BEQ); - - /*if (mono_object_isinst (value, aklass)) */ - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_icall (mb, mono_object_isinst_icall); - b2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* do_store: */ - mono_mb_patch_branch (mb, b1); - mono_mb_patch_branch (mb, b_fast); - mono_mb_emit_ldloc (mb, array_slot_addr); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_RET); - - /* do_exception: */ - mono_mb_patch_branch (mb, b2); - - mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - break; - } - case STELEMREF_SEALED_CLASS: - /* - - if (!value) - goto store; - - aklass = array->vtable->m_class_get_element_class (klass); - vklass = value->vtable->klass; - - if (vklass != aklass) - goto do_exception; - - do_store: - *array_slot_addr = value; - - do_exception: - throw new ArrayTypeMismatchException (); - */ - aklass = mono_mb_add_local (mb, int_type); - vklass = mono_mb_add_local (mb, int_type); - array_slot_addr = mono_mb_add_local (mb, object_type_byref); - - /* ldelema (implicit bound check) */ - load_array_element_address (mb); - mono_mb_emit_stloc (mb, array_slot_addr); - - /* if (!value) goto do_store */ - mono_mb_emit_ldarg (mb, 2); - b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* aklass = array->vtable->klass->element_class */ - load_array_class (mb, aklass); - - /* vklass = value->vtable->klass */ - load_value_class (mb, vklass); - - /*if (vklass != aklass) goto do_exception; */ - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldloc (mb, vklass); - b2 = mono_mb_emit_branch (mb, CEE_BNE_UN); - - /* do_store: */ - mono_mb_patch_branch (mb, b1); - mono_mb_emit_ldloc (mb, array_slot_addr); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_RET); - - /* do_exception: */ - mono_mb_patch_branch (mb, b2); - mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - break; - - case STELEMREF_CLASS: { - /* - the method: - - if (!value) - goto do_store; - - aklass = array->vtable->m_class_get_element_class (klass); - vklass = value->vtable->klass; - - if (vklass->idepth < aklass->idepth) - goto do_exception; - - if (vklass->supertypes [aklass->idepth - 1] != aklass) - goto do_exception; - - do_store: - *array_slot_addr = value; - return; - - long: - throw new ArrayTypeMismatchException (); - */ - aklass = mono_mb_add_local (mb, int_type); - vklass = mono_mb_add_local (mb, int_type); - array_slot_addr = mono_mb_add_local (mb, object_type_byref); - - /* ldelema (implicit bound check) */ - load_array_element_address (mb); - mono_mb_emit_stloc (mb, array_slot_addr); - - /* if (!value) goto do_store */ - mono_mb_emit_ldarg (mb, 2); - b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* aklass = array->vtable->klass->element_class */ - load_array_class (mb, aklass); - - /* vklass = value->vtable->klass */ - load_value_class (mb, vklass); - - /* if (vklass->idepth < aklass->idepth) goto failue */ - mono_mb_emit_ldloc (mb, vklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - - b3 = mono_mb_emit_branch (mb, CEE_BLT_UN); - - /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ - mono_mb_emit_ldloc (mb, vklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - mono_mb_emit_icon (mb, 1); - mono_mb_emit_byte (mb, CEE_SUB); - mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P); - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_ldloc (mb, aklass); - b4 = mono_mb_emit_branch (mb, CEE_BNE_UN); - - /* do_store: */ - mono_mb_patch_branch (mb, b1); - mono_mb_emit_ldloc (mb, array_slot_addr); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_RET); - - /* do_exception: */ - mono_mb_patch_branch (mb, b3); - mono_mb_patch_branch (mb, b4); - - mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - break; - } - - case STELEMREF_CLASS_SMALL_IDEPTH: - /* - the method: - - if (!value) - goto do_store; - - aklass = array->vtable->m_class_get_element_class (klass); - vklass = value->vtable->klass; - - if (vklass->supertypes [aklass->idepth - 1] != aklass) - goto do_exception; - - do_store: - *array_slot_addr = value; - return; - - long: - throw new ArrayTypeMismatchException (); - */ - aklass = mono_mb_add_local (mb, int_type); - vklass = mono_mb_add_local (mb, int_type); - array_slot_addr = mono_mb_add_local (mb, object_type_byref); - - /* ldelema (implicit bound check) */ - load_array_element_address (mb); - mono_mb_emit_stloc (mb, array_slot_addr); - - /* if (!value) goto do_store */ - mono_mb_emit_ldarg (mb, 2); - b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* aklass = array->vtable->klass->element_class */ - load_array_class (mb, aklass); - - /* vklass = value->vtable->klass */ - load_value_class (mb, vklass); - - /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ - mono_mb_emit_ldloc (mb, vklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - mono_mb_emit_icon (mb, 1); - mono_mb_emit_byte (mb, CEE_SUB); - mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P); - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_ldloc (mb, aklass); - b4 = mono_mb_emit_branch (mb, CEE_BNE_UN); - - /* do_store: */ - mono_mb_patch_branch (mb, b1); - mono_mb_emit_ldloc (mb, array_slot_addr); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_RET); - - /* do_exception: */ - mono_mb_patch_branch (mb, b4); - - mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - break; - - case STELEMREF_INTERFACE: - /*Mono *klass; - MonoVTable *vt; - unsigned uiid; - if (value == NULL) - goto store; - - klass = array->obj.vtable->klass->element_class; - vt = value->vtable; - uiid = klass->interface_id; - if (uiid > vt->max_interface_id) - goto exception; - if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) - goto exception; - store: - mono_array_setref_internal (array, index, value); - return; - exception: - mono_raise_exception (mono_get_exception_array_type_mismatch ());*/ - - array_slot_addr = mono_mb_add_local (mb, object_type_byref); - aklass = mono_mb_add_local (mb, int_type); - vtable = mono_mb_add_local (mb, int_type); - uiid = mono_mb_add_local (mb, int32_type); - - /* ldelema (implicit bound check) */ - load_array_element_address (mb); - mono_mb_emit_stloc (mb, array_slot_addr); - - /* if (!value) goto do_store */ - mono_mb_emit_ldarg (mb, 2); - b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* klass = array->vtable->m_class_get_element_class (klass) */ - load_array_class (mb, aklass); - - /* vt = value->vtable */ - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_stloc (mb, vtable); - - /* uiid = klass->interface_id; */ - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_interface_id ()); - mono_mb_emit_byte (mb, CEE_LDIND_U4); - mono_mb_emit_stloc (mb, uiid); - - /*if (uiid > vt->max_interface_id)*/ - mono_mb_emit_ldloc (mb, uiid); - mono_mb_emit_ldloc (mb, vtable); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id)); - mono_mb_emit_byte (mb, CEE_LDIND_U4); - b2 = mono_mb_emit_branch (mb, CEE_BGT_UN); - - /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */ - - /*vt->interface_bitmap*/ - mono_mb_emit_ldloc (mb, vtable); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - /*uiid >> 3*/ - mono_mb_emit_ldloc (mb, uiid); - mono_mb_emit_icon (mb, 3); - mono_mb_emit_byte (mb, CEE_SHR_UN); - - /*vt->interface_bitmap [(uiid) >> 3]*/ - mono_mb_emit_byte (mb, CEE_ADD); /*interface_bitmap is a guint8 array*/ - mono_mb_emit_byte (mb, CEE_LDIND_U1); - - /*(1 << ((uiid)&7)))*/ - mono_mb_emit_icon (mb, 1); - mono_mb_emit_ldloc (mb, uiid); - mono_mb_emit_icon (mb, 7); - mono_mb_emit_byte (mb, CEE_AND); - mono_mb_emit_byte (mb, CEE_SHL); - - /*bitwise and the whole thing*/ - mono_mb_emit_byte (mb, CEE_AND); - b3 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* do_store: */ - mono_mb_patch_branch (mb, b1); - mono_mb_emit_ldloc (mb, array_slot_addr); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_RET); - - /* do_exception: */ - mono_mb_patch_branch (mb, b2); - mono_mb_patch_branch (mb, b3); - mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - break; - - default: - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_managed_call (mb, mono_marshal_get_stelemref (), NULL); - mono_mb_emit_byte (mb, CEE_RET); - g_assert (0); - } -} - -static void -emit_stelemref_ilgen (MonoMethodBuilder *mb) -{ - guint32 b1, b2, b3, b4; - guint32 copy_pos; - int aklass, vklass; - int array_slot_addr; - - MonoType *int_type = mono_get_int_type (); - MonoType *object_type_byref = mono_class_get_byref_type (mono_defaults.object_class); - - aklass = mono_mb_add_local (mb, int_type); - vklass = mono_mb_add_local (mb, int_type); - array_slot_addr = mono_mb_add_local (mb, object_type_byref); - - /* - the method: - - if (!value) - goto store; - - aklass = array->vtable->m_class_get_element_class (klass); - vklass = value->vtable->klass; - - if (vklass->idepth < aklass->idepth) - goto long; - - if (vklass->supertypes [aklass->idepth - 1] != aklass) - goto long; - - store: - *array_slot_addr = value; - return; - - long: - if (mono_object_isinst (value, aklass)) - goto store; - - throw new ArrayTypeMismatchException (); - */ - - /* ldelema (implicit bound check) */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class); - mono_mb_emit_stloc (mb, array_slot_addr); - - /* if (!value) goto do_store */ - mono_mb_emit_ldarg (mb, 2); - b1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* aklass = array->vtable->klass->element_class */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldflda (mb, m_class_offsetof_element_class ()); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_stloc (mb, aklass); - - /* vklass = value->vtable->klass */ - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_stloc (mb, vklass); - - /* if (vklass->idepth < aklass->idepth) goto failue */ - mono_mb_emit_ldloc (mb, vklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - - b2 = mono_mb_emit_branch (mb, CEE_BLT_UN); - - /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ - mono_mb_emit_ldloc (mb, vklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); - mono_mb_emit_byte (mb, CEE_LDIND_U2); - mono_mb_emit_icon (mb, 1); - mono_mb_emit_byte (mb, CEE_SUB); - mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P); - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_ldloc (mb, aklass); - - b3 = mono_mb_emit_branch (mb, CEE_BNE_UN); - - copy_pos = mono_mb_get_label (mb); - /* do_store */ - mono_mb_patch_branch (mb, b1); - mono_mb_emit_ldloc (mb, array_slot_addr); - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_emit_byte (mb, CEE_RET); - - /* the hard way */ - mono_mb_patch_branch (mb, b2); - mono_mb_patch_branch (mb, b3); - - mono_mb_emit_ldarg (mb, 2); - mono_mb_emit_ldloc (mb, aklass); - mono_mb_emit_icall (mb, mono_object_isinst_icall); - - b4 = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4)); - mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - - mono_mb_emit_byte (mb, CEE_RET); -} - -static void -mb_emit_byte_ilgen (MonoMethodBuilder *mb, guint8 op) -{ - mono_mb_emit_byte (mb, op); -} - -static void -emit_array_address_ilgen (MonoMethodBuilder *mb, int rank, int elem_size) -{ - int i, bounds, ind, realidx; - int branch_pos, *branch_positions; - - MonoType *int_type = mono_get_int_type (); - MonoType *int32_type = mono_get_int32_type (); - - branch_positions = g_new0 (int, rank); - - bounds = mono_mb_add_local (mb, int_type); - ind = mono_mb_add_local (mb, int32_type); - realidx = mono_mb_add_local (mb, int32_type); - - /* bounds = array->bounds; */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, bounds)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_stloc (mb, bounds); - - /* ind is the overall element index, realidx is the partial index in a single dimension */ - /* ind = idx0 - bounds [0].lower_bound */ - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_ldloc (mb, bounds); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - mono_mb_emit_byte (mb, CEE_SUB); - mono_mb_emit_stloc (mb, ind); - /* if (ind >= bounds [0].length) goto exeception; */ - mono_mb_emit_ldloc (mb, ind); - mono_mb_emit_ldloc (mb, bounds); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, length)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - /* note that we use unsigned comparison */ - branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN); - - /* For large ranks (> 4?) use a loop n IL later to reduce code size. - * We could also decide to ignore the passed elem_size and get it - * from the array object, to reduce the number of methods we generate: - * the additional cost is 3 memory loads and a non-immediate mul. - */ - for (i = 1; i < rank; ++i) { - /* realidx = idxi - bounds [i].lower_bound */ - mono_mb_emit_ldarg (mb, 1 + i); - mono_mb_emit_ldloc (mb, bounds); - mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - mono_mb_emit_byte (mb, CEE_SUB); - mono_mb_emit_stloc (mb, realidx); - /* if (realidx >= bounds [i].length) goto exeception; */ - mono_mb_emit_ldloc (mb, realidx); - mono_mb_emit_ldloc (mb, bounds); - mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN); - /* ind = ind * bounds [i].length + realidx */ - mono_mb_emit_ldloc (mb, ind); - mono_mb_emit_ldloc (mb, bounds); - mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_ldloc (mb, realidx); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, ind); - } - - /* return array->vector + ind * element_size */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_ldloc (mb, ind); - if (elem_size) { - mono_mb_emit_icon (mb, elem_size); - } else { - /* Load arr->vtable->klass->sizes.element_class */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I); - /* sizes is an union, so this reads sizes.element_size */ - mono_mb_emit_icon (mb, m_class_offsetof_sizes ()); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - } - mono_mb_emit_byte (mb, CEE_MUL); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_RET); - - /* patch the branches to get here and throw */ - for (i = 1; i < rank; ++i) { - mono_mb_patch_branch (mb, branch_positions [i]); - } - mono_mb_patch_branch (mb, branch_pos); - /* throw exception */ - mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL); - - g_free (branch_positions); -} - -static void -emit_delegate_begin_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig) -{ - int params_var; - params_var = mono_mb_emit_save_args (mb, sig, FALSE); - - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldloc (mb, params_var); - mono_mb_emit_icall (mb, mono_delegate_begin_invoke); - mono_mb_emit_byte (mb, CEE_RET); -} - -static void -emit_delegate_end_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig) -{ - int params_var; - params_var = mono_mb_emit_save_args (mb, sig, FALSE); - - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldloc (mb, params_var); - mono_mb_emit_icall (mb, mono_delegate_end_invoke); - - if (sig->ret->type == MONO_TYPE_VOID) { - mono_mb_emit_byte (mb, CEE_POP); - mono_mb_emit_byte (mb, CEE_RET); - } else - mono_mb_emit_restore_result (mb, sig->ret); -} - -static void -emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodSignature *invoke_sig, gboolean static_method_with_first_arg_bound, gboolean callvirt, gboolean closed_over_null, MonoMethod *method, MonoMethod *target_method, MonoClass *target_class, MonoGenericContext *ctx, MonoGenericContainer *container) -{ - int local_i, local_len, local_delegates, local_d, local_target, local_res = 0; - int pos0, pos1, pos2; - int i; - gboolean void_ret; - - MonoType *int32_type = mono_get_int32_type (); - MonoType *object_type = mono_get_object_type (); - - void_ret = sig->ret->type == MONO_TYPE_VOID && !method->string_ctor; - - /* allocate local 0 (object) */ - local_i = mono_mb_add_local (mb, int32_type); - local_len = mono_mb_add_local (mb, int32_type); - local_delegates = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.array_class)); - local_d = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.multicastdelegate_class)); - local_target = mono_mb_add_local (mb, object_type); - - if (!void_ret) - local_res = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret))); - - g_assert (sig->hasthis); - - /* - * {type: sig->ret} res; - * if (delegates == null) { - * return this. ( args .. ); - * } else { - * int i = 0, len = this.delegates.Length; - * do { - * res = this.delegates [i].Invoke ( args .. ); - * } while (++i < len); - * return res; - * } - */ - - /* this wrapper can be used in unmanaged-managed transitions */ - emit_thread_interrupt_checkpoint (mb); - - /* delegates = this.delegates */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoMulticastDelegate, delegates)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_stloc (mb, local_delegates); - - /* if (delegates == null) */ - mono_mb_emit_ldloc (mb, local_delegates); - pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE); - - /* return target. ( args .. ); */ - - /* target = d.target; */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, target)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_stloc (mb, local_target); - - /*static methods with bound first arg can have null target and still be bound*/ - if (!static_method_with_first_arg_bound) { - /* if target != null */ - mono_mb_emit_ldloc (mb, local_target); - pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* then call this->method_ptr nonstatic */ - if (callvirt) { - // FIXME: - mono_mb_emit_exception_full (mb, "System", "NotImplementedException", ""); - } else { - mono_mb_emit_ldloc (mb, local_target); - for (i = 0; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_LD_DELEGATE_METHOD_PTR); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig); - mono_mb_emit_byte (mb, CEE_RET); - } - - /* else [target == null] call this->method_ptr static */ - mono_mb_patch_branch (mb, pos0); - } - - if (callvirt) { - if (!closed_over_null) { - /* if target_method is not really virtual, turn it into a direct call */ - if (!(target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) || m_class_is_valuetype (target_class)) { - mono_mb_emit_ldarg (mb, 1); - for (i = 1; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_op (mb, CEE_CALL, target_method); - } else { - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_op (mb, CEE_CASTCLASS, target_class); - for (i = 1; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_op (mb, CEE_CALLVIRT, target_method); - } - } else { - mono_mb_emit_byte (mb, CEE_LDNULL); - for (i = 0; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_op (mb, CEE_CALL, target_method); - } - } else { - if (static_method_with_first_arg_bound) { - mono_mb_emit_ldloc (mb, local_target); - if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0])) - mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type_internal (invoke_sig->params[0])); - } - for (i = 0; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_LD_DELEGATE_METHOD_PTR); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig); - } - - mono_mb_emit_byte (mb, CEE_RET); - - /* else [delegates != null] */ - mono_mb_patch_branch (mb, pos2); - - /* len = delegates.Length; */ - mono_mb_emit_ldloc (mb, local_delegates); - mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_byte (mb, CEE_CONV_I4); - mono_mb_emit_stloc (mb, local_len); - - /* i = 0; */ - mono_mb_emit_icon (mb, 0); - mono_mb_emit_stloc (mb, local_i); - - pos1 = mono_mb_get_label (mb); - - /* d = delegates [i]; */ - mono_mb_emit_ldloc (mb, local_delegates); - mono_mb_emit_ldloc (mb, local_i); - mono_mb_emit_byte (mb, CEE_LDELEM_REF); - mono_mb_emit_stloc (mb, local_d); - - /* res = d.Invoke ( args .. ); */ - mono_mb_emit_ldloc (mb, local_d); - for (i = 0; i < sig->param_count; i++) - mono_mb_emit_ldarg (mb, i + 1); - if (!ctx) { - mono_mb_emit_op (mb, CEE_CALLVIRT, method); - } else { - ERROR_DECL (error); - mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method_checked (method, &container->context, error)); - g_assert (is_ok (error)); /* FIXME don't swallow the error */ - } - - if (!void_ret) - mono_mb_emit_stloc (mb, local_res); - - /* i += 1 */ - mono_mb_emit_add_to_local (mb, local_i, 1); - - /* i < l */ - mono_mb_emit_ldloc (mb, local_i); - mono_mb_emit_ldloc (mb, local_len); - mono_mb_emit_branch_label (mb, CEE_BLT, pos1); - - /* return res */ - if (!void_ret) - mono_mb_emit_ldloc (mb, local_res); - mono_mb_emit_byte (mb, CEE_RET); -} - -static void -mb_skip_visibility_ilgen (MonoMethodBuilder *mb) -{ - mb->skip_visibility = 1; -} - -static void -mb_set_dynamic_ilgen (MonoMethodBuilder *mb) -{ - mb->dynamic = 1; -} - -static void -emit_synchronized_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoGenericContext *ctx, MonoGenericContainer *container, MonoMethod *enter_method, MonoMethod *exit_method, MonoMethod *gettypefromhandle_method) -{ - int i, pos, pos2, this_local, taken_local, ret_local = 0; - MonoMethodSignature *sig = mono_method_signature_internal (method); - MonoExceptionClause *clause; - - /* result */ - if (!MONO_TYPE_IS_VOID (sig->ret)) - ret_local = mono_mb_add_local (mb, sig->ret); - - if (m_class_is_valuetype (method->klass) && !(method->flags & MONO_METHOD_ATTR_STATIC)) { - /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */ - mono_class_set_type_load_failure (method->klass, ""); - /* This will throw the type load exception when the wrapper is compiled */ - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_op (mb, CEE_ISINST, method->klass); - mono_mb_emit_byte (mb, CEE_POP); - - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_ldloc (mb, ret_local); - mono_mb_emit_byte (mb, CEE_RET); - - return; - } - - MonoType *object_type = mono_get_object_type (); - MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); - /* this */ - this_local = mono_mb_add_local (mb, object_type); - taken_local = mono_mb_add_local (mb, boolean_type); - - clause = (MonoExceptionClause *)mono_image_alloc0 (get_method_image (method), sizeof (MonoExceptionClause)); - clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY; - - /* Push this or the type object */ - if (method->flags & METHOD_ATTRIBUTE_STATIC) { - /* We have special handling for this in the JIT */ - int index = mono_mb_add_data (mb, method->klass); - mono_mb_add_data (mb, mono_defaults.typehandle_class); - mono_mb_emit_byte (mb, CEE_LDTOKEN); - mono_mb_emit_i4 (mb, index); - - mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL); - } - else - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_stloc (mb, this_local); - - clause->try_offset = mono_mb_get_label (mb); - /* Call Monitor::Enter() */ - mono_mb_emit_ldloc (mb, this_local); - mono_mb_emit_ldloc_addr (mb, taken_local); - mono_mb_emit_managed_call (mb, enter_method, NULL); - - /* Call the method */ - if (sig->hasthis) - mono_mb_emit_ldarg (mb, 0); - for (i = 0; i < sig->param_count; i++) - mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE)); - - if (ctx) { - ERROR_DECL (error); - mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, error), NULL); - g_assert (is_ok (error)); /* FIXME don't swallow the error */ - } else { - mono_mb_emit_managed_call (mb, method, NULL); - } - - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_stloc (mb, ret_local); - - pos = mono_mb_emit_branch (mb, CEE_LEAVE); - - clause->try_len = mono_mb_get_pos (mb) - clause->try_offset; - clause->handler_offset = mono_mb_get_label (mb); - - /* Call Monitor::Exit() if needed */ - mono_mb_emit_ldloc (mb, taken_local); - pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_ldloc (mb, this_local); - mono_mb_emit_managed_call (mb, exit_method, NULL); - mono_mb_patch_branch (mb, pos2); - mono_mb_emit_byte (mb, CEE_ENDFINALLY); - - clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; - - mono_mb_patch_branch (mb, pos); - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_ldloc (mb, ret_local); - mono_mb_emit_byte (mb, CEE_RET); - - mono_mb_set_clauses (mb, 1, clause); -} - -static void -emit_unbox_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method) -{ - MonoMethodSignature *sig = mono_method_signature_internal (method); - - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); - for (int i = 0; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_managed_call (mb, method, NULL); - mono_mb_emit_byte (mb, CEE_RET); -} - -static void -emit_array_accessor_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *sig, MonoGenericContext *ctx) -{ - MonoGenericContainer *container = NULL; - /* Call the method */ - if (sig->hasthis) - mono_mb_emit_ldarg (mb, 0); - for (int i = 0; i < sig->param_count; i++) - mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE)); - - if (ctx) { - ERROR_DECL (error); - mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, error), NULL); - g_assert (is_ok (error)); /* FIXME don't swallow the error */ - } else { - mono_mb_emit_managed_call (mb, method, NULL); - } - mono_mb_emit_byte (mb, CEE_RET); -} - -static void -emit_generic_array_helper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig) -{ - mono_mb_emit_ldarg (mb, 0); - for (int i = 0; i < csig->param_count; i++) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_managed_call (mb, method, NULL); - mono_mb_emit_byte (mb, CEE_RET); -} - -static void -emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig) -{ - MonoImage *image = get_method_image (method); - MonoMethodSignature *sig = mono_method_signature_internal (method); - int param_count = sig->param_count + sig->hasthis + 1; - int pos_leave, coop_gc_var = 0; - MonoExceptionClause *clause; - MonoType *object_type = mono_get_object_type (); -#if defined (TARGET_WASM) - const gboolean do_blocking_transition = FALSE; -#else - const gboolean do_blocking_transition = TRUE; -#endif - - /* local 0 (temp for exception object) */ - mono_mb_add_local (mb, object_type); - - /* local 1 (temp for result) */ - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_add_local (mb, sig->ret); - - if (do_blocking_transition) { - /* local 4, the local to be used when calling the suspend funcs */ - coop_gc_var = mono_mb_add_local (mb, mono_get_int_type ()); - } - - /* clear exception arg */ - mono_mb_emit_ldarg (mb, param_count - 1); - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - if (do_blocking_transition) { - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_GET_SP); - mono_mb_emit_icall (mb, mono_threads_enter_gc_unsafe_region_unbalanced); - mono_mb_emit_stloc (mb, coop_gc_var); - } - - /* try */ - clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause)); - clause->try_offset = mono_mb_get_label (mb); - - /* push method's args */ - for (int i = 0; i < param_count - 1; i++) { - MonoType *type; - MonoClass *klass; - - mono_mb_emit_ldarg (mb, i); - - /* get the byval type of the param */ - klass = mono_class_from_mono_type_internal (csig->params [i]); - type = m_class_get_byval_arg (klass); - - /* unbox struct args */ - if (MONO_TYPE_ISSTRUCT (type)) { - mono_mb_emit_op (mb, CEE_UNBOX, klass); - - /* byref args & and the "this" arg must remain a ptr. - Otherwise make a copy of the value type */ - if (!(m_type_is_byref (csig->params [i]) || (i == 0 && sig->hasthis))) - mono_mb_emit_op (mb, CEE_LDOBJ, klass); - - csig->params [i] = object_type; - } - } - - /* call */ - if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) - mono_mb_emit_op (mb, CEE_CALLVIRT, method); - else - mono_mb_emit_op (mb, CEE_CALL, method); - - /* save result at local 1 */ - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_stloc (mb, 1); - - pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE); - - /* catch */ - clause->flags = MONO_EXCEPTION_CLAUSE_NONE; - clause->try_len = mono_mb_get_pos (mb) - clause->try_offset; - clause->data.catch_class = mono_defaults.object_class; - - clause->handler_offset = mono_mb_get_label (mb); - - /* store exception at local 0 */ - mono_mb_emit_stloc (mb, 0); - mono_mb_emit_ldarg (mb, param_count - 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_branch (mb, CEE_LEAVE); - - clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; - - mono_mb_set_clauses (mb, 1, clause); - - mono_mb_patch_branch (mb, pos_leave); - /* end-try */ - - if (!MONO_TYPE_IS_VOID (sig->ret)) { - mono_mb_emit_ldloc (mb, 1); - - /* box the return value */ - if (MONO_TYPE_ISSTRUCT (sig->ret)) - mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (sig->ret)); - } - - if (do_blocking_transition) { - mono_mb_emit_ldloc (mb, coop_gc_var); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_GET_SP); - mono_mb_emit_icall (mb, mono_threads_exit_gc_unsafe_region_unbalanced); - } - - 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) -{ - /* Throw exception and emit compensation code, if neccesary */ - switch (action) { - case MARSHAL_ACTION_CONV_IN: - case MARSHAL_ACTION_MANAGED_CONV_IN: - case MARSHAL_ACTION_CONV_RESULT: - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT)) - mono_mb_emit_byte (mb, CEE_POP); - - mono_mb_emit_exception_full (mb, exc_nspace, exc_name, msg); - - break; - case MARSHAL_ACTION_PUSH: - mono_mb_emit_byte (mb, CEE_LDNULL); - break; - default: - break; - } - - return 0; -} - -static int -emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - ERROR_DECL (error); - MonoType *mtype; - MonoClass *mklass; - static MonoClass *ICustomMarshaler = NULL; - static MonoMethod *cleanup_native, *cleanup_managed; - static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed; - MonoMethodBuilder *mb = m->mb; - MonoAssemblyLoadContext *alc = mono_alc_get_ambient (); - guint32 loc1; - int pos2; - - MonoType *int_type = mono_get_int_type (); - MonoType *object_type = mono_get_object_type (); - - if (!ICustomMarshaler) { - MonoClass *klass = mono_class_try_get_icustom_marshaler_class (); - 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); - g_assert (cleanup_native); - - cleanup_managed = get_method_nofail (klass, "CleanUpManagedData", 1, 0); - g_assert (cleanup_managed); - - marshal_managed_to_native = get_method_nofail (klass, "MarshalManagedToNative", 1, 0); - g_assert (marshal_managed_to_native); - - marshal_native_to_managed = get_method_nofail (klass, "MarshalNativeToManaged", 1, 0); - g_assert (marshal_native_to_managed); - - mono_memory_barrier (); - ICustomMarshaler = klass; - } - - if (spec->data.custom_data.image) - mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, spec->data.custom_data.image, error); - else - mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, m->image, error); - - if (!mtype) - return emit_marshal_custom_ilgen_throw_exception (mb, "System", "TypeLoadException", g_strdup ("Failed to load ICustomMarshaler type"), action); - - mklass = mono_class_from_mono_type_internal (mtype); - g_assert (mklass != NULL); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: - switch (t->type) { - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_VALUETYPE: - break; - - default: - g_warning ("custom marshalling of type %x is currently not supported", t->type); - g_assert_not_reached (); - break; - } - - conv_arg = mono_mb_add_local (mb, int_type); - - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) - break; - - /* Minic MS.NET behavior */ - if (!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN)) - break; - - /* Check for null */ - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (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_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - if (t->type == MONO_TYPE_VALUETYPE) { - /* - * Since we can't determine the type of the argument, we - * will assume the unmanaged function takes a pointer. - */ - *conv_arg_type = int_type; - - mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t)); - } - - mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); - mono_mb_emit_stloc (mb, conv_arg); - - mono_mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_CONV_OUT: - /* Check for null */ - mono_mb_emit_ldloc (mb, conv_arg); - pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - 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_mb_emit_byte (mb, CEE_DUP); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - - 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 (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_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_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - /* We have nowhere to store the result */ - mono_mb_emit_byte (mb, CEE_POP); - } - - // 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_mb_emit_ldloc (mb, conv_arg); - - mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native); - } - - mono_mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: - mono_mb_emit_stloc (mb, 3); - - /* Check for null */ - mono_mb_emit_ldloc (mb, 3); - pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - 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); - mono_mb_emit_stloc (mb, 3); - - mono_mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - switch (t->type) { - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_STRING: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_VALUETYPE: - case MONO_TYPE_BOOLEAN: - break; - - default: - g_warning ("custom marshalling of type %x is currently not supported", t->type); - g_assert_not_reached (); - break; - } - - conv_arg = mono_mb_add_local (mb, object_type); - - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t) && t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - /* Check for null */ - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (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_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_I); - - mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); - mono_mb_emit_stloc (mb, conv_arg); - - mono_mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - g_assert (!m_type_is_byref (t)); - - loc1 = mono_mb_add_local (mb, object_type); - - mono_mb_emit_stloc (mb, 3); - - mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_stloc (mb, loc1); - - /* Check for null */ - mono_mb_emit_ldloc (mb, 3); - pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - emit_marshal_custom_get_instance (mb, mklass, spec); - mono_mb_emit_byte (mb, CEE_DUP); - - mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); - mono_mb_emit_stloc (mb, 3); - - mono_mb_emit_ldloc (mb, loc1); - mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - - mono_mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - - /* Check for null */ - mono_mb_emit_ldloc (mb, conv_arg); - pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - if (m_type_is_byref (t)) { - mono_mb_emit_ldarg (mb, argnum); - - 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); - mono_mb_emit_byte (mb, CEE_STIND_I); - } - - // 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_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - } - - mono_mb_patch_branch (mb, pos2); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - - MonoType *int_type = mono_get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL); - - g_assert (t->type == MONO_TYPE_OBJECT); - g_assert (!m_type_is_byref (t)); - - conv_arg = mono_mb_add_local (mb, int_type); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_icon (mb, encoding); - mono_mb_emit_icon (mb, t->attrs); - mono_mb_emit_icall (mb, mono_marshal_asany); - mono_mb_emit_stloc (mb, conv_arg); - break; - } - - case MARSHAL_ACTION_PUSH: - mono_mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_OUT: { - MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icon (mb, encoding); - mono_mb_emit_icon (mb, t->attrs); - mono_mb_emit_icall (mb, mono_marshal_free_asany); - break; - } - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static int -emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoClass *klass, *date_time_class; - int pos = 0, pos2; - - klass = mono_class_from_mono_type_internal (t); - - date_time_class = mono_class_get_date_time_class (); - - MonoType *int_type = mono_get_int_type (); - MonoType *double_type = m_class_get_byval_arg (mono_defaults.double_class); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: - if (klass == date_time_class) { - /* Convert it to an OLE DATE type */ - - conv_arg = mono_mb_add_local (mb, double_type); - - if (m_type_is_byref (t)) { - mono_mb_emit_ldarg (mb, argnum); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - } - - if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { - if (!m_type_is_byref (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); - g_assert (to_oadate); - MONO_STATIC_POINTER_INIT_END (MonoMethod, to_oadate) - - mono_mb_emit_ldarg_addr (mb, argnum); - mono_mb_emit_managed_call (mb, to_oadate, NULL); - mono_mb_emit_stloc (mb, conv_arg); - } - - if (m_type_is_byref (t)) - mono_mb_patch_branch (mb, pos); - break; - } - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - break; - - conv_arg = mono_mb_add_local (mb, int_type); - - /* store the address of the source into local variable 0 */ - if (m_type_is_byref (t)) - mono_mb_emit_ldarg (mb, argnum); - else - mono_mb_emit_ldarg_addr (mb, argnum); - - mono_mb_emit_stloc (mb, 0); - - /* allocate space for the native struct and - * store the address into local variable 1 (dest) */ - mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_LOCALLOC); - mono_mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t)) { - mono_mb_emit_ldloc (mb, 0); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - } - - if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { - /* set dst_ptr */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); - } - - if (m_type_is_byref (t)) - mono_mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_PUSH: - if (spec && spec->native == MONO_NATIVE_LPSTRUCT) { - /* FIXME: */ - g_assert (!m_type_is_byref (t)); - - /* Have to change the signature since the vtype is passed byref */ - m->csig->params [argnum - m->csig->hasthis] = int_type; - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - mono_mb_emit_ldarg_addr (mb, argnum); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; - } - - if (klass == date_time_class) { - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; - } - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { - mono_mb_emit_ldarg (mb, argnum); - break; - } - mono_mb_emit_ldloc (mb, conv_arg); - if (!m_type_is_byref (t)) { - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass); - } - break; - - case MARSHAL_ACTION_CONV_OUT: - if (klass == date_time_class) { - /* Convert from an OLE DATE type */ - - if (!m_type_is_byref (t)) - break; - - 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); - MONO_STATIC_POINTER_INIT_END (MonoMethod, from_oadate) - - g_assert (from_oadate); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_managed_call (mb, from_oadate, NULL); - mono_mb_emit_op (mb, CEE_STOBJ, date_time_class); - } - break; - } - - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - break; - - if (m_type_is_byref (t)) { - /* dst = argument */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_stloc (mb, 1); - - mono_mb_emit_ldloc (mb, 1); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - - if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { - /* src = tmp_locals [i] */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, 0); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); - } - } - - emit_struct_free (mb, klass, conv_arg); - - if (m_type_is_byref (t)) - mono_mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_CONV_RESULT: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass)) { - mono_mb_emit_stloc (mb, 3); - break; - } - - /* load pointer to returned value type */ - g_assert (m->vtaddr_var); - mono_mb_emit_ldloc (mb, m->vtaddr_var); - /* store the address of the source into local variable 0 */ - mono_mb_emit_stloc (mb, 0); - /* set dst_ptr */ - mono_mb_emit_ldloc_addr (mb, 3); - mono_mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { - conv_arg = 0; - break; - } - - conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass)); - - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - if (m_type_is_byref (t)) - mono_mb_emit_ldarg (mb, argnum); - else - mono_mb_emit_ldarg_addr (mb, argnum); - mono_mb_emit_stloc (mb, 0); - - if (m_type_is_byref (t)) { - mono_mb_emit_ldloc (mb, 0); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - } - - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); - - if (m_type_is_byref (t)) - mono_mb_patch_branch (mb, pos); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) - break; - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) - break; - - /* Check for null */ - mono_mb_emit_ldarg (mb, argnum); - pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* Set src */ - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_stloc (mb, 0); - - /* Set dest */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); - - mono_mb_patch_branch (mb, pos2); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { - mono_mb_emit_stloc (mb, 3); - m->retobj_var = 0; - break; - } - - /* load pointer to returned value type */ - g_assert (m->vtaddr_var); - mono_mb_emit_ldloc (mb, m->vtaddr_var); - - /* store the address of the source into local variable 0 */ - mono_mb_emit_stloc (mb, 0); - /* allocate space for the native struct and - * store the address into dst_ptr */ - m->retobj_var = mono_mb_add_local (mb, int_type); - m->retobj_class = klass; - g_assert (m->retobj_var); - mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); - mono_mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_icall (mb, ves_icall_marshal_alloc); - mono_mb_emit_stloc (mb, 1); - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_stloc (mb, m->retobj_var); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - -static inline 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) - mono_mb_emit_icall (mb, mono_free_bstr); - else - mono_mb_emit_icall (mb, mono_marshal_free); -} - -static int -emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); - MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); - gboolean need_free; - - MonoType *int_type = mono_get_int_type (); - MonoType *object_type = mono_get_object_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = int_type; - conv_arg = mono_mb_add_local (mb, int_type); - - if (m_type_is_byref (t)) { - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); - } else { - mono_mb_emit_ldarg (mb, argnum); - } - - 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); - } else { - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); - - mono_mb_emit_stloc (mb, conv_arg); - } - break; - - case MARSHAL_ACTION_CONV_OUT: - 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); - break; - } - - if (encoding == MONO_NATIVE_VBBYREFSTR) { - - if (!m_type_is_byref (t)) { - char *msg = g_strdup ("VBByRefStr marshalling requires a ref parameter."); - mono_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); - - MONO_STATIC_POINTER_INIT_END (MonoMethod, method) - - /* - * Have to allocate a new string with the same length as the original, and - * copy the contents of the buffer pointed to by CONV_ARG into it. - */ - g_assert (m_type_is_byref (t)); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_managed_call (mb, method, NULL); - mono_mb_emit_icall (mb, mono_string_new_len_wrapper); - mono_mb_emit_byte (mb, CEE_STIND_REF); - } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { - 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_byte (mb, stind_op); - need_free = TRUE; - } - - if (need_free) { - mono_mb_emit_ldloc (mb, conv_arg); - emit_string_free_icall (mb, conv); - } - break; - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t) && encoding != MONO_NATIVE_VBBYREFSTR) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: - mono_mb_emit_stloc (mb, 0); - - 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); - break; - } - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); - mono_mb_emit_stloc (mb, 3); - - /* free the string */ - mono_mb_emit_ldloc (mb, 0); - emit_string_free_icall (mb, conv); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: - conv_arg = mono_mb_add_local (mb, object_type); - - *conv_arg_type = int_type; - - if (m_type_is_byref (t)) { - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - } - - 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); - 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_stloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (m_type_is_byref (t)) { - if (conv_arg) { - 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_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) - /* 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_stloc (mb, 3); - break; - - default: - g_assert_not_reached (); - } - return conv_arg; -} - - -static int -emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - MonoType *int_type = mono_get_int_type (); - MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); - - switch (action){ - case MARSHAL_ACTION_CONV_IN: { - int dar_release_slot, pos; - - conv_arg = mono_mb_add_local (mb, int_type); - *conv_arg_type = int_type; - - if (!sh_dangerous_add_ref) - init_safe_handle (); - - mono_mb_emit_ldarg (mb, argnum); - pos = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_emit_exception (mb, "ArgumentNullException", NULL); - - mono_mb_patch_branch (mb, pos); - - /* Create local to hold the ref parameter to DangerousAddRef */ - dar_release_slot = mono_mb_add_local (mb, boolean_type); - - /* set release = false; */ - mono_mb_emit_icon (mb, 0); - mono_mb_emit_stloc (mb, dar_release_slot); - - if (m_type_is_byref (t)) { - int old_handle_value_slot = mono_mb_add_local (mb, int_type); - - if (!is_in (t)) { - mono_mb_emit_icon (mb, 0); - mono_mb_emit_stloc (mb, conv_arg); - } else { - /* safehandle.DangerousAddRef (ref release) */ - 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); - - /* Pull the handle field from SafeHandle */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_DUP); - mono_mb_emit_stloc (mb, conv_arg); - mono_mb_emit_stloc (mb, old_handle_value_slot); - } - } else { - /* 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); - - /* Pull the handle field from SafeHandle */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_stloc (mb, conv_arg); - } - - break; - } - - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_OUT: { - /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */ - int dar_release_slot = conv_arg + 1; - int label_next = 0; - - if (!sh_dangerous_release) - 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)) { - 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_patch_branch (mb, label_next); - } + /* vklass = value->vtable->klass */ + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, vklass); - if (is_out (t)) { - ERROR_DECL (local_error); - MonoMethod *ctor; - - /* - * If the SafeHandle was marshalled on input we can skip the marshalling on - * output if the handle value is identical. - */ - if (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); - label_next = mono_mb_emit_branch (mb, CEE_BEQ); - } + /* if (vklass->idepth < aklass->idepth) goto failue */ + mono_mb_emit_ldloc (mb, vklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); - /* - * Create an empty SafeHandle (of correct derived type). - * - * FIXME: If an out-of-memory situation or exception happens here we will - * leak the handle. We should move the allocation of the SafeHandle to the - * input marshalling code to prevent that. - */ - ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, local_error); - if (ctor == NULL || !is_ok (local_error)){ - mono_mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); - mono_error_cleanup (local_error); - break; - } + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); - /* refval = new SafeHandleDerived ()*/ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); - mono_mb_emit_byte (mb, CEE_STIND_REF); + b2 = mono_mb_emit_branch (mb, CEE_BLT_UN); - /* refval.handle = returned_handle */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_STIND_I); + /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */ + mono_mb_emit_ldloc (mb, vklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_supertypes ()); + mono_mb_emit_byte (mb, CEE_LDIND_I); - if (is_in (t) && label_next) { - mono_mb_patch_branch (mb, label_next); - } - } - } else { - 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_patch_branch (mb, label_next); - } - break; - } + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_ldflda (mb, m_class_offsetof_idepth ()); + mono_mb_emit_byte (mb, CEE_LDIND_U2); + mono_mb_emit_icon (mb, 1); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); - case MARSHAL_ACTION_CONV_RESULT: { - ERROR_DECL (error); - MonoMethod *ctor = NULL; - int intptr_handle_slot; + mono_mb_emit_ldloc (mb, aklass); - 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")); - break; - } + b3 = mono_mb_emit_branch (mb, CEE_BNE_UN); - ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, error); - if (ctor == NULL || !is_ok (error)){ - mono_error_cleanup (error); - mono_mb_emit_byte (mb, CEE_POP); - mono_mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); - break; - } - /* Store the IntPtr results into a local */ - intptr_handle_slot = mono_mb_add_local (mb, int_type); - mono_mb_emit_stloc (mb, intptr_handle_slot); + copy_pos = mono_mb_get_label (mb); + /* do_store */ + mono_mb_patch_branch (mb, b1); + mono_mb_emit_ldloc (mb, array_slot_addr); + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_byte (mb, CEE_STIND_REF); - /* Create return value */ - mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); - mono_mb_emit_stloc (mb, 3); + mono_mb_emit_byte (mb, CEE_RET); - /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */ - mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); - mono_mb_emit_ldloc (mb, intptr_handle_slot); - mono_mb_emit_byte (mb, CEE_STIND_I); - break; - } + /* the hard way */ + mono_mb_patch_branch (mb, b2); + mono_mb_patch_branch (mb, b3); - case MARSHAL_ACTION_MANAGED_CONV_IN: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); - break; + mono_mb_emit_ldarg (mb, 2); + mono_mb_emit_ldloc (mb, aklass); + mono_mb_emit_icall (mb, mono_object_isinst_icall); - case MARSHAL_ACTION_MANAGED_CONV_OUT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); - break; + b4 = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4)); + mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL); - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); - break; - default: - printf ("Unhandled case for MarshalAction: %d\n", action); - } - return conv_arg; + mono_mb_emit_byte (mb, CEE_RET); } - -static int -emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) +static void +mb_emit_byte_ilgen (MonoMethodBuilder *mb, guint8 op) { - MonoMethodBuilder *mb = m->mb; - - MonoType *int_type = mono_get_int_type (); - switch (action){ - case MARSHAL_ACTION_CONV_IN: { - conv_arg = mono_mb_add_local (mb, int_type); - *conv_arg_type = int_type; - - 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); - break; - } - mono_mb_emit_ldarg_addr (mb, argnum); - 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_stloc (mb, conv_arg); - break; - } - - case MARSHAL_ACTION_PUSH: - mono_mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_OUT: { - /* no resource release required */ - break; - } - - 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); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_IN: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); - break; - - case MARSHAL_ACTION_MANAGED_CONV_OUT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); - break; - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: - fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); - break; - default: - fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action); - } - return conv_arg; + mono_mb_emit_byte (mb, op); } - -static int -emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) +static void +emit_array_address_ilgen (MonoMethodBuilder *mb, int rank, int elem_size) { - MonoMethodBuilder *mb = m->mb; - MonoClass *klass = mono_class_from_mono_type_internal (t); - int pos, pos2, loc; + int i, bounds, ind, realidx; + int branch_pos, *branch_positions; MonoType *int_type = mono_get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = int_type; - conv_arg = mono_mb_add_local (mb, int_type); - - m->orig_conv_args [argnum] = 0; - - 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); - break; - } - - if (m_class_is_delegate (klass)) { - 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_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_stloc (mb, conv_arg); - } - } else if (klass == mono_class_try_get_stringbuilder_class ()) { - MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); - MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); - -#if 0 - 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); - } - break; - } -#endif - - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT)) - break; - - 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); - 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_stloc (mb, conv_arg); - } else if (m_class_is_blittable (klass)) { - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - - mono_mb_emit_ldarg (mb, argnum); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, conv_arg); - - mono_mb_patch_branch (mb, pos); - break; - } else { - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t)) { - /* we dont need any conversions for out parameters */ - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); - - } else { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - } - - /* store the address of the source into local variable 0 */ - mono_mb_emit_stloc (mb, 0); - mono_mb_emit_ldloc (mb, 0); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); - - /* allocate space for the native struct and store the address */ - mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_LOCALLOC); - mono_mb_emit_stloc (mb, conv_arg); - - if (m_type_is_byref (t)) { - /* Need to store the original buffer so we can free it later */ - m->orig_conv_args [argnum] = mono_mb_add_local (mb, int_type); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]); - } - - /* set the src_ptr */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 0); - - /* set dst_ptr */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, 1); - - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); - - mono_mb_patch_branch (mb, pos); - } - break; - - case MARSHAL_ACTION_CONV_OUT: - if (klass == mono_class_try_get_stringbuilder_class ()) { - gboolean need_free; - MonoMarshalNative encoding; - MonoMarshalConv conv; + MonoType *int32_type = mono_get_int32_type (); - encoding = mono_marshal_get_string_encoding (m->piinfo, spec); - conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); + branch_positions = g_new0 (int, rank); - g_assert (encoding != -1); + bounds = mono_mb_add_local (mb, int_type); + ind = mono_mb_add_local (mb, int32_type); + realidx = mono_mb_add_local (mb, int32_type); - if (m_type_is_byref (t)) { - //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT)); + /* bounds = array->bounds; */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, bounds)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, bounds); - need_free = TRUE; + /* ind is the overall element index, realidx is the partial index in a single dimension */ + /* ind = idx0 - bounds [0].lower_bound */ + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_stloc (mb, ind); + /* if (ind >= bounds [0].length) goto exeception; */ + mono_mb_emit_ldloc (mb, ind); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, length)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + /* note that we use unsigned comparison */ + branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); + /* For large ranks (> 4?) use a loop n IL later to reduce code size. + * We could also decide to ignore the passed elem_size and get it + * from the array object, to reduce the number of methods we generate: + * the additional cost is 3 memory loads and a non-immediate mul. + */ + for (i = 1; i < rank; ++i) { + /* realidx = idxi - bounds [i].lower_bound */ + mono_mb_emit_ldarg (mb, 1 + i); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_stloc (mb, realidx); + /* if (realidx >= bounds [i].length) goto exeception; */ + mono_mb_emit_ldloc (mb, realidx); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN); + /* ind = ind * bounds [i].length + realidx */ + mono_mb_emit_ldloc (mb, ind); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_ldloc (mb, realidx); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_stloc (mb, ind); + } - switch (encoding) { - case MONO_NATIVE_LPWSTR: - mono_mb_emit_icall (mb, mono_string_utf16_to_builder2); - break; - case MONO_NATIVE_LPSTR: - mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); - break; - case MONO_NATIVE_UTF8STR: - mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); - break; - default: - g_assert_not_reached (); - } + /* return array->vector + ind * element_size */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_ldloc (mb, ind); + if (elem_size) { + mono_mb_emit_icon (mb, elem_size); + } else { + /* Load arr->vtable->klass->sizes.element_class */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoObject, vtable)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I); + /* sizes is an union, so this reads sizes.element_size */ + mono_mb_emit_icon (mb, m_class_offsetof_sizes ()); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + } + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_RET); - mono_mb_emit_byte (mb, CEE_STIND_REF); - } else if (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN)) { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); + /* patch the branches to get here and throw */ + for (i = 1; i < rank; ++i) { + mono_mb_patch_branch (mb, branch_positions [i]); + } + mono_mb_patch_branch (mb, branch_pos); + /* throw exception */ + mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL); - mono_mb_emit_icall_id (mb, conv_to_icall (conv, NULL)); - } + g_free (branch_positions); +} - if (need_free) { - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall (mb, mono_marshal_free); - } - break; - } +static void +emit_delegate_begin_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig) +{ + int params_var; + params_var = mono_mb_emit_save_args (mb, sig, FALSE); - if (m_class_is_delegate (klass)) { - if (m_type_is_byref (t)) { - mono_mb_emit_ldarg (mb, argnum); - 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_byte (mb, CEE_STIND_REF); - } - break; - } + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldloc (mb, params_var); + mono_mb_emit_icall (mb, mono_delegate_begin_invoke); + mono_mb_emit_byte (mb, CEE_RET); +} - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { - /* allocate a new object */ - mono_mb_emit_ldarg (mb, argnum); - 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); - } +static void +emit_delegate_end_invoke_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig) +{ + int params_var; + params_var = mono_mb_emit_save_args (mb, sig, FALSE); - /* dst = *argument */ - mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldloc (mb, params_var); + mono_mb_emit_icall (mb, mono_delegate_end_invoke); - if (m_type_is_byref (t)) - mono_mb_emit_byte (mb, CEE_LDIND_I); + if (sig->ret->type == MONO_TYPE_VOID) { + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_byte (mb, CEE_RET); + } else + mono_mb_emit_restore_result (mb, sig->ret); +} - mono_mb_emit_stloc (mb, 1); +static void +emit_delegate_invoke_internal_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodSignature *invoke_sig, gboolean static_method_with_first_arg_bound, gboolean callvirt, gboolean closed_over_null, MonoMethod *method, MonoMethod *target_method, MonoClass *target_class, MonoGenericContext *ctx, MonoGenericContainer *container) +{ + int local_i, local_len, local_delegates, local_d, local_target, local_res = 0; + int pos0, pos1, pos2; + int i; + gboolean void_ret; - mono_mb_emit_ldloc (mb, 1); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + MonoType *int32_type = mono_get_int32_type (); + MonoType *object_type = mono_get_object_type (); - if (m_type_is_byref (t) || (t->attrs & PARAM_ATTRIBUTE_OUT)) { - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_stloc (mb, 1); + void_ret = sig->ret->type == MONO_TYPE_VOID && !method->string_ctor; - /* src = tmp_locals [i] */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_stloc (mb, 0); + /* allocate local 0 (object) */ + local_i = mono_mb_add_local (mb, int32_type); + local_len = mono_mb_add_local (mb, int32_type); + local_delegates = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.array_class)); + local_d = mono_mb_add_local (mb, m_class_get_byval_arg (mono_defaults.multicastdelegate_class)); + local_target = mono_mb_add_local (mb, object_type); - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + if (!void_ret) + local_res = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret))); - /* Free the structure returned by the native code */ - emit_struct_free (mb, klass, conv_arg); + g_assert (sig->hasthis); - if (m->orig_conv_args [argnum]) { - /* - * If the native function changed the pointer, then free - * the original structure plus the new pointer. - */ - mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]); - mono_mb_emit_ldloc (mb, conv_arg); - pos2 = mono_mb_emit_branch (mb, CEE_BEQ); + /* + * {type: sig->ret} res; + * if (delegates == null) { + * return this. ( args .. ); + * } else { + * int i = 0, len = this.delegates.Length; + * do { + * res = this.delegates [i].Invoke ( args .. ); + * } while (++i < len); + * return res; + * } + */ - if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { - g_assert (m->orig_conv_args [argnum]); + /* this wrapper can be used in unmanaged-managed transitions */ + emit_thread_interrupt_checkpoint (mb); - emit_struct_free (mb, klass, m->orig_conv_args [argnum]); - } + /* delegates = this.delegates */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoMulticastDelegate, delegates)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_stloc (mb, local_delegates); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icall (mb, mono_marshal_free); + /* if (delegates == null) */ + mono_mb_emit_ldloc (mb, local_delegates); + pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_patch_branch (mb, pos2); - } - } - else - /* Free the original structure passed to native code */ - emit_struct_free (mb, klass, conv_arg); + /* return target. ( args .. ); */ - mono_mb_patch_branch (mb, pos); - break; + /* target = d.target; */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, target)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_stloc (mb, local_target); - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; + /*static methods with bound first arg can have null target and still be bound*/ + if (!static_method_with_first_arg_bound) { + /* if target != null */ + mono_mb_emit_ldloc (mb, local_target); + pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE); - case MARSHAL_ACTION_CONV_RESULT: - if (m_class_is_delegate (klass)) { - g_assert (!m_type_is_byref (t)); - mono_mb_emit_stloc (mb, 0); - 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_stloc (mb, 3); - } else if (klass == mono_class_try_get_stringbuilder_class ()) { + /* then call this->method_ptr nonstatic */ + if (callvirt) { // FIXME: - char *msg = g_strdup_printf ("Return marshalling of stringbuilders is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_mb_emit_exception_full (mb, "System", "NotImplementedException", ""); } else { - /* set src */ - mono_mb_emit_stloc (mb, 0); + mono_mb_emit_ldloc (mb, local_target); + for (i = 0; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_LD_DELEGATE_METHOD_PTR); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig); + mono_mb_emit_byte (mb, CEE_RET); + } - /* Make a copy since emit_conv modifies local 0 */ - loc = mono_mb_add_local (mb, int_type); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_stloc (mb, loc); + /* else [target == null] call this->method_ptr static */ + mono_mb_patch_branch (mb, pos0); + } + if (callvirt) { + if (!closed_over_null) { + /* if target_method is not really virtual, turn it into a direct call */ + if (!(target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) || m_class_is_valuetype (target_class)) { + mono_mb_emit_ldarg (mb, 1); + for (i = 1; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALL, target_method); + } else { + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_op (mb, CEE_CASTCLASS, target_class); + for (i = 1; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALLVIRT, target_method); + } + } else { mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, 3); - - mono_mb_emit_ldloc (mb, 0); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + for (i = 0; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALL, target_method); + } + } else { + if (static_method_with_first_arg_bound) { + mono_mb_emit_ldloc (mb, local_target); + if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0])) + mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type_internal (invoke_sig->params[0])); + } + for (i = 0; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_LD_DELEGATE_METHOD_PTR); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig); + } - /* allocate result object */ + mono_mb_emit_byte (mb, CEE_RET); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); - mono_mb_emit_stloc (mb, 3); + /* else [delegates != null] */ + mono_mb_patch_branch (mb, pos2); - /* set dst */ + /* len = delegates.Length; */ + mono_mb_emit_ldloc (mb, local_delegates); + mono_mb_emit_byte (mb, CEE_LDLEN); + mono_mb_emit_byte (mb, CEE_CONV_I4); + mono_mb_emit_stloc (mb, local_len); - mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 1); + /* i = 0; */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, local_i); - /* emit conversion code */ - emit_struct_conv (mb, klass, TRUE); + pos1 = mono_mb_get_label (mb); - emit_struct_free (mb, klass, loc); + /* d = delegates [i]; */ + mono_mb_emit_ldloc (mb, local_delegates); + mono_mb_emit_ldloc (mb, local_i); + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + mono_mb_emit_stloc (mb, local_d); - /* Free the pointer allocated by unmanaged code */ - mono_mb_emit_ldloc (mb, loc); - mono_mb_emit_icall (mb, mono_marshal_free); - mono_mb_patch_branch (mb, pos); - } - break; + /* res = d.Invoke ( args .. ); */ + mono_mb_emit_ldloc (mb, local_d); + for (i = 0; i < sig->param_count; i++) + mono_mb_emit_ldarg (mb, i + 1); + if (!ctx) { + mono_mb_emit_op (mb, CEE_CALLVIRT, method); + } else { + ERROR_DECL (error); + mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method_checked (method, &container->context, error)); + g_assert (is_ok (error)); /* FIXME don't swallow the error */ + } - case MARSHAL_ACTION_MANAGED_CONV_IN: - conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass)); + if (!void_ret) + mono_mb_emit_stloc (mb, local_res); - if (m_class_is_delegate (klass)) { - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); - 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_stloc (mb, conv_arg); - break; - } + /* i += 1 */ + mono_mb_emit_add_to_local (mb, local_i, 1); - if (klass == mono_class_try_get_stringbuilder_class ()) { - MonoMarshalNative encoding; + /* i < l */ + mono_mb_emit_ldloc (mb, local_i); + mono_mb_emit_ldloc (mb, local_len); + mono_mb_emit_branch_label (mb, CEE_BLT, pos1); - encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + /* return res */ + if (!void_ret) + mono_mb_emit_ldloc (mb, local_res); + mono_mb_emit_byte (mb, CEE_RET); +} - // FIXME: - g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR); +static void +mb_skip_visibility_ilgen (MonoMethodBuilder *mb) +{ + mb->skip_visibility = 1; +} - g_assert (!m_type_is_byref (t)); - g_assert (encoding != -1); +static void +mb_set_dynamic_ilgen (MonoMethodBuilder *mb) +{ + mb->dynamic = 1; +} - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); - mono_mb_emit_stloc (mb, conv_arg); - break; - } +static void +emit_synchronized_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoGenericContext *ctx, MonoGenericContainer *container, MonoMethod *enter_method, MonoMethod *exit_method, MonoMethod *gettypefromhandle_method) +{ + int i, pos, pos2, this_local, taken_local, ret_local = 0; + MonoMethodSignature *sig = mono_method_signature_internal (method); + MonoExceptionClause *clause; - /* The class can not have an automatic layout */ - if (mono_class_is_auto_layout (klass)) { - mono_mb_emit_auto_layout_exception (mb, klass); - break; - } + /* result */ + if (!MONO_TYPE_IS_VOID (sig->ret)) + ret_local = mono_mb_add_local (mb, sig->ret); - if (t->attrs & PARAM_ATTRIBUTE_OUT) { - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - break; - } + if (m_class_is_valuetype (method->klass) && !(method->flags & MONO_METHOD_ATTR_STATIC)) { + /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */ + mono_class_set_type_load_failure (method->klass, ""); + /* This will throw the type load exception when the wrapper is compiled */ + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_op (mb, CEE_ISINST, method->klass); + mono_mb_emit_byte (mb, CEE_POP); - /* Set src */ - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) { - /* Check for NULL and raise an exception */ - pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE); + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_emit_ldloc (mb, ret_local); + mono_mb_emit_byte (mb, CEE_RET); - mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + return; + } - mono_mb_patch_branch (mb, pos2); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); - } + MonoType *object_type = mono_get_object_type (); + MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); + /* this */ + this_local = mono_mb_add_local (mb, object_type); + taken_local = mono_mb_add_local (mb, boolean_type); - mono_mb_emit_stloc (mb, 0); + clause = (MonoExceptionClause *)mono_image_alloc0 (get_method_image (method), sizeof (MonoExceptionClause)); + clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY; - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_stloc (mb, conv_arg); + /* Push this or the type object */ + if (method->flags & METHOD_ATTRIBUTE_STATIC) { + /* We have special handling for this in the JIT */ + int index = mono_mb_add_data (mb, method->klass); + mono_mb_add_data (mb, mono_defaults.typehandle_class); + mono_mb_emit_byte (mb, CEE_LDTOKEN); + mono_mb_emit_i4 (mb, index); - mono_mb_emit_ldloc (mb, 0); - pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL); + } + else + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_stloc (mb, this_local); - /* Create and set dst */ - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); - mono_mb_emit_stloc (mb, conv_arg); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 1); + clause->try_offset = mono_mb_get_label (mb); + /* Call Monitor::Enter() */ + mono_mb_emit_ldloc (mb, this_local); + mono_mb_emit_ldloc_addr (mb, taken_local); + mono_mb_emit_managed_call (mb, enter_method, NULL); - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, TRUE); + /* Call the method */ + if (sig->hasthis) + mono_mb_emit_ldarg (mb, 0); + for (i = 0; i < sig->param_count; i++) + mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE)); - mono_mb_patch_branch (mb, pos); - break; + if (ctx) { + ERROR_DECL (error); + mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, error), NULL); + g_assert (is_ok (error)); /* FIXME don't swallow the error */ + } else { + mono_mb_emit_managed_call (mb, method, NULL); + } - case MARSHAL_ACTION_MANAGED_CONV_OUT: - if (m_class_is_delegate (klass)) { - if (m_type_is_byref (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_byte (mb, stind_op); - break; - } - } + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_emit_stloc (mb, ret_local); - if (m_type_is_byref (t)) { - /* Check for null */ - mono_mb_emit_ldloc (mb, conv_arg); - pos = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_byte (mb, CEE_STIND_I); - pos2 = mono_mb_emit_branch (mb, CEE_BR); - - mono_mb_patch_branch (mb, pos); - - /* Set src */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 0); - - /* Allocate and set dest */ - mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); - mono_mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_icall (mb, ves_icall_marshal_alloc); - mono_mb_emit_stloc (mb, 1); + pos = mono_mb_emit_branch (mb, CEE_LEAVE); - /* Update argument pointer */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_STIND_I); + clause->try_len = mono_mb_get_pos (mb) - clause->try_offset; + clause->handler_offset = mono_mb_get_label (mb); - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); + /* Call Monitor::Exit() if needed */ + mono_mb_emit_ldloc (mb, taken_local); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldloc (mb, this_local); + mono_mb_emit_managed_call (mb, exit_method, NULL); + mono_mb_patch_branch (mb, pos2); + mono_mb_emit_byte (mb, CEE_ENDFINALLY); - mono_mb_patch_branch (mb, pos2); - } else if (klass == mono_class_try_get_stringbuilder_class ()) { - // FIXME: What to do here ? - } else { - /* byval [Out] marshalling */ + clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; - /* FIXME: Handle null */ + mono_mb_patch_branch (mb, pos); + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_emit_ldloc (mb, ret_local); + mono_mb_emit_byte (mb, CEE_RET); - /* Set src */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 0); + mono_mb_set_clauses (mb, 1, clause); +} - /* Set dest */ - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_stloc (mb, 1); +static void +emit_unbox_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method) +{ + MonoMethodSignature *sig = mono_method_signature_internal (method); - /* emit valuetype conversion code */ - emit_struct_conv (mb, klass, FALSE); - } - break; + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_byte (mb, CEE_ADD); + for (int i = 0; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_managed_call (mb, method, NULL); + mono_mb_emit_byte (mb, CEE_RET); +} - 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_stloc (mb, 3); - break; - } +static void +emit_array_accessor_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *sig, MonoGenericContext *ctx) +{ + MonoGenericContainer *container = NULL; + /* Call the method */ + if (sig->hasthis) + mono_mb_emit_ldarg (mb, 0); + for (int i = 0; i < sig->param_count; i++) + mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE)); - /* The class can not have an automatic layout */ - if (mono_class_is_auto_layout (klass)) { - mono_mb_emit_auto_layout_exception (mb, klass); - break; - } + if (ctx) { + ERROR_DECL (error); + mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, error), NULL); + g_assert (is_ok (error)); /* FIXME don't swallow the error */ + } else { + mono_mb_emit_managed_call (mb, method, NULL); + } + mono_mb_emit_byte (mb, CEE_RET); +} - mono_mb_emit_stloc (mb, 0); - /* Check for null */ - mono_mb_emit_ldloc (mb, 0); - pos = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, 3); - pos2 = mono_mb_emit_branch (mb, CEE_BR); +static void +emit_generic_array_helper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig) +{ + mono_mb_emit_ldarg (mb, 0); + for (int i = 0; i < csig->param_count; i++) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_managed_call (mb, method, NULL); + mono_mb_emit_byte (mb, CEE_RET); +} - mono_mb_patch_branch (mb, pos); +static void +emit_thunk_invoke_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *csig) +{ + MonoImage *image = get_method_image (method); + MonoMethodSignature *sig = mono_method_signature_internal (method); + int param_count = sig->param_count + sig->hasthis + 1; + int pos_leave, coop_gc_var = 0; + MonoExceptionClause *clause; + MonoType *object_type = mono_get_object_type (); +#if defined (TARGET_WASM) + const gboolean do_blocking_transition = FALSE; +#else + const gboolean do_blocking_transition = TRUE; +#endif - /* Set src */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); - mono_mb_emit_stloc (mb, 0); + /* local 0 (temp for exception object) */ + mono_mb_add_local (mb, object_type); - /* Allocate and set dest */ - mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); - mono_mb_emit_byte (mb, CEE_CONV_I); - mono_mb_emit_icall (mb, ves_icall_marshal_alloc); - mono_mb_emit_byte (mb, CEE_DUP); - mono_mb_emit_stloc (mb, 1); - mono_mb_emit_stloc (mb, 3); + /* local 1 (temp for result) */ + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_add_local (mb, sig->ret); - emit_struct_conv (mb, klass, FALSE); + if (do_blocking_transition) { + /* local 4, the local to be used when calling the suspend funcs */ + coop_gc_var = mono_mb_add_local (mb, mono_get_int_type ()); + } - mono_mb_patch_branch (mb, pos2); - break; + /* clear exception arg */ + mono_mb_emit_ldarg (mb, param_count - 1); + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); - default: - g_assert_not_reached (); + if (do_blocking_transition) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_GET_SP); + mono_mb_emit_icall (mb, mono_threads_enter_gc_unsafe_region_unbalanced); + mono_mb_emit_stloc (mb, coop_gc_var); } - return conv_arg; -} -static int -emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ -#ifndef DISABLE_COM - MonoMethodBuilder *mb = m->mb; - MonoType *variant_type = m_class_get_byval_arg (mono_class_get_variant_class ()); - MonoType *variant_type_byref = mono_class_get_byref_type (mono_class_get_variant_class ()); - MonoType *object_type = mono_get_object_type (); + /* try */ + clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause)); + clause->try_offset = mono_mb_get_label (mb); - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - conv_arg = mono_mb_add_local (mb, variant_type); + /* push method's args */ + for (int i = 0; i < param_count - 1; i++) { + MonoType *type; + MonoClass *klass; - if (m_type_is_byref (t)) - *conv_arg_type = variant_type_byref; - else - *conv_arg_type = variant_type; + mono_mb_emit_ldarg (mb, i); - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) - break; + /* get the byval type of the param */ + klass = mono_class_from_mono_type_internal (csig->params [i]); + type = m_class_get_byval_arg (klass); - mono_mb_emit_ldarg (mb, argnum); - if (m_type_is_byref (t)) - mono_mb_emit_byte(mb, CEE_LDIND_REF); - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); - break; - } + /* unbox struct args */ + if (MONO_TYPE_ISSTRUCT (type)) { + mono_mb_emit_op (mb, CEE_UNBOX, klass); - case MARSHAL_ACTION_CONV_OUT: { - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - } + /* byref args & and the "this" arg must remain a ptr. + Otherwise make a copy of the value type */ + if (!(m_type_is_byref (csig->params [i]) || (i == 0 && sig->hasthis))) + mono_mb_emit_op (mb, CEE_LDOBJ, klass); - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL); - break; + csig->params [i] = object_type; + } } - case MARSHAL_ACTION_PUSH: - if (m_type_is_byref (t)) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; + /* call */ + if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) + mono_mb_emit_op (mb, CEE_CALLVIRT, method); + else + mono_mb_emit_op (mb, CEE_CALL, method); - 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); - break; - } + /* save result at local 1 */ + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_emit_stloc (mb, 1); - case MARSHAL_ACTION_MANAGED_CONV_IN: { - conv_arg = mono_mb_add_local (mb, object_type); + pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE); - if (m_type_is_byref (t)) - *conv_arg_type = variant_type_byref; - else - *conv_arg_type = variant_type; + /* catch */ + clause->flags = MONO_EXCEPTION_CLAUSE_NONE; + clause->try_len = mono_mb_get_pos (mb) - clause->try_offset; + clause->data.catch_class = mono_defaults.object_class; - if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) - break; + clause->handler_offset = mono_mb_get_label (mb); - if (m_type_is_byref (t)) - mono_mb_emit_ldarg (mb, argnum); - else - mono_mb_emit_ldarg_addr (mb, argnum); - mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); - mono_mb_emit_stloc (mb, conv_arg); - break; - } + /* store exception at local 0 */ + mono_mb_emit_stloc (mb, 0); + mono_mb_emit_ldarg (mb, param_count - 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_branch (mb, CEE_LEAVE); - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); - } - break; - } + clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; - 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); - break; + mono_mb_set_clauses (mb, 1, clause); + + mono_mb_patch_branch (mb, pos_leave); + /* end-try */ + + if (!MONO_TYPE_IS_VOID (sig->ret)) { + mono_mb_emit_ldloc (mb, 1); + + /* box the return value */ + if (MONO_TYPE_ISSTRUCT (sig->ret)) + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (sig->ret)); } - default: - g_assert_not_reached (); + if (do_blocking_transition) { + mono_mb_emit_ldloc (mb, coop_gc_var); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_GET_SP); + mono_mb_emit_icall (mb, mono_threads_exit_gc_unsafe_region_unbalanced); } -#endif /* DISABLE_COM */ - return conv_arg; + mono_mb_emit_byte (mb, CEE_RET); } static gboolean @@ -6587,7 +2810,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 +2843,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 +3131,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 @@ -6955,21 +3178,7 @@ mono_marshal_ilgen_init (void) { MonoMarshalCallbacks cb; cb.version = MONO_MARSHAL_CALLBACKS_VERSION; - cb.emit_marshal_array = emit_marshal_array_ilgen; - cb.emit_marshal_ptr = emit_marshal_ptr_ilgen; cb.emit_marshal_scalar = emit_marshal_scalar_ilgen; -#ifndef DISABLE_NONBLITTABLE - cb.emit_marshal_boolean = emit_marshal_boolean_ilgen; - cb.emit_marshal_char = emit_marshal_char_ilgen; - cb.emit_marshal_custom = emit_marshal_custom_ilgen; - cb.emit_marshal_asany = emit_marshal_asany_ilgen; - cb.emit_marshal_vtype = emit_marshal_vtype_ilgen; - cb.emit_marshal_string = emit_marshal_string_ilgen; - cb.emit_marshal_safehandle = emit_marshal_safehandle_ilgen; - cb.emit_marshal_handleref = emit_marshal_handleref_ilgen; - cb.emit_marshal_object = emit_marshal_object_ilgen; - cb.emit_marshal_variant = emit_marshal_variant_ilgen; -#endif cb.emit_castclass = emit_castclass_ilgen; cb.emit_struct_to_ptr = emit_struct_to_ptr_ilgen; cb.emit_ptr_to_struct = emit_ptr_to_struct_ilgen; diff --git a/src/mono/mono/metadata/marshal-legacy-noilgen.c b/src/mono/mono/metadata/marshal-legacy-noilgen.c new file mode 100644 index 0000000000000..1aa60aa193618 --- /dev/null +++ b/src/mono/mono/metadata/marshal-legacy-noilgen.c @@ -0,0 +1,189 @@ +#include "config.h" + +#include "mono/metadata/attrdefs.h" +#include "metadata/marshal-internals.h" +#include "metadata/marshal.h" +#include "metadata/marshal-legacy.h" +#include "utils/mono-compiler.h" + +#ifndef ENABLE_ILGEN + +static int +emit_marshal_array_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = object_type; + break; + case MARSHAL_ACTION_MANAGED_CONV_IN: + *conv_arg_type = int_type; + break; + } + return conv_arg; +} + +static int +emit_marshal_ptr_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + return conv_arg; +} + +#endif + +#if !defined(ENABLE_ILGEN) || defined(DISABLE_NONBLITTABLE) + +static int +emit_marshal_boolean_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + if (m_type_is_byref (t)) + *conv_arg_type = int_type; + else + *conv_arg_type = mono_marshal_boolean_conv_in_get_local_type (spec, NULL); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + MonoClass* conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, NULL); + if (m_type_is_byref (t)) + *conv_arg_type = m_class_get_this_arg (conv_arg_class); + else + *conv_arg_type = m_class_get_byval_arg (conv_arg_class); + break; + } + + } + return conv_arg; +} + +static int +emit_marshal_char_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + return conv_arg; +} + +static int +emit_marshal_custom_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN && t->type == MONO_TYPE_VALUETYPE) + *conv_arg_type = int_type; + return conv_arg; +} + +static int +emit_marshal_asany_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + return conv_arg; +} + +static int +emit_marshal_vtype_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + return conv_arg; +} + +static int +emit_marshal_string_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = int_type; + break; + case MARSHAL_ACTION_MANAGED_CONV_IN: + *conv_arg_type = int_type; + break; + } + return conv_arg; +} + +static int +emit_marshal_safehandle_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN) + *conv_arg_type = int_type; + return conv_arg; +} + + +static int +emit_marshal_handleref_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN) + *conv_arg_type = int_type; + return conv_arg; +} + +static int +emit_marshal_object_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoType *int_type = mono_get_int_type (); + if (action == MARSHAL_ACTION_CONV_IN) + *conv_arg_type = int_type; + return conv_arg; +} + +static int +emit_marshal_variant_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + g_assert_not_reached (); +} + +void +mono_marshal_noilgen_legacy_init (void) +{ + MonoMarshalCallbacksLegacy legacy_cb; + + legacy_cb.emit_marshal_array = emit_marshal_array_noilgen; + legacy_cb.emit_marshal_ptr = emit_marshal_ptr_noilgen; + legacy_cb.emit_marshal_boolean = emit_marshal_boolean_noilgen; + legacy_cb.emit_marshal_char = emit_marshal_char_noilgen; + legacy_cb.emit_marshal_custom = emit_marshal_custom_noilgen; + legacy_cb.emit_marshal_asany = emit_marshal_asany_noilgen; + legacy_cb.emit_marshal_vtype = emit_marshal_vtype_noilgen; + legacy_cb.emit_marshal_string = emit_marshal_string_noilgen; + legacy_cb.emit_marshal_safehandle = emit_marshal_safehandle_noilgen; + legacy_cb.emit_marshal_handleref = emit_marshal_handleref_noilgen; + legacy_cb.emit_marshal_object = emit_marshal_object_noilgen; + legacy_cb.emit_marshal_variant = emit_marshal_variant_noilgen; +} + +#endif // if !defined(ENABLE_ILGEN) || defined(DISABLE_NONBLITTABLE) \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal-legacy.c b/src/mono/mono/metadata/marshal-legacy.c new file mode 100644 index 0000000000000..15aa7ad39ca82 --- /dev/null +++ b/src/mono/mono/metadata/marshal-legacy.c @@ -0,0 +1,2793 @@ +/** + * \file + * Copyright 2022 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#include "mono/metadata/debug-helpers.h" +#include "metadata/marshal.h" +#include "metadata/marshal-legacy.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 (date_time, "System", "DateTime"); +static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler"); + +static void +emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var); + + +static int +emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass = mono_class_from_mono_type_internal (t); + MonoMarshalNative encoding; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + + MonoClass *eklass = m_class_get_element_class (klass); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = object_type; + conv_arg = mono_mb_add_local (mb, object_type); + + if (m_class_is_blittable (eklass)) { + 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, 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_marshal_shared_emit_exception_marshal_directive (mb, msg); +#else + guint32 label1, label2, label3; + int index_var, src_var, dest_ptr, esize; + MonoMarshalConv conv; + gboolean is_string = FALSE; + + dest_ptr = mono_mb_add_local (mb, int_type); + + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + } + else if (eklass == mono_class_try_get_stringbuilder_class ()) { + is_string = TRUE; + conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); + } + else + conv = MONO_MARSHAL_CONV_INVALID; + + if (is_string && conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + src_var = mono_mb_add_local (mb, object_type); + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, src_var); + + /* Check null */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, src_var); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/ + esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; + else + esize = mono_class_native_size (eklass, NULL); + + /* allocate space for the native struct and store the address */ + mono_mb_emit_icon (mb, esize); + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + + if (eklass == mono_defaults.string_class) { + /* Make the array bigger for the terminating null */ + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_ADD); + } + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_LOCALLOC); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, dest_ptr); + + /* 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); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + + if (is_string) { + int stind_op; + mono_mb_emit_ldloc (mb, dest_ptr); + 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, mono_marshal_shared_conv_to_icall(conv, &stind_op)); + mono_mb_emit_byte (mb, stind_op); + } else { + /* set the src_ptr */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 0); + + /* set dst_ptr */ + mono_mb_emit_ldloc (mb, dest_ptr); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + 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); + mono_mb_emit_add_to_local (mb, dest_ptr, esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + + if (eklass == mono_defaults.string_class) { + /* Null terminate */ + mono_mb_emit_ldloc (mb, dest_ptr); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_STIND_I); + } + + mono_mb_patch_branch (mb, label1); +#endif + } + + break; + + case MARSHAL_ACTION_CONV_OUT: { +#ifndef DISABLE_NONBLITTABLE + gboolean need_convert, need_free; + /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */ + need_convert = ((eklass == mono_defaults.char_class) && (encoding == MONO_NATIVE_LPWSTR)) || (eklass == mono_class_try_get_stringbuilder_class ()) || (t->attrs & PARAM_ATTRIBUTE_OUT); + need_free = mono_marshal_need_free (m_class_get_byval_arg (eklass), m->piinfo, spec); + + if ((t->attrs & PARAM_ATTRIBUTE_OUT) && spec && spec->native == MONO_NATIVE_LPARRAY && spec->data.array_data.param_num != -1) { + int param_num = spec->data.array_data.param_num; + MonoType *param_type; + + param_type = m->sig->params [param_num]; + + if (m_type_is_byref (param_type) && param_type->type != MONO_TYPE_I4) { + char *msg = g_strdup ("Not implemented."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + if (m_type_is_byref (t) ) { + mono_mb_emit_ldarg (mb, argnum); + + /* Create the managed array */ + mono_mb_emit_ldarg (mb, param_num); + if (m_type_is_byref (m->sig->params [param_num])) + // FIXME: Support other types + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_CONV_OVF_I); + mono_mb_emit_op (mb, CEE_NEWARR, eklass); + /* Store into argument */ + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + } + + if (need_convert || need_free) { + /* FIXME: Optimize blittable case */ + guint32 label1, label2, label3; + int index_var, src_ptr, loc, esize; + + if ((eklass == mono_class_try_get_stringbuilder_class ()) || (eklass == mono_defaults.string_class)) + esize = TARGET_SIZEOF_VOID_P; + else if (eklass == mono_defaults.char_class) + esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; + else + esize = mono_class_native_size (eklass, NULL); + src_ptr = mono_mb_add_local (mb, int_type); + loc = mono_mb_add_local (mb, int_type); + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, src_ptr); + + /* 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); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + + if (eklass == mono_class_try_get_stringbuilder_class ()) { + gboolean need_free2; + MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2); + + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + /* dest */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + + /* src */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall(conv, NULL)); + + if (need_free) { + /* src */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall (mb, mono_marshal_free); + } + } + else if (eklass == mono_defaults.string_class) { + if (need_free) { + /* src */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_icall (mb, mono_marshal_free); + } + } + else { + if (need_convert) { + /* set the src_ptr */ + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_stloc (mb, 0); + + /* set dst_ptr */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1); + } + + if (need_free) { + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_stloc (mb, loc); + + emit_struct_free (mb, eklass, loc); + } + } + + mono_mb_emit_add_to_local (mb, index_var, 1); + mono_mb_emit_add_to_local (mb, src_ptr, esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); + } +#endif + + if (m_class_is_blittable (eklass)) { + /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */ + + mono_mb_emit_ldarg (mb, argnum); + 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, mono_marshal_shared_conv_to_icall(MONO_MARSHAL_FREE_LPARRAY, NULL)); + } + + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + guint32 label1, label2, label3; + int index_var, src_ptr, esize, param_num, num_elem; + MonoMarshalConv conv; + gboolean is_string = FALSE; + + conv_arg = mono_mb_add_local (mb, object_type); + *conv_arg_type = int_type; + + if (m_type_is_byref (t)) { + char *msg = g_strdup ("Byref array marshalling to managed code is not implemented."); + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + switch (spec->native) { + case MONO_NATIVE_LPARRAY: + break; + case MONO_NATIVE_SAFEARRAY: +#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_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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + } + + /* FIXME: t is from the method which is wrapped, not the delegate type */ + /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */ + + param_num = spec->data.array_data.param_num; + num_elem = spec->data.array_data.num_elem; + if (spec->data.array_data.elem_mult == 0) + /* param_num is not specified */ + param_num = -1; + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + } + + /* FIXME: Optimize blittable case */ + +#ifndef DISABLE_NONBLITTABLE + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + gboolean need_free; + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); + } + else if (eklass == mono_class_try_get_stringbuilder_class ()) { + is_string = TRUE; + gboolean need_free; + conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); + } + else + conv = MONO_MARSHAL_CONV_INVALID; +#endif + + mono_marshal_load_type_info (eklass); + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else + esize = mono_class_native_size (eklass, NULL); + src_ptr = mono_mb_add_local (mb, int_type); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + /* Check param index */ + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + switch (m->sig->params [param_num]->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + break; + default: { + char *msg = g_strdup ("Array size control parameter must be an integral type."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + } + } + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, src_ptr); + + /* Create managed array */ + /* + * The LPArray marshalling spec says that sometimes param_num starts + * from 1, sometimes it starts from 0. But MS seems to allways start + * from 0. + */ + + if (param_num == -1) { + mono_mb_emit_icon (mb, num_elem); + } else { + mono_mb_emit_ldarg (mb, param_num); + if (num_elem > 0) { + mono_mb_emit_icon (mb, num_elem); + mono_mb_emit_byte (mb, CEE_ADD); + } + mono_mb_emit_byte (mb, CEE_CONV_OVF_I); + } + + mono_mb_emit_op (mb, CEE_NEWARR, eklass); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_class_is_blittable (eklass)) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + mono_mb_emit_icon (mb, esize); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_patch_branch (mb, label1); + break; + } +#ifdef DISABLE_NONBLITTABLE + else { + char *msg = g_strdup ("Non-blittable marshalling conversion is disabled"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } +#else + /* 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); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + if (is_string) { + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, index_var); + + mono_mb_emit_ldloc (mb, src_ptr); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + mono_mb_emit_add_to_local (mb, index_var, 1); + mono_mb_emit_add_to_local (mb, src_ptr, esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); +#endif + + break; + } + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + guint32 label1, label2, label3; + int index_var, dest_ptr, esize, param_num, num_elem; + MonoMarshalConv conv; + gboolean is_string = FALSE; + + if (!spec) + /* Already handled in CONV_IN */ + break; + + /* These are already checked in CONV_IN */ + g_assert (!m_type_is_byref (t)); + g_assert (spec->native == MONO_NATIVE_LPARRAY); + g_assert (t->attrs & PARAM_ATTRIBUTE_OUT); + + param_num = spec->data.array_data.param_num; + num_elem = spec->data.array_data.num_elem; + + if (spec->data.array_data.elem_mult == 0) + /* param_num is not specified */ + param_num = -1; + + if (param_num == -1) { + if (num_elem <= 0) { + g_assert_not_reached (); + } + } + + /* FIXME: Optimize blittable case */ + +#ifndef DISABLE_NONBLITTABLE + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + } + else if (eklass == mono_class_try_get_stringbuilder_class ()) { + is_string = TRUE; + conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); + } + else + conv = MONO_MARSHAL_CONV_INVALID; +#endif + + mono_marshal_load_type_info (eklass); + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else + esize = mono_class_native_size (eklass, NULL); + + dest_ptr = mono_mb_add_local (mb, int_type); + + /* Check null */ + mono_mb_emit_ldloc (mb, conv_arg); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, dest_ptr); + + if (m_class_is_blittable (eklass)) { + /* dest */ + mono_mb_emit_ldarg (mb, argnum); + /* src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_byte (mb, CEE_ADD); + /* length */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + mono_mb_emit_icon (mb, esize); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + mono_mb_patch_branch (mb, label1); + break; + } + +#ifndef DISABLE_NONBLITTABLE + /* 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); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + if (is_string) { + int stind_op; + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + /* dest */ + mono_mb_emit_ldloc (mb, dest_ptr); + + /* src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, index_var); + + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + mono_mb_emit_add_to_local (mb, index_var, 1); + mono_mb_emit_add_to_local (mb, dest_ptr, esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); +#endif + + break; + } + case MARSHAL_ACTION_MANAGED_CONV_RESULT: { +#ifndef DISABLE_NONBLITTABLE + guint32 label1, label2, label3; + int index_var, src, dest, esize; + MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID; + gboolean is_string = FALSE; + + g_assert (!m_type_is_byref (t)); + + mono_marshal_load_type_info (eklass); + + if (eklass == mono_defaults.string_class) { + is_string = TRUE; + conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + } + else { + g_assert_not_reached (); + } + + if (is_string) + esize = TARGET_SIZEOF_VOID_P; + else if (eklass == mono_defaults.char_class) + esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1; + else + esize = mono_class_native_size (eklass, NULL); + + src = mono_mb_add_local (mb, object_type); + dest = mono_mb_add_local (mb, int_type); + + mono_mb_emit_stloc (mb, src); + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_stloc (mb, 3); + + /* Check for null */ + mono_mb_emit_ldloc (mb, src); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* Allocate native array */ + mono_mb_emit_icon (mb, esize); + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_byte (mb, CEE_LDLEN); + + if (eklass == mono_defaults.string_class) { + /* Make the array bigger for the terminating null */ + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_byte (mb, CEE_ADD); + } + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_stloc (mb, dest); + mono_mb_emit_ldloc (mb, dest); + mono_mb_emit_stloc (mb, 3); + + /* 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); + label2 = mono_mb_get_label (mb); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Emit marshalling code */ + if (is_string) { + int stind_op; + g_assert (conv != MONO_MARSHAL_CONV_INVALID); + + /* dest */ + mono_mb_emit_ldloc (mb, dest); + + /* src */ + mono_mb_emit_ldloc (mb, src); + mono_mb_emit_ldloc (mb, index_var); + + mono_mb_emit_byte (mb, CEE_LDELEM_REF); + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + + mono_mb_emit_add_to_local (mb, index_var, 1); + mono_mb_emit_add_to_local (mb, dest, esize); + + mono_mb_emit_branch_label (mb, CEE_BR, label2); + + mono_mb_patch_branch (mb, label3); + mono_mb_patch_branch (mb, label1); +#endif + break; + } + default: + g_assert_not_reached (); + } + return conv_arg; +} + + +static int +emit_marshal_ptr_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + /* MS seems to allow this in some cases, ie. bxc #158 */ + /* + 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_marshal_shared_mb_emit_exception_marshal_directive (m->mb, msg); + } + */ + break; + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* no conversions necessary */ + mono_mb_emit_stloc (mb, 3); + break; + + default: + break; + } + return conv_arg; +} + + +static int +emit_marshal_char_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + switch (action) { + case MARSHAL_ACTION_PUSH: + /* fixme: dont know how to marshal that. We cant simply + * convert it to a one byte UTF8 character, because an + * unicode character may need more that one byte in UTF8 */ + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* fixme: we need conversions here */ + mono_mb_emit_stloc (mb, 3); + break; + + default: + break; + } + return conv_arg; +} + +static int +emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass, *date_time_class; + int pos = 0, pos2; + + klass = mono_class_from_mono_type_internal (t); + + date_time_class = mono_class_get_date_time_class (); + + MonoType *int_type = mono_get_int_type (); + MonoType *double_type = m_class_get_byval_arg (mono_defaults.double_class); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + if (klass == date_time_class) { + /* Convert it to an OLE DATE type */ + + conv_arg = mono_mb_add_local (mb, double_type); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + if (!m_type_is_byref (t)) + m->csig->params [argnum - m->csig->hasthis] = double_type; + + MONO_STATIC_POINTER_INIT (MonoMethod, to_oadate) + 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) + + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, to_oadate, NULL); + mono_mb_emit_stloc (mb, conv_arg); + } + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + } + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + break; + + conv_arg = mono_mb_add_local (mb, int_type); + + /* store the address of the source into local variable 0 */ + if (m_type_is_byref (t)) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + + mono_mb_emit_stloc (mb, 0); + + /* allocate space for the native struct and + * store the address into local variable 1 (dest) */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_LOCALLOC); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + if (!(m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + /* set dst_ptr */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + } + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_PUSH: + if (spec && spec->native == MONO_NATIVE_LPSTRUCT) { + /* FIXME: */ + g_assert (!m_type_is_byref (t)); + + /* Have to change the signature since the vtype is passed byref */ + m->csig->params [argnum - m->csig->hasthis] = int_type; + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + mono_mb_emit_ldarg_addr (mb, argnum); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + } + + if (klass == date_time_class) { + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + } + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { + mono_mb_emit_ldarg (mb, argnum); + break; + } + mono_mb_emit_ldloc (mb, conv_arg); + if (!m_type_is_byref (t)) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass); + } + break; + + case MARSHAL_ACTION_CONV_OUT: + if (klass == date_time_class) { + /* Convert from an OLE DATE type */ + + if (!m_type_is_byref (t)) + break; + + if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { + + MONO_STATIC_POINTER_INIT (MonoMethod, from_oadate) + 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); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_managed_call (mb, from_oadate, NULL); + mono_mb_emit_op (mb, CEE_STOBJ, date_time_class); + } + break; + } + + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + break; + + if (m_type_is_byref (t)) { + /* dst = argument */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, 1); + + mono_mb_emit_ldloc (mb, 1); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { + /* src = tmp_locals [i] */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 0); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + } + } + + emit_struct_free (mb, klass, conv_arg); + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_CONV_RESULT: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass)) { + mono_mb_emit_stloc (mb, 3); + break; + } + + /* load pointer to returned value type */ + g_assert (m->vtaddr_var); + mono_mb_emit_ldloc (mb, m->vtaddr_var); + /* store the address of the source into local variable 0 */ + mono_mb_emit_stloc (mb, 0); + /* set dst_ptr */ + mono_mb_emit_ldloc_addr (mb, 3); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { + conv_arg = 0; + break; + } + + conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass)); + + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + if (m_type_is_byref (t)) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_stloc (mb, 0); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) + break; + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + + /* Check for null */ + mono_mb_emit_ldarg (mb, argnum); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* Set src */ + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_stloc (mb, 0); + + /* Set dest */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + if (mono_class_is_explicit_layout (klass) || m_class_is_blittable (klass) || m_class_is_enumtype (klass)) { + mono_mb_emit_stloc (mb, 3); + m->retobj_var = 0; + break; + } + + /* load pointer to returned value type */ + g_assert (m->vtaddr_var); + mono_mb_emit_ldloc (mb, m->vtaddr_var); + + /* store the address of the source into local variable 0 */ + mono_mb_emit_stloc (mb, 0); + /* allocate space for the native struct and + * store the address into dst_ptr */ + m->retobj_var = mono_mb_add_local (mb, int_type); + m->retobj_class = klass; + g_assert (m->retobj_var); + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_stloc (mb, 1); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, m->retobj_var); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; + +} + +static int +emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec); + gboolean need_free; + + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = int_type; + conv_arg = mono_mb_add_local (mb, int_type); + + if (m_type_is_byref (t)) { + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + } else { + mono_mb_emit_ldarg (mb, argnum); + } + + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } else { + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall(conv, NULL)); + + mono_mb_emit_stloc (mb, conv_arg); + } + break; + + case MARSHAL_ACTION_CONV_OUT: + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + if (encoding == MONO_NATIVE_VBBYREFSTR) { + + if (!m_type_is_byref (t)) { + char *msg = g_strdup ("VBByRefStr marshalling requires a ref parameter."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + MONO_STATIC_POINTER_INIT (MonoMethod, method) + + method = mono_marshal_shared_get_method_nofail (mono_defaults.string_class, "get_Length", -1, 0); + + MONO_STATIC_POINTER_INIT_END (MonoMethod, method) + + /* + * Have to allocate a new string with the same length as the original, and + * copy the contents of the buffer pointed to by CONV_ARG into it. + */ + g_assert (m_type_is_byref (t)); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_managed_call (mb, method, NULL); + mono_mb_emit_icall (mb, mono_string_new_len_wrapper); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { + int stind_op; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + 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; + } + + if (need_free) { + mono_mb_emit_ldloc (mb, conv_arg); + emit_string_free_icall (mb, conv); + } + break; + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t) && encoding != MONO_NATIVE_VBBYREFSTR) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: + mono_mb_emit_stloc (mb, 0); + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall(conv, NULL)); + mono_mb_emit_stloc (mb, 3); + + /* free the string */ + mono_mb_emit_ldloc (mb, 0); + emit_string_free_icall (mb, conv); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + conv_arg = mono_mb_add_local (mb, object_type); + + *conv_arg_type = int_type; + + if (m_type_is_byref (t)) { + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + } + + 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_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, mono_marshal_shared_conv_to_icall(conv, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (m_type_is_byref (t)) { + if (conv_arg) { + int stind_op; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + 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 (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, mono_marshal_shared_conv_to_icall(conv, NULL)); + mono_mb_emit_stloc (mb, 3); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_variant_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ +#ifndef DISABLE_COM + MonoMethodBuilder *mb = m->mb; + MonoType *variant_type = m_class_get_byval_arg (mono_class_get_variant_class ()); + MonoType *variant_type_byref = mono_class_get_byref_type (mono_class_get_variant_class ()); + MonoType *object_type = mono_get_object_type (); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + conv_arg = mono_mb_add_local (mb, variant_type); + + if (m_type_is_byref (t)) + *conv_arg_type = variant_type_byref; + else + *conv_arg_type = variant_type; + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte(mb, CEE_LDIND_REF); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); + break; + } + + case MARSHAL_ACTION_CONV_OUT: { + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL); + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + conv_arg = mono_mb_add_local (mb, object_type); + + if (m_type_is_byref (t)) + *conv_arg_type = variant_type_byref; + else + *conv_arg_type = variant_type; + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + if (m_type_is_byref (t)) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL); + } + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + default: + g_assert_not_reached (); + } +#endif /* DISABLE_COM */ + + return conv_arg; +} + +static int +emit_marshal_safehandle_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoType *int_type = mono_get_int_type (); + MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); + + switch (action){ + case MARSHAL_ACTION_CONV_IN: { + int dar_release_slot, pos; + + conv_arg = mono_mb_add_local (mb, int_type); + *conv_arg_type = int_type; + + 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); + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + + mono_mb_patch_branch (mb, pos); + + /* Create local to hold the ref parameter to DangerousAddRef */ + dar_release_slot = mono_mb_add_local (mb, boolean_type); + + /* set release = false; */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, dar_release_slot); + + if (m_type_is_byref (t)) { + int old_handle_value_slot = mono_mb_add_local (mb, int_type); + + if (!mono_marshal_shared_is_in (t)) { + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, conv_arg); + } else { + /* safehandle.DangerousAddRef (ref release) */ + 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, * mono_marshal_shared_get_sh_dangerous_add_ref (), NULL); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_stloc (mb, old_handle_value_slot); + } + } else { + /* 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, *mono_marshal_shared_get_sh_dangerous_add_ref(), NULL); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, conv_arg); + } + + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */ + int dar_release_slot = conv_arg + 1; + int label_next = 0; + + 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 (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, *mono_marshal_shared_get_sh_dangerous_release (), NULL); + mono_mb_patch_branch (mb, label_next); + } + + if (mono_marshal_shared_is_out (t)) { + ERROR_DECL (local_error); + MonoMethod *ctor; + + /* + * If the SafeHandle was marshalled on input we can skip the marshalling on + * output if the handle value is identical. + */ + 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); + label_next = mono_mb_emit_branch (mb, CEE_BEQ); + } + + /* + * Create an empty SafeHandle (of correct derived type). + * + * FIXME: If an out-of-memory situation or exception happens here we will + * leak the handle. We should move the allocation of the SafeHandle to the + * input marshalling code to prevent that. + */ + ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, local_error); + if (ctor == NULL || !is_ok (local_error)){ + mono_mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); + mono_error_cleanup (local_error); + break; + } + + /* refval = new SafeHandleDerived ()*/ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + /* refval.handle = returned_handle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_STIND_I); + + if (mono_marshal_shared_is_in (t) && label_next) { + mono_mb_patch_branch (mb, label_next); + } + } + } else { + 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, *mono_marshal_shared_get_sh_dangerous_release (), NULL); + mono_mb_patch_branch (mb, label_next); + } + break; + } + + case MARSHAL_ACTION_CONV_RESULT: { + ERROR_DECL (error); + MonoMethod *ctor = NULL; + int intptr_handle_slot; + + if (mono_class_is_abstract (t->data.klass)) { + mono_mb_emit_byte (mb, CEE_POP); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract")); + break; + } + + ctor = mono_class_get_method_from_name_checked (t->data.klass, ".ctor", 0, 0, error); + if (ctor == NULL || !is_ok (error)){ + mono_error_cleanup (error); + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_exception (mb, "MissingMethodException", "parameterless constructor required"); + break; + } + /* Store the IntPtr results into a local */ + intptr_handle_slot = mono_mb_add_local (mb, int_type); + mono_mb_emit_stloc (mb, intptr_handle_slot); + + /* Create return value */ + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_stloc (mb, 3); + + /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */ + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, intptr_handle_slot); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); + break; + default: + printf ("Unhandled case for MarshalAction: %d\n", action); + } + return conv_arg; +} + +static int +emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass = mono_class_from_mono_type_internal (t); + int pos, pos2, loc; + + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = int_type; + conv_arg = mono_mb_add_local (mb, int_type); + + m->orig_conv_args [argnum] = 0; + + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + if (m_class_is_delegate (klass)) { + 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_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, 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 ()) { + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); + +#if 0 + 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } + break; + } +#endif + + if (m_type_is_byref (t) && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + + if (conv == MONO_MARSHAL_CONV_INVALID) { + char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding); + 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, 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); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, pos); + break; + } else { + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t)) { + /* we dont need any conversions for out parameters */ + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + + } else { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); + } + + /* store the address of the source into local variable 0 */ + mono_mb_emit_stloc (mb, 0); + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* allocate space for the native struct and store the address */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_LOCALLOC); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t)) { + /* Need to store the original buffer so we can free it later */ + m->orig_conv_args [argnum] = mono_mb_add_local (mb, int_type); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]); + } + + /* set the src_ptr */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* set dst_ptr */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos); + } + break; + + case MARSHAL_ACTION_CONV_OUT: + if (klass == mono_class_try_get_stringbuilder_class ()) { + gboolean need_free; + MonoMarshalNative encoding; + MonoMarshalConv conv; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); + + g_assert (encoding != -1); + + if (m_type_is_byref (t)) { + //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT)); + + need_free = TRUE; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + switch (encoding) { + case MONO_NATIVE_LPWSTR: + mono_mb_emit_icall (mb, mono_string_utf16_to_builder2); + break; + case MONO_NATIVE_LPSTR: + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + break; + case MONO_NATIVE_UTF8STR: + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + break; + default: + g_assert_not_reached (); + } + + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else if (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN)) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + mono_mb_emit_icall_id (mb, mono_marshal_shared_conv_to_icall (conv, NULL)); + } + + if (need_free) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, mono_marshal_free); + } + break; + } + + if (m_class_is_delegate (klass)) { + if (m_type_is_byref (t)) { + mono_mb_emit_ldarg (mb, argnum); + 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, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + break; + } + + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) { + /* allocate a new object */ + mono_mb_emit_ldarg (mb, argnum); + 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); + } + + /* dst = *argument */ + mono_mb_emit_ldarg (mb, argnum); + + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_stloc (mb, 1); + + mono_mb_emit_ldloc (mb, 1); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (m_type_is_byref (t) || (t->attrs & PARAM_ATTRIBUTE_OUT)) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_icon (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_stloc (mb, 1); + + /* src = tmp_locals [i] */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_stloc (mb, 0); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + /* Free the structure returned by the native code */ + emit_struct_free (mb, klass, conv_arg); + + if (m->orig_conv_args [argnum]) { + /* + * If the native function changed the pointer, then free + * the original structure plus the new pointer. + */ + mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]); + mono_mb_emit_ldloc (mb, conv_arg); + pos2 = mono_mb_emit_branch (mb, CEE_BEQ); + + if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { + g_assert (m->orig_conv_args [argnum]); + + emit_struct_free (mb, klass, m->orig_conv_args [argnum]); + } + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, mono_marshal_free); + + mono_mb_patch_branch (mb, pos2); + } + } + else + /* Free the original structure passed to native code */ + emit_struct_free (mb, klass, conv_arg); + + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: + if (m_class_is_delegate (klass)) { + g_assert (!m_type_is_byref (t)); + mono_mb_emit_stloc (mb, 0); + 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, 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_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + } else { + /* set src */ + mono_mb_emit_stloc (mb, 0); + + /* Make a copy since emit_conv modifies local 0 */ + loc = mono_mb_add_local (mb, int_type); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, loc); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, 3); + + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* allocate result object */ + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_stloc (mb, 3); + + /* set dst */ + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 1); + + /* emit conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + emit_struct_free (mb, klass, loc); + + /* Free the pointer allocated by unmanaged code */ + mono_mb_emit_ldloc (mb, loc); + mono_mb_emit_icall (mb, mono_marshal_free); + mono_mb_patch_branch (mb, pos); + } + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass)); + + if (m_class_is_delegate (klass)) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + 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, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL)); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + if (klass == mono_class_try_get_stringbuilder_class ()) { + MonoMarshalNative encoding; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + + // FIXME: + g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR); + + g_assert (!m_type_is_byref (t)); + g_assert (encoding != -1); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + /* The class can not have an automatic layout */ + if (mono_class_is_auto_layout (klass)) { + mono_mb_emit_auto_layout_exception (mb, klass); + break; + } + + if (t->attrs & PARAM_ATTRIBUTE_OUT) { + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + /* Set src */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) { + /* Check for NULL and raise an exception */ + pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE); + + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + + mono_mb_patch_branch (mb, pos2); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_I); + } + + mono_mb_emit_stloc (mb, 0); + + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + + /* Create and set dst */ + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, TRUE); + + mono_mb_patch_branch (mb, pos); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (m_class_is_delegate (klass)) { + if (m_type_is_byref (t)) { + int stind_op; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + 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; + } + } + + if (m_type_is_byref (t)) { + /* Check for null */ + mono_mb_emit_ldloc (mb, conv_arg); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_STIND_I); + pos2 = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, pos); + + /* Set src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* Allocate and set dest */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_stloc (mb, 1); + + /* Update argument pointer */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_STIND_I); + + /* emit valuetype conversion code */ + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos2); + } else if (klass == mono_class_try_get_stringbuilder_class ()) { + // FIXME: What to do here ? + } else { + /* byval [Out] marshalling */ + + /* FIXME: Handle null */ + + /* Set src */ + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* Set dest */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_stloc (mb, 1); + + /* emit valuetype conversion code */ + 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, mono_marshal_shared_conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL)); + mono_mb_emit_stloc (mb, 3); + break; + } + + /* The class can not have an automatic layout */ + if (mono_class_is_auto_layout (klass)) { + mono_mb_emit_auto_layout_exception (mb, klass); + break; + } + + mono_mb_emit_stloc (mb, 0); + /* Check for null */ + mono_mb_emit_ldloc (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, 3); + pos2 = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, pos); + + /* Set src */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_ldflda (mb, MONO_ABI_SIZEOF (MonoObject)); + mono_mb_emit_stloc (mb, 0); + + /* Allocate and set dest */ + mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_icall (mb, ves_icall_marshal_alloc); + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_stloc (mb, 1); + mono_mb_emit_stloc (mb, 3); + + mono_marshal_shared_emit_struct_conv (mb, klass, FALSE); + + mono_mb_patch_branch (mb, pos2); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_boolean_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoType *int_type = mono_get_int_type (); + MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + MonoType *local_type; + int label_false; + guint8 ldc_op = CEE_LDC_I4_1; + + local_type = mono_marshal_boolean_conv_in_get_local_type (spec, &ldc_op); + if (m_type_is_byref (t)) + *conv_arg_type = int_type; + else + *conv_arg_type = local_type; + conv_arg = mono_mb_add_local (mb, local_type); + + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I1); + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, ldc_op); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_patch_branch (mb, label_false); + + break; + } + + case MARSHAL_ACTION_CONV_OUT: + { + int label_false, label_end; + if (!m_type_is_byref (t)) + break; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + + label_end = mono_mb_emit_branch (mb, CEE_BR); + mono_mb_patch_branch (mb, label_false); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_patch_branch (mb, label_end); + + mono_mb_emit_byte (mb, CEE_STIND_I1); + break; + } + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else if (conv_arg) + mono_mb_emit_ldloc (mb, conv_arg); + else + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* maybe we need to make sure that it fits within 8 bits */ + mono_mb_emit_stloc (mb, 3); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + MonoClass* conv_arg_class = mono_defaults.int32_class; + guint8 ldop = CEE_LDIND_I4; + int label_null, label_false; + + conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, &ldop); + conv_arg = mono_mb_add_local (mb, boolean_type); + + if (m_type_is_byref (t)) + *conv_arg_type = m_class_get_this_arg (conv_arg_class); + else + *conv_arg_type = m_class_get_byval_arg (conv_arg_class); + + + mono_mb_emit_ldarg (mb, argnum); + + /* Check null */ + if (m_type_is_byref (t)) { + label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, ldop); + } else + label_null = 0; + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_stloc (mb, conv_arg); + mono_mb_patch_branch (mb, label_false); + + if (m_type_is_byref (t)) + mono_mb_patch_branch (mb, label_null); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + guint8 stop = CEE_STIND_I4; + guint8 ldc_op = CEE_LDC_I4_1; + int label_null,label_false, label_end; + + if (!m_type_is_byref (t)) + break; + if (spec) { + switch (spec->native) { + case MONO_NATIVE_I1: + case MONO_NATIVE_U1: + stop = CEE_STIND_I1; + break; + case MONO_NATIVE_VARIANTBOOL: + stop = CEE_STIND_I2; + ldc_op = CEE_LDC_I4_M1; + break; + default: + break; + } + } + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, ldc_op); + label_end = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, label_false); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_patch_branch (mb, label_end); + + mono_mb_emit_byte (mb, stop); + mono_mb_patch_branch (mb, label_null); + break; + } + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_custom_ilgen_throw_exception (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg, MarshalAction action) +{ + /* Throw exception and emit compensation code, if neccesary */ + switch (action) { + case MARSHAL_ACTION_CONV_IN: + case MARSHAL_ACTION_MANAGED_CONV_IN: + case MARSHAL_ACTION_CONV_RESULT: + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT)) + mono_mb_emit_byte (mb, CEE_POP); + + mono_mb_emit_exception_full (mb, exc_nspace, exc_name, msg); + + break; + case MARSHAL_ACTION_PUSH: + mono_mb_emit_byte (mb, CEE_LDNULL); + break; + default: + break; + } + + return 0; +} + +static int +emit_marshal_custom_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + ERROR_DECL (error); + MonoType *mtype; + MonoClass *mklass; + static MonoClass *ICustomMarshaler = NULL; + static MonoMethod *cleanup_native, *cleanup_managed; + static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed; + MonoMethodBuilder *mb = m->mb; + MonoAssemblyLoadContext *alc = mono_alc_get_ambient (); + guint32 loc1; + int pos2; + + MonoType *int_type = mono_get_int_type (); + MonoType *object_type = mono_get_object_type (); + + if (!ICustomMarshaler) { + MonoClass *klass = mono_class_try_get_icustom_marshaler_class (); + if (!klass) + return emit_marshal_custom_ilgen_throw_exception (mb, "System", "ApplicationException", g_strdup ("Current profile doesn't support ICustomMarshaler"), action); + + cleanup_native = mono_marshal_shared_get_method_nofail (klass, "CleanUpNativeData", 1, 0); + g_assert (cleanup_native); + + cleanup_managed =mono_marshal_shared_get_method_nofail (klass, "CleanUpManagedData", 1, 0); + g_assert (cleanup_managed); + + marshal_managed_to_native = mono_marshal_shared_get_method_nofail (klass, "MarshalManagedToNative", 1, 0); + g_assert (marshal_managed_to_native); + + marshal_native_to_managed = mono_marshal_shared_get_method_nofail (klass, "MarshalNativeToManaged", 1, 0); + g_assert (marshal_native_to_managed); + + mono_memory_barrier (); + ICustomMarshaler = klass; + } + + if (spec->data.custom_data.image) + mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, spec->data.custom_data.image, error); + else + mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, alc, m->image, error); + + if (!mtype) + return emit_marshal_custom_ilgen_throw_exception (mb, "System", "TypeLoadException", g_strdup ("Failed to load ICustomMarshaler type"), action); + + mklass = mono_class_from_mono_type_internal (mtype); + g_assert (mklass != NULL); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + switch (t->type) { + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_VALUETYPE: + break; + + default: + g_warning ("custom marshalling of type %x is currently not supported", t->type); + g_assert_not_reached (); + break; + } + + conv_arg = mono_mb_add_local (mb, int_type); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + + /* Minic MS.NET behavior */ + if (!m_type_is_byref (t) && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN)) + break; + + /* Check for null */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (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_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + if (t->type == MONO_TYPE_VALUETYPE) { + /* + * Since we can't determine the type of the argument, we + * will assume the unmanaged function takes a pointer. + */ + *conv_arg_type = int_type; + + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t)); + } + + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_CONV_OUT: + /* Check for null */ + mono_mb_emit_ldloc (mb, conv_arg); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + 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_mb_emit_byte (mb, CEE_DUP); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); + + 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 (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_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_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + /* We have nowhere to store the result */ + mono_mb_emit_byte (mb, CEE_POP); + } + + // 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_mb_emit_ldloc (mb, conv_arg); + + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native); + } + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_PUSH: + if (m_type_is_byref (t)) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: + mono_mb_emit_stloc (mb, 3); + + /* Check for null */ + mono_mb_emit_ldloc (mb, 3); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + 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); + mono_mb_emit_stloc (mb, 3); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_IN: + switch (t->type) { + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_BOOLEAN: + break; + + default: + g_warning ("custom marshalling of type %x is currently not supported", t->type); + g_assert_not_reached (); + break; + } + + conv_arg = mono_mb_add_local (mb, object_type); + + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); + + if (m_type_is_byref (t) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + /* Check for null */ + mono_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (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_mb_emit_ldarg (mb, argnum); + if (m_type_is_byref (t)) + mono_mb_emit_byte (mb, CEE_LDIND_I); + + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + g_assert (!m_type_is_byref (t)); + + loc1 = mono_mb_add_local (mb, object_type); + + mono_mb_emit_stloc (mb, 3); + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_stloc (mb, loc1); + + /* Check for null */ + mono_mb_emit_ldloc (mb, 3); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + emit_marshal_custom_get_instance (mb, mklass, spec); + mono_mb_emit_byte (mb, CEE_DUP); + + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); + mono_mb_emit_stloc (mb, 3); + + mono_mb_emit_ldloc (mb, loc1); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); + + mono_mb_patch_branch (mb, pos2); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + + /* Check for null */ + mono_mb_emit_ldloc (mb, conv_arg); + pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + if (m_type_is_byref (t)) { + mono_mb_emit_ldarg (mb, argnum); + + 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); + mono_mb_emit_byte (mb, CEE_STIND_I); + } + + // 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_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); + } + + mono_mb_patch_branch (mb, pos2); + break; + + default: + g_assert_not_reached (); + } + return conv_arg; +} + + +static int +emit_marshal_asany_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + MonoType *int_type = mono_get_int_type (); + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL); + + g_assert (t->type == MONO_TYPE_OBJECT); + g_assert (!m_type_is_byref (t)); + + conv_arg = mono_mb_add_local (mb, int_type); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icon (mb, encoding); + mono_mb_emit_icon (mb, t->attrs); + mono_mb_emit_icall (mb, mono_marshal_asany); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icon (mb, encoding); + mono_mb_emit_icon (mb, t->attrs); + mono_mb_emit_icall (mb, mono_marshal_free_asany); + break; + } + + default: + g_assert_not_reached (); + } + return conv_arg; +} + +static int +emit_marshal_handleref_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + + MonoType *int_type = mono_get_int_type (); + switch (action){ + case MARSHAL_ACTION_CONV_IN: { + conv_arg = mono_mb_add_local (mb, int_type); + *conv_arg_type = int_type; + + if (m_type_is_byref (t)) { + char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + mono_mb_emit_ldarg_addr (mb, argnum); + 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_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_OUT: { + /* no resource release required */ + break; + } + + case MARSHAL_ACTION_CONV_RESULT: { + char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)"); + mono_marshal_shared_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); + break; + default: + fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action); + } + return conv_arg; +} + + +#ifdef ENABLE_ILGEN +void +mono_marshal_ilgen_legacy_init (void) +{ + MonoMarshalCallbacksLegacy cb; + cb.version = MONO_MARSHAL_CALLBACKS_VERSION; + cb.emit_marshal_array = emit_marshal_array_ilgen; + cb.emit_marshal_ptr = emit_marshal_ptr_ilgen; + cb.emit_marshal_char = emit_marshal_char_ilgen; + cb.emit_marshal_vtype = emit_marshal_vtype_ilgen; + cb.emit_marshal_string = emit_marshal_string_ilgen; + cb.emit_marshal_variant = emit_marshal_variant_ilgen; + cb.emit_marshal_safehandle = emit_marshal_safehandle_ilgen; + cb.emit_marshal_object = emit_marshal_object_ilgen; + cb.emit_marshal_boolean = emit_marshal_boolean_ilgen; + cb.emit_marshal_custom = emit_marshal_custom_ilgen; + cb.emit_marshal_asany = emit_marshal_asany_ilgen; + cb.emit_marshal_handleref = emit_marshal_handleref_ilgen; + +#ifdef DISABLE_NONBLITTABLE + mono_marshal_noilgen_init_blittable (&cb); +#endif + mono_install_marshal_callbacks_legacy (&cb); +} +#endif // ENABLE_ILGEN + +static gboolean legacy_cb_inited = FALSE; +static MonoMarshalCallbacksLegacy legacy_marshal_cb_static; +MonoMarshalCallbacksLegacy* get_marshal_legacy_cb (void) +{ + if (G_UNLIKELY (!legacy_cb_inited)) { +#ifdef ENABLE_ILGEN + mono_marshal_ilgen_legacy_init (); +#else + mono_marshal_noilgen_legacy_init (); +#endif + } + return &legacy_marshal_cb_static; +} + + +void +mono_install_marshal_callbacks_legacy (MonoMarshalCallbacksLegacy *cb) +{ + g_assert (!legacy_cb_inited); + g_assert (cb->version == MONO_MARSHAL_CALLBACKS_VERSION); + memcpy (&legacy_marshal_cb_static, cb, sizeof (MonoMarshalCallbacksLegacy)); + legacy_cb_inited = TRUE; +} + + +int +mono_emit_marshal_legacy (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action, MonoMarshalCallbacks* cb) +{ + MonoMarshalCallbacksLegacy* legacy_marshal_cb; + + legacy_marshal_cb = get_marshal_legacy_cb(); + + if (spec && spec->native == MONO_NATIVE_CUSTOM) + return legacy_marshal_cb->emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + if (spec && spec->native == MONO_NATIVE_ASANY) + return legacy_marshal_cb->emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + switch (t->type) { + case MONO_TYPE_VALUETYPE: + if (t->data.klass == mono_class_try_get_handleref_class ()) + return legacy_marshal_cb->emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + return legacy_marshal_cb->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_STRING: + return legacy_marshal_cb->emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: +#if !defined(DISABLE_COM) + if (spec && spec->native == MONO_NATIVE_STRUCT) + return legacy_marshal_cb->emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif + +#if !defined(DISABLE_COM) + if ((spec && (spec->native == MONO_NATIVE_IUNKNOWN || + spec->native == MONO_NATIVE_IDISPATCH || + spec->native == MONO_NATIVE_INTERFACE)) || + (t->type == MONO_TYPE_CLASS && mono_cominterop_is_interface(t->data.klass))) + return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); + if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && + (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && + ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH))) + return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif + + if (mono_class_try_get_safehandle_class () != NULL && t->data.klass && + mono_class_is_subclass_of_internal (t->data.klass, mono_class_try_get_safehandle_class (), FALSE)) + return legacy_marshal_cb->emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + return legacy_marshal_cb->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + return legacy_marshal_cb->emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_BOOLEAN: + return legacy_marshal_cb->emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_PTR: + return legacy_marshal_cb->emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_CHAR: + return legacy_marshal_cb->emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_FNPTR: + return cb->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_GENERICINST: + if (mono_type_generic_inst_is_valuetype (t)) + return legacy_marshal_cb->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); + else + return legacy_marshal_cb->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); + default: + return conv_arg; + } + +} + +static void +emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var) +{ + /* Call DestroyStructure */ + /* FIXME: Only do this if needed */ + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); + mono_mb_emit_ldloc (mb, struct_var); + mono_mb_emit_icall (mb, mono_struct_delete_old); +} \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal-legacy.h b/src/mono/mono/metadata/marshal-legacy.h new file mode 100644 index 0000000000000..b12c35f99f4c7 --- /dev/null +++ b/src/mono/mono/metadata/marshal-legacy.h @@ -0,0 +1,44 @@ +/** + * \file + * Copyright 2022 Microsoft + * Licensed under the MIT license. See LICENSE file in the project root for full license information. + */ +#ifndef __MARSHAL_LEGACY_H__ +#define __MARSHAL_LEGACY_H__ + +#include "metadata/marshal.h" + +typedef struct { + int version; + int (*emit_marshal_vtype) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_string) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_variant) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_safehandle) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_object) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_array) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_boolean) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_ptr) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_char) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_custom) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_asany) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); + int (*emit_marshal_handleref) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); +} MonoMarshalCallbacksLegacy; + +int +mono_emit_marshal_legacy (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action, MonoMarshalCallbacks *cb); + +void +mono_install_marshal_callbacks_legacy (MonoMarshalCallbacksLegacy *cb); + +#ifdef ENABLE_ILGEN +void +mono_marshal_ilgen_legacy_init (void); +#else +void +mono_marshal_noilgen_legacy_init (void); +#endif + + +#endif // __MARSHAL_LEGACY_H__ \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal-noilgen.c b/src/mono/mono/metadata/marshal-noilgen.c index 67350404c287e..06ce1e02fd3b5 100644 --- a/src/mono/mono/metadata/marshal-noilgen.c +++ b/src/mono/mono/metadata/marshal-noilgen.c @@ -6,32 +6,6 @@ #include "utils/mono-compiler.h" #ifndef ENABLE_ILGEN -static int -emit_marshal_array_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - MonoType *object_type = mono_get_object_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = object_type; - break; - case MARSHAL_ACTION_MANAGED_CONV_IN: - *conv_arg_type = int_type; - break; - } - return conv_arg; -} - -static int -emit_marshal_ptr_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - return conv_arg; -} static int emit_marshal_scalar_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, @@ -42,135 +16,6 @@ emit_marshal_scalar_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, } #endif -#if !defined(ENABLE_ILGEN) || defined(DISABLE_NONBLITTABLE) -static int -emit_marshal_boolean_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - if (m_type_is_byref (t)) - *conv_arg_type = int_type; - else - *conv_arg_type = mono_marshal_boolean_conv_in_get_local_type (spec, NULL); - break; - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - MonoClass* conv_arg_class = mono_marshal_boolean_managed_conv_in_get_conv_arg_class (spec, NULL); - if (m_type_is_byref (t)) - *conv_arg_type = m_class_get_this_arg (conv_arg_class); - else - *conv_arg_type = m_class_get_byval_arg (conv_arg_class); - break; - } - - } - return conv_arg; -} - -static int -emit_marshal_char_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - return conv_arg; -} - -static int -emit_marshal_custom_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN && t->type == MONO_TYPE_VALUETYPE) - *conv_arg_type = int_type; - return conv_arg; -} - -static int -emit_marshal_asany_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - return conv_arg; -} - -static int -emit_marshal_vtype_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - return conv_arg; -} - -static int -emit_marshal_string_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = int_type; - break; - case MARSHAL_ACTION_MANAGED_CONV_IN: - *conv_arg_type = int_type; - break; - } - return conv_arg; -} - -static int -emit_marshal_safehandle_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN) - *conv_arg_type = int_type; - return conv_arg; -} - - -static int -emit_marshal_handleref_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, int conv_arg, - MonoType **conv_arg_type, MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN) - *conv_arg_type = int_type; - return conv_arg; -} - -static int -emit_marshal_object_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoType *int_type = mono_get_int_type (); - if (action == MARSHAL_ACTION_CONV_IN) - *conv_arg_type = int_type; - return conv_arg; -} - -static int -emit_marshal_variant_noilgen (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - g_assert_not_reached (); -} -#endif #ifndef ENABLE_ILGEN static void @@ -368,19 +213,7 @@ mono_marshal_noilgen_init (void) { MonoMarshalCallbacks cb; cb.version = MONO_MARSHAL_CALLBACKS_VERSION; - cb.emit_marshal_array = emit_marshal_array_noilgen; - cb.emit_marshal_ptr = emit_marshal_ptr_noilgen; cb.emit_marshal_scalar = emit_marshal_scalar_noilgen; - cb.emit_marshal_boolean = emit_marshal_boolean_noilgen; - cb.emit_marshal_char = emit_marshal_char_noilgen; - cb.emit_marshal_custom = emit_marshal_custom_noilgen; - cb.emit_marshal_asany = emit_marshal_asany_noilgen; - cb.emit_marshal_vtype = emit_marshal_vtype_noilgen; - cb.emit_marshal_string = emit_marshal_string_noilgen; - cb.emit_marshal_safehandle = emit_marshal_safehandle_noilgen; - cb.emit_marshal_handleref = emit_marshal_handleref_noilgen; - cb.emit_marshal_object = emit_marshal_object_noilgen; - cb.emit_marshal_variant = emit_marshal_variant_noilgen; cb.emit_castclass = emit_castclass_noilgen; cb.emit_struct_to_ptr = emit_struct_to_ptr_noilgen; cb.emit_ptr_to_struct = emit_ptr_to_struct_noilgen; diff --git a/src/mono/mono/metadata/marshal-shared.c b/src/mono/mono/metadata/marshal-shared.c new file mode 100644 index 0000000000000..0cc1125311109 --- /dev/null +++ b/src/mono/mono/metadata/marshal-shared.c @@ -0,0 +1,1257 @@ +#include "metadata/marshal-shared.h" +#include "mono/metadata/debug-helpers.h" +#include "metadata/marshal.h" +#include "metadata/marshal-legacy.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 + +/* TODO: dedup */ +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"); + +static MonoMethod *sh_dangerous_add_ref = NULL; +static MonoMethod *sh_dangerous_release = NULL; + +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 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 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 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 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 +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); +} + +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) + mono_mb_emit_icall (mb, mono_free_bstr); + else + mono_mb_emit_icall (mb, mono_marshal_free); +} + +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); +} + +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); + } + } +} + +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) +{ + int i; + int fcount = mono_class_get_field_count (klass); + mono_class_setup_fields (klass); + MonoClassField *klass_fields = m_class_get_fields (klass); + for (i = 0; i < fcount; i++) { + if (!(klass_fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass_fields[i])) + return klass_fields[i].offset - 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) +{ + 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: { + 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; + } + +#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); + } + } +} + +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); +} \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal-shared.h b/src/mono/mono/metadata/marshal-shared.h new file mode 100644 index 0000000000000..7035c9e9f7f31 --- /dev/null +++ b/src/mono/mono/metadata/marshal-shared.h @@ -0,0 +1,78 @@ +#include "mono/metadata/debug-helpers.h" +#include "metadata/marshal.h" +#include "metadata/marshal-legacy.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_MARHSAL_SHARED_H_ +#define _MONO_METADATA_MARHSAL_SHARED_H_ + +MonoMethod** mono_marshal_shared_get_sh_dangerous_add_ref (void); +MonoMethod** mono_marshal_shared_get_sh_dangerous_release (void); + +void +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); + +/* TODO: This was inlined before */ +void +emit_string_free_icall (MonoMethodBuilder *mb, MonoMarshalConv conv); + +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); + +MonoMarshalCallbacksLegacy* get_marshal_legacy_cb (void); + +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_MARHSAL_SHARED_H_ */ \ No newline at end of file diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index d7f24a1e8d2f9..aa2dafb55e2bc 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -33,6 +33,7 @@ MONO_PRAGMA_WARNING_POP() #include "metadata/marshal.h" #include "metadata/marshal-internals.h" #include "metadata/marshal-ilgen.h" +#include "metadata/marshal-legacy.h" #include "metadata/method-builder.h" #include "metadata/method-builder-internals.h" #include "metadata/tabledefs.h" @@ -3157,75 +3158,7 @@ mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, if (!m->runtime_marshalling_enabled) return mono_emit_disabled_marshal (m, argnum, t, spec, conv_arg, conv_arg_type, action); - if (spec && spec->native == MONO_NATIVE_CUSTOM) - return get_marshal_cb ()->emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - if (spec && spec->native == MONO_NATIVE_ASANY) - return get_marshal_cb ()->emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - switch (t->type) { - case MONO_TYPE_VALUETYPE: - if (t->data.klass == mono_class_try_get_handleref_class ()) - return get_marshal_cb ()->emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - return get_marshal_cb ()->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_STRING: - return get_marshal_cb ()->emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: -#if !defined(DISABLE_COM) - if (spec && spec->native == MONO_NATIVE_STRUCT) - return get_marshal_cb ()->emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action); -#endif - -#if !defined(DISABLE_COM) - if ((spec && (spec->native == MONO_NATIVE_IUNKNOWN || - spec->native == MONO_NATIVE_IDISPATCH || - spec->native == MONO_NATIVE_INTERFACE)) || - (t->type == MONO_TYPE_CLASS && mono_cominterop_is_interface(t->data.klass))) - return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); - if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && - (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && - ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH))) - return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); -#endif - - if (mono_class_try_get_safehandle_class () != NULL && t->data.klass && - mono_class_is_subclass_of_internal (t->data.klass, mono_class_try_get_safehandle_class (), FALSE)) - return get_marshal_cb ()->emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); - - return get_marshal_cb ()->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - return get_marshal_cb ()->emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_BOOLEAN: - return get_marshal_cb ()->emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_PTR: - return get_marshal_cb ()->emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_CHAR: - return get_marshal_cb ()->emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_FNPTR: - return get_marshal_cb ()->emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); - case MONO_TYPE_GENERICINST: - if (mono_type_generic_inst_is_valuetype (t)) - return get_marshal_cb ()->emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); - else - return get_marshal_cb ()->emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); - default: - return conv_arg; - } + return mono_emit_marshal_legacy (m, argnum, t, spec, conv_arg, conv_arg_type, action, get_marshal_cb ()); } static void diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index 3d8706d241a03..14a45e684ad08 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -313,20 +313,6 @@ G_ENUM_FUNCTIONS(MonoNativeWrapperFlags); typedef struct { int version; - int (*emit_marshal_array) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_boolean) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_ptr) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_char) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_scalar) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - - int (*emit_marshal_custom) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_asany) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_vtype) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_string) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_safehandle) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_handleref) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_object) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); - int (*emit_marshal_variant) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); void (*emit_castclass) (MonoMethodBuilder *mb); void (*emit_struct_to_ptr) (MonoMethodBuilder *mb, MonoClass *klass); void (*emit_ptr_to_struct) (MonoMethodBuilder *mb, MonoClass *klass); @@ -357,6 +343,7 @@ typedef struct { void (*mb_emit_exception_for_error) (MonoMethodBuilder *mb, const MonoError *emitted_error); void (*mb_emit_byte) (MonoMethodBuilder *mb, guint8 op); void (*emit_marshal_directive_exception) (EmitMarshalContext *m, int argnum, const char* msg); + int (*emit_marshal_scalar) (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action); } MonoMarshalCallbacks; /*type of the function pointer of methods returned by mono_marshal_get_runtime_invoke*/