[runtime] Fix Mono BStr marshaling, cleanup IL generation (#35804)
authorRyan Lucia <rylucia@microsoft.com>
Thu, 28 May 2020 19:01:05 +0000 (15:01 -0400)
committerGitHub <noreply@github.com>
Thu, 28 May 2020 19:01:05 +0000 (15:01 -0400)
* [COM] Set and free BSTR size correctly

Apparently, while the previous 4 bytes contain the size, the actual allocation is either 4 or 8 bytes depending on the platform! See https://github.com/dotnet/runtime/blob/fcd862e06413a000f9cafa9d2f359226c60b9b42/src/coreclr/tests/src/Common/Platform/platformdefines.cpp#L418

* [meta] Cleanup string marshalling and support additional conversions

* [COM] Align BSTR creation to 16 bytes

* Enable test

* Feedback

* Fix offset

* Add support for AnsiBStr and TBStr marshalling

Also makes BStr changes netcore-only and enables AnsiBStr test. No TBStr test appears to exist.

* String marshaling IL gen refactoring

* Fix Windows build

* Feedback

src/coreclr/tests/issues.targets
src/mono/mono/metadata/cominterop.c
src/mono/mono/metadata/cominterop.h
src/mono/mono/metadata/icall-def.h
src/mono/mono/metadata/jit-icall-reg.h
src/mono/mono/metadata/marshal-ilgen.c
src/mono/mono/metadata/marshal.c
src/mono/mono/metadata/marshal.h
src/mono/mono/metadata/metadata.h

index 27080bf..5e22d18 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/SizeParamIndex/ReversePInvoke/PassingByRef/PassingByRefTest/**">
             <Issue>https://github.com/dotnet/runtime/issues/34196</Issue>
         </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/Interop/StringMarshalling/AnsiBSTR/AnsiBStrTest/**">
-            <Issue>needs triage</Issue>
-        </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/Interop/StringMarshalling/BSTR/BSTRTest/**">
-            <Issue>https://github.com/dotnet/runtime/issues/34375</Issue>
-        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/Interop/StringMarshalling/LPSTR/LPSTRTest/**">
             <Issue>needs triage</Issue>
         </ExcludeList>
index 94b8e24..cba6f96 100644 (file)
@@ -2988,6 +2988,26 @@ init_com_provider_ms (void)
 #endif // WIN32
 #endif // DISABLE_COM
 
+// This function is used regardless of the BSTR type, so cast the return value
+// Inputted string length, in bytes, should include the null terminator
+// Returns the start of the string itself
+static gpointer
+mono_bstr_alloc (size_t str_byte_len)
+{
+       // Allocate string length plus pointer-size integer to store the length, aligned to 16 bytes
+       size_t alloc_size = str_byte_len + SIZEOF_VOID_P;
+       alloc_size += (16 - 1);
+       alloc_size &= ~(16 - 1);
+       gpointer ret = g_malloc0 (alloc_size);
+       return ret ? (char *)ret + SIZEOF_VOID_P : NULL;
+}
+
+static void
+mono_bstr_set_length (gunichar2 *bstr, int slen)
+{
+       *((guint32 *)bstr - 1) = slen * sizeof (gunichar2);
+}
+
 /* PTR can be NULL */
 mono_bstr
 mono_ptr_to_bstr (const gunichar2* ptr, int slen)
@@ -2998,12 +3018,24 @@ mono_ptr_to_bstr (const gunichar2* ptr, int slen)
 #ifndef DISABLE_COM
        if (com_provider == MONO_COM_DEFAULT) {
 #endif
+               // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform.
+               // Presumably this is due to the BStr documentation page, which indicates that behavior and then directs you to call
+               // SysAllocString on Windows to handle the allocation for you. Unfortunately, this is not actually how it works:
+               // The allocation pre-string is pointer-sized, and then only 4 bytes are used for the length regardless. Additionally,
+               // the total length is also aligned to a 16-byte boundary. This preserves the old behavior on legacy and fixes it for
+               // netcore moving forward.
+#ifdef ENABLE_NETCORE
+               mono_bstr const s = (mono_bstr)mono_bstr_alloc ((slen + 1) * sizeof (gunichar2));
+               if (s == NULL)
+                       return NULL;
+#else
                /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
                guint32 * const ret = (guint32 *)g_malloc ((slen + 1) * sizeof (gunichar2) + sizeof (guint32));
                if (ret == NULL)
                        return NULL;
                mono_bstr const s = (mono_bstr)(ret + 1);
-               *ret = slen * sizeof (gunichar2);
+#endif
+               mono_bstr_set_length (s, slen);
                if (ptr)
                        memcpy (s, ptr, slen * sizeof (gunichar2));
                s [slen] = 0;
@@ -3024,7 +3056,21 @@ mono_ptr_to_bstr (const gunichar2* ptr, int slen)
 #endif
 }
 
-static MonoStringHandle
+char *
+mono_ptr_to_ansibstr (const char *ptr, size_t slen)
+{
+       // FIXME: should this behave differently without DISABLE_COM?
+       char *s = (char *)mono_bstr_alloc ((slen + 1) * sizeof(char));
+       if (s == NULL)
+               return NULL;
+       *((guint32 *)s - 1) = slen * sizeof (char);
+       if (ptr)
+               memcpy (s, ptr, slen * sizeof (char));
+       s [slen] = 0;
+       return s;
+}
+
+MonoStringHandle
 mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error)
 {
        if (!bstr)
@@ -3079,7 +3125,11 @@ mono_free_bstr (/*mono_bstr_const*/gpointer bstr)
 #ifndef DISABLE_COM
        if (com_provider == MONO_COM_DEFAULT) {
 #endif
+#ifdef ENABLE_NETCORE
+               g_free (((char *)bstr) - SIZEOF_VOID_P);
+#else // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform
                g_free (((char *)bstr) - 4);
+#endif
 #ifndef DISABLE_COM
        } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
                sys_free_string_ms ((mono_bstr_const)bstr);
index effe379..cc6380b 100644 (file)
@@ -58,6 +58,9 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum,
 MONO_API MONO_RT_EXTERNAL_ONLY MonoString *
 mono_string_from_bstr (/*mono_bstr*/gpointer bstr);
 
+MonoStringHandle
+mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error);
+
 MONO_API void 
 mono_free_bstr (/*mono_bstr_const*/gpointer bstr);
 
index 5b003c6..f4ceeec 100644 (file)
@@ -1168,15 +1168,18 @@ MONO_HANDLE_REGISTER_ICALL (mono_marshal_string_to_utf16_copy, gunichar2_ptr, 1,
 MONO_HANDLE_REGISTER_ICALL (mono_object_isinst_icall, MonoObject, 2, (MonoObject, MonoClass_ptr))
 MONO_HANDLE_REGISTER_ICALL (mono_string_builder_to_utf16, gunichar2_ptr, 1, (MonoStringBuilder))
 MONO_HANDLE_REGISTER_ICALL (mono_string_builder_to_utf8, char_ptr, 1, (MonoStringBuilder))
+MONO_HANDLE_REGISTER_ICALL (mono_string_from_ansibstr, MonoString, 1, (const_char_ptr))
 MONO_HANDLE_REGISTER_ICALL (mono_string_from_bstr_icall, MonoString, 1, (mono_bstr_const))
 MONO_HANDLE_REGISTER_ICALL (mono_string_from_byvalstr, MonoString, 2, (const_char_ptr, int))
 MONO_HANDLE_REGISTER_ICALL (mono_string_from_byvalwstr, MonoString, 2, (const_gunichar2_ptr, int))
+MONO_HANDLE_REGISTER_ICALL (mono_string_from_tbstr, MonoString, 1, (gpointer))
 MONO_HANDLE_REGISTER_ICALL (mono_string_new_len_wrapper, MonoString, 2, (const_char_ptr, guint))
 MONO_HANDLE_REGISTER_ICALL (mono_string_new_wrapper_internal, MonoString, 1, (const_char_ptr))
-MONO_HANDLE_REGISTER_ICALL (mono_string_to_ansibstr, gpointer, 1, (MonoString))
+MONO_HANDLE_REGISTER_ICALL (mono_string_to_ansibstr, char_ptr, 1, (MonoString))
 MONO_HANDLE_REGISTER_ICALL (mono_string_to_bstr, mono_bstr, 1, (MonoString))
 MONO_HANDLE_REGISTER_ICALL (mono_string_to_byvalstr, void, 3, (char_ptr, MonoString, int))
 MONO_HANDLE_REGISTER_ICALL (mono_string_to_byvalwstr, void, 3, (gunichar2_ptr, MonoString, int))
+MONO_HANDLE_REGISTER_ICALL (mono_string_to_tbstr, gpointer, 1, (MonoString))
 MONO_HANDLE_REGISTER_ICALL (mono_string_to_utf16_internal, mono_unichar2_ptr, 1, (MonoString))
 MONO_HANDLE_REGISTER_ICALL (mono_string_to_utf32_internal, mono_unichar4_ptr, 1, (MonoString)) // embedding API
 MONO_HANDLE_REGISTER_ICALL (mono_string_utf16_to_builder, void, 2, (MonoStringBuilder, const_gunichar2_ptr))
index a21b9f0..5b07e4c 100644 (file)
@@ -276,15 +276,18 @@ MONO_JIT_ICALL (mono_resume_unwind) \
 MONO_JIT_ICALL (mono_rethrow_preserve_exception) \
 MONO_JIT_ICALL (mono_string_builder_to_utf16) \
 MONO_JIT_ICALL (mono_string_builder_to_utf8) \
+MONO_JIT_ICALL (mono_string_from_ansibstr) \
 MONO_JIT_ICALL (mono_string_from_bstr_icall) \
 MONO_JIT_ICALL (mono_string_from_byvalstr) \
 MONO_JIT_ICALL (mono_string_from_byvalwstr) \
+MONO_JIT_ICALL (mono_string_from_tbstr) \
 MONO_JIT_ICALL (mono_string_new_len_wrapper) \
 MONO_JIT_ICALL (mono_string_new_wrapper_internal) \
 MONO_JIT_ICALL (mono_string_to_ansibstr) \
 MONO_JIT_ICALL (mono_string_to_bstr) \
 MONO_JIT_ICALL (mono_string_to_byvalstr) \
 MONO_JIT_ICALL (mono_string_to_byvalwstr) \
+MONO_JIT_ICALL (mono_string_to_tbstr) \
 MONO_JIT_ICALL (mono_string_to_utf16_internal) \
 MONO_JIT_ICALL (mono_string_to_utf8str) \
 MONO_JIT_ICALL (mono_string_utf16_to_builder) \
index 9a5202f..2235a8e 100644 (file)
@@ -113,6 +113,12 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
 static void
 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
 
+static MonoJitICallId
+conv_to_icall (MonoMarshalConv conv, int *ind_store_type);
+
+static MonoMarshalConv
+conv_str_inverse (MonoMarshalConv conv);
+
 /**
  * mono_mb_strdup:
  * \param mb the MethodBuilder
@@ -460,34 +466,22 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                }
                mono_mb_emit_byte (mb, CEE_STIND_REF);          
                break;          
-       case MONO_MARSHAL_CONV_STR_LPTSTR:
-               mono_mb_emit_ldloc (mb, 1);
-               mono_mb_emit_ldloc (mb, 0);
-               mono_mb_emit_byte (mb, CEE_LDIND_I);
-#ifdef TARGET_WIN32
-               mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
-#else
-               mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
-#endif
-               mono_mb_emit_byte (mb, CEE_STIND_REF);  
-               break;
 
-               // In Mono historically LPSTR was treated as a UTF8STR
-       case MONO_MARSHAL_CONV_STR_LPSTR:
+       case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+       case MONO_MARSHAL_CONV_STR_TBSTR:
        case MONO_MARSHAL_CONV_STR_UTF8STR:
-               mono_mb_emit_ldloc (mb, 1);
-               mono_mb_emit_ldloc (mb, 0);
-               mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
-               mono_mb_emit_byte (mb, CEE_STIND_REF);          
-               break;
        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 (mb, ves_icall_mono_string_from_utf16);
+               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;
@@ -576,9 +570,6 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                break;
        }
                
-       case MONO_MARSHAL_CONV_STR_BSTR:
-       case MONO_MARSHAL_CONV_STR_ANSIBSTR:
-       case MONO_MARSHAL_CONV_STR_TBSTR:
        case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
        default: {
                char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv);
@@ -589,6 +580,98 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
        }
 }
 
+// On legacy Mono, LPTSTR was either UTF16 or UTF8 depending on platform
+static inline MonoJitICallId
+mono_string_to_platform_unicode (void)
+{
+#ifdef TARGET_WIN32
+       return MONO_JIT_ICALL_mono_marshal_string_to_utf16;
+#else
+       return MONO_JIT_ICALL_mono_string_to_utf8str;
+#endif
+}
+
+static inline MonoJitICallId
+mono_string_from_platform_unicode (void)
+{
+#ifdef TARGET_WIN32
+       return MONO_JIT_ICALL_ves_icall_mono_string_from_utf16;
+#else
+       return MONO_JIT_ICALL_ves_icall_string_new_wrapper;
+#endif
+}
+
+static inline MonoJitICallId
+mono_string_builder_to_platform_unicode (void)
+{
+#ifdef TARGET_WIN32
+       return MONO_JIT_ICALL_mono_string_builder_to_utf16;
+#else
+       return MONO_JIT_ICALL_mono_string_builder_to_utf8;
+#endif
+}
+
+static inline MonoJitICallId
+mono_string_builder_from_platform_unicode (void)
+{
+#ifdef TARGET_WIN32
+       return MONO_JIT_ICALL_mono_string_utf16_to_builder;
+#else
+       return MONO_JIT_ICALL_mono_string_utf8_to_builder;
+#endif
+}
+
+static MonoMarshalConv
+conv_str_inverse (MonoMarshalConv conv)
+{
+       switch (conv) {
+       // AnsiBStr
+       case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+               return MONO_MARSHAL_CONV_ANSIBSTR_STR;
+       case MONO_MARSHAL_CONV_ANSIBSTR_STR:
+               return MONO_MARSHAL_CONV_STR_ANSIBSTR;
+
+       // BStr
+       case MONO_MARSHAL_CONV_STR_BSTR:
+               return MONO_MARSHAL_CONV_BSTR_STR;
+       case MONO_MARSHAL_CONV_BSTR_STR:
+               return MONO_MARSHAL_CONV_STR_BSTR;
+
+       // LPStr
+       case MONO_MARSHAL_CONV_STR_LPSTR:
+               return MONO_MARSHAL_CONV_LPSTR_STR;
+       case MONO_MARSHAL_CONV_LPSTR_STR:
+               return MONO_MARSHAL_CONV_STR_LPSTR;
+
+       // LPTStr
+       case MONO_MARSHAL_CONV_STR_LPTSTR:
+               return MONO_MARSHAL_CONV_LPTSTR_STR;
+       case MONO_MARSHAL_CONV_LPTSTR_STR:
+               return MONO_MARSHAL_CONV_STR_LPTSTR;
+
+       // LPUTF8Str
+       case MONO_MARSHAL_CONV_STR_UTF8STR:
+               return MONO_MARSHAL_CONV_UTF8STR_STR;
+       case MONO_MARSHAL_CONV_UTF8STR_STR:
+               return MONO_MARSHAL_CONV_STR_UTF8STR;
+
+       // LPWStr
+       case MONO_MARSHAL_CONV_STR_LPWSTR:
+               return MONO_MARSHAL_CONV_LPWSTR_STR;
+       case MONO_MARSHAL_CONV_LPWSTR_STR:
+               return MONO_MARSHAL_CONV_STR_LPWSTR;
+
+       // TBStr
+       case MONO_MARSHAL_CONV_STR_TBSTR:
+               return MONO_MARSHAL_CONV_TBSTR_STR;
+       case MONO_MARSHAL_CONV_TBSTR_STR:
+               return MONO_MARSHAL_CONV_STR_TBSTR;
+
+       default:
+               g_assert_not_reached ();
+       }
+}
+
 static MonoJitICallId
 conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
 {
@@ -602,78 +685,100 @@ conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
                ind_store_type = &dummy;
        *ind_store_type = CEE_STIND_I;
        switch (conv) {
-       case MONO_MARSHAL_CONV_STR_LPWSTR:
-               return MONO_JIT_ICALL_mono_marshal_string_to_utf16;
-       case MONO_MARSHAL_CONV_LPWSTR_STR:
+       // 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_ves_icall_mono_string_from_utf16;
-       case MONO_MARSHAL_CONV_LPTSTR_STR:
+               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_ves_icall_string_new_wrapper;
-       case MONO_MARSHAL_CONV_UTF8STR_STR:
+               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:
-#ifdef TARGET_WIN32
-               return MONO_JIT_ICALL_mono_marshal_string_to_utf16;
-#else
-               return MONO_JIT_ICALL_mono_string_to_utf8str;
-#endif
-               // In Mono historically LPSTR was treated as a UTF8STR
+               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:
-       case MONO_MARSHAL_CONV_STR_LPSTR:
                return MONO_JIT_ICALL_mono_string_to_utf8str;
-       case MONO_MARSHAL_CONV_STR_BSTR:
-               return MONO_JIT_ICALL_mono_string_to_bstr;
-       case MONO_MARSHAL_CONV_BSTR_STR:
+       case MONO_MARSHAL_CONV_UTF8STR_STR:
                *ind_store_type = CEE_STIND_REF;
-               return MONO_JIT_ICALL_mono_string_from_bstr_icall;
-       case MONO_MARSHAL_CONV_STR_TBSTR:
-       case MONO_MARSHAL_CONV_STR_ANSIBSTR:
-               return MONO_JIT_ICALL_mono_string_to_ansibstr;
+               return MONO_JIT_ICALL_ves_icall_string_new_wrapper;
        case MONO_MARSHAL_CONV_SB_UTF8STR:
-       case MONO_MARSHAL_CONV_SB_LPSTR:
-               return MONO_JIT_ICALL_mono_string_builder_to_utf8;
-       case MONO_MARSHAL_CONV_SB_LPTSTR:
-#ifdef TARGET_WIN32
-               return MONO_JIT_ICALL_mono_string_builder_to_utf16;
-#else
                return MONO_JIT_ICALL_mono_string_builder_to_utf8;
-#endif
-       case MONO_MARSHAL_CONV_SB_LPWSTR:
-               return MONO_JIT_ICALL_mono_string_builder_to_utf16;
-       case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
-               return MONO_JIT_ICALL_mono_array_to_savearray;
-       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;
-       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_UTF8STR_SB:
-       case MONO_MARSHAL_CONV_LPSTR_SB:
                *ind_store_type = CEE_STIND_REF;
                return MONO_JIT_ICALL_mono_string_utf8_to_builder;
-       case MONO_MARSHAL_CONV_LPTSTR_SB:
+
+       // 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;
-#ifdef TARGET_WIN32
-               return MONO_JIT_ICALL_mono_string_utf16_to_builder;
-#else
-               return MONO_JIT_ICALL_mono_string_utf8_to_builder;
-#endif
+               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;
-       case MONO_MARSHAL_FREE_ARRAY:
-               return MONO_JIT_ICALL_mono_marshal_free_array;
+
+       // 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 ();
        }
@@ -701,7 +806,6 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_byte (mb, CEE_NEG);
                mono_mb_emit_byte (mb, CEE_STIND_I2);
                break;
-       // In Mono historically LPSTR was treated as a UTF8STR
        case MONO_MARSHAL_CONV_STR_UTF8STR:
        case MONO_MARSHAL_CONV_STR_LPWSTR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
@@ -4988,6 +5092,15 @@ emit_marshal_vtype_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
        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, 
@@ -5071,10 +5184,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
 
                if (need_free) {
                        mono_mb_emit_ldloc (mb, conv_arg);
-                       if (conv == MONO_MARSHAL_CONV_BSTR_STR)
-                               mono_mb_emit_icall (mb, mono_free_bstr);
-                       else
-                               mono_mb_emit_icall (mb, mono_marshal_free);
+                       emit_string_free_icall (mb, conv);
                }
                break;
 
@@ -5101,10 +5211,7 @@ emit_marshal_string_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* free the string */
                mono_mb_emit_ldloc (mb, 0);
-               if (conv == MONO_MARSHAL_CONV_BSTR_STR)
-                       mono_mb_emit_icall (mb, mono_free_bstr);
-               else
-                       mono_mb_emit_icall (mb, mono_marshal_free);
+               emit_string_free_icall (mb, conv);
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_IN:
index 30b6b55..bec2c30 100644 (file)
@@ -206,12 +206,15 @@ mono_marshal_init (void)
                register_icall (ves_icall_mono_string_from_utf16, mono_icall_sig_obj_ptr, FALSE);
                register_icall (mono_string_from_byvalstr, mono_icall_sig_obj_ptr_int, FALSE);
                register_icall (mono_string_from_byvalwstr, mono_icall_sig_obj_ptr_int, FALSE);
+               register_icall (mono_string_from_ansibstr, mono_icall_sig_obj_ptr, FALSE);
+               register_icall (mono_string_from_tbstr, mono_icall_sig_obj_ptr, FALSE);
                register_icall (mono_string_new_wrapper_internal, mono_icall_sig_obj_ptr, FALSE);
                register_icall (ves_icall_string_new_wrapper, mono_icall_sig_obj_ptr, FALSE);
                register_icall (mono_string_new_len_wrapper, mono_icall_sig_obj_ptr_int, FALSE);
                register_icall (ves_icall_mono_string_to_utf8, mono_icall_sig_ptr_obj, FALSE);
                register_icall (mono_string_to_utf8str, mono_icall_sig_ptr_obj, FALSE);
                register_icall (mono_string_to_ansibstr, mono_icall_sig_ptr_object, FALSE);
+               register_icall (mono_string_to_tbstr, mono_icall_sig_ptr_object, FALSE);
                register_icall (mono_string_builder_to_utf8, mono_icall_sig_ptr_object, FALSE);
                register_icall (mono_string_builder_to_utf16, mono_icall_sig_ptr_object, FALSE);
                register_icall (mono_array_to_savearray, mono_icall_sig_ptr_object, FALSE);
@@ -992,11 +995,52 @@ mono_string_to_utf8str_impl (MonoStringHandle s, MonoError *error)
 
 #endif
 
-gpointer
+// Assume ANSI == UTF8 for now, same as LPSTR
+
+/* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
+char *
 mono_string_to_ansibstr_impl (MonoStringHandle string_obj, MonoError *error)
 {
-       g_error ("UnmanagedMarshal.BStr is not implemented.");
-       return NULL;
+       if (MONO_HANDLE_IS_NULL (string_obj))
+               return NULL;
+
+       char *utf8_str = mono_string_handle_to_utf8 (string_obj, error);
+       return_val_if_nok (error, NULL);
+       char *res = mono_ptr_to_ansibstr (utf8_str, g_utf8_strlen (utf8_str, -1));
+       g_free (utf8_str);
+       return res;
+}
+
+/* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
+MonoStringHandle
+mono_string_from_ansibstr_impl (const char *data, MonoError *error)
+{
+       if (!data)
+               return NULL_HANDLE_STRING;
+
+       return mono_string_new_utf8_len (mono_domain_get (), data, *((guint32 *)data - 1) / sizeof (char), error);
+}
+
+/* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
+gpointer
+mono_string_to_tbstr_impl (MonoStringHandle string_obj, MonoError *error)
+{
+#ifdef TARGET_WIN32
+       return mono_string_to_bstr_impl (string_obj, error);
+#else
+       return mono_string_to_ansibstr_impl (string_obj, error);
+#endif
+}
+
+/* This is a JIT icall, it sets the pending exception (in wrapper) and returns NULL on error. */
+MonoStringHandle
+mono_string_from_tbstr_impl (gpointer data, MonoError *error)
+{
+#ifdef TARGET_WIN32
+       return mono_string_from_bstr_checked ((mono_bstr)data, error);
+#else
+       return mono_string_from_ansibstr_impl ((char *)data, error);
+#endif
 }
 
 /**
@@ -1332,6 +1376,10 @@ mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
                return MONO_MARSHAL_CONV_STR_BSTR;
        case MONO_NATIVE_UTF8STR:
                return MONO_MARSHAL_CONV_STR_UTF8STR;
+       case MONO_NATIVE_ANSIBSTR:
+               return MONO_MARSHAL_CONV_STR_ANSIBSTR;
+       case MONO_NATIVE_TBSTR:
+               return MONO_MARSHAL_CONV_STR_TBSTR;
        default:
                return MONO_MARSHAL_CONV_INVALID;
        }
@@ -1379,6 +1427,10 @@ mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
                return MONO_MARSHAL_CONV_LPTSTR_STR;
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_BSTR_STR;
+       case MONO_NATIVE_ANSIBSTR:
+               return MONO_MARSHAL_CONV_ANSIBSTR_STR;
+       case MONO_NATIVE_TBSTR:
+               return MONO_MARSHAL_CONV_TBSTR_STR;
        default:
                return MONO_MARSHAL_CONV_INVALID;
        }
@@ -5597,11 +5649,12 @@ mono_struct_delete_old (MonoClass *klass, char *ptr)
                        break;
 #endif
                case MONO_MARSHAL_CONV_STR_LPSTR:
-               case MONO_MARSHAL_CONV_STR_ANSIBSTR:
-               case MONO_MARSHAL_CONV_STR_TBSTR:
                case MONO_MARSHAL_CONV_STR_UTF8STR:
                        mono_marshal_free (*(gpointer *)cpos);
                        break;
+
+               case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+               case MONO_MARSHAL_CONV_STR_TBSTR:
                case MONO_MARSHAL_CONV_STR_BSTR:
                        mono_free_bstr (*(gpointer*)cpos);
                        break;
index 3442a45..0d35659 100644 (file)
@@ -382,6 +382,9 @@ mono_type_native_stack_size (MonoType *type, guint32 *alignment);
 mono_bstr
 mono_ptr_to_bstr (const gunichar2* ptr, int slen);
 
+char *
+mono_ptr_to_ansibstr (const char *ptr, size_t slen);
+
 void mono_delegate_free_ftnptr (MonoDelegate *delegate);
 
 void
index c69d042..5bda9a3 100644 (file)
@@ -171,7 +171,9 @@ typedef enum {
        MONO_MARSHAL_CONV_SB_UTF8STR,
        MONO_MARSHAL_CONV_UTF8STR_STR,
        MONO_MARSHAL_CONV_UTF8STR_SB,
-       MONO_MARSHAL_CONV_FIXED_BUFFER
+       MONO_MARSHAL_CONV_FIXED_BUFFER,
+       MONO_MARSHAL_CONV_ANSIBSTR_STR,
+       MONO_MARSHAL_CONV_TBSTR_STR
 } MonoMarshalConv;
 
 #define MONO_MARSHAL_CONV_INVALID ((MonoMarshalConv)-1)