[runtime] Implement support for SuppressGCTransitionAttribute. (mono/mono#17534)
authorZoltan Varga <vargaz@gmail.com>
Mon, 28 Oct 2019 14:59:53 +0000 (10:59 -0400)
committerAleksey Kliger (λgeek) <alklig@microsoft.com>
Mon, 28 Oct 2019 14:59:52 +0000 (10:59 -0400)
Fixes https://github.com/mono/mono/issues/17367.

Commit migrated from https://github.com/mono/mono/commit/e4cc70f4b5038ec5d6500ba988d0bb67143658bc

src/mono/mono/metadata/cominterop.c
src/mono/mono/metadata/marshal-ilgen.c
src/mono/mono/metadata/marshal.c
src/mono/mono/metadata/marshal.h

index 20f6129..299beab 100644 (file)
@@ -1008,7 +1008,7 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method)
                }
        }
 
-       mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
+       mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE, FALSE);
 
        res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);      
 
index d751f29..35cd3a1 100644 (file)
@@ -1865,11 +1865,12 @@ gc_safe_transition_builder_cleanup (GCSafeTransitionBuilder *builder)
  * \param method if non-NULL, the pinvoke method to call
  * \param check_exceptions Whenever to check for pending exceptions after the native call
  * \param func_param the function to call is passed as a boxed IntPtr as the first parameter
+ * \param skip_gc_trans Whenever to skip GC transitions
  *
  * generates IL code for the pinvoke wrapper, the generated code calls \p func .
  */
 static void
-emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param)
+emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans)
 {
        EmitMarshalContext m;
        MonoMethodSignature *csig;
@@ -1884,7 +1885,8 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi
        m.sig = sig;
        m.piinfo = piinfo;
 
-       need_gc_safe = gc_safe_transition_builder_init (&gc_safe_transition_builder, mb, func_param);
+       if (!skip_gc_trans)
+               need_gc_safe = gc_safe_transition_builder_init (&gc_safe_transition_builder, mb, func_param);
 
        /* we copy the signature, so that we can set pinvoke to 0 */
        if (func_param) {
index be89c4d..df78309 100644 (file)
@@ -111,6 +111,10 @@ delegate_hash_table_remove (MonoDelegate *d);
 GENERATE_TRY_GET_CLASS_WITH_CACHE (stringbuilder, "System.Text", "StringBuilder");
 static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
 
+#ifdef ENABLE_NETCORE
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute")
+#endif
+
 static MonoImage*
 get_method_image (MonoMethod *method)
 {
@@ -3464,6 +3468,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
        MonoMethod *res;
        GHashTable *cache;
        gboolean pinvoke = FALSE;
+       gboolean skip_gc_trans = FALSE;
        gpointer iter;
        int i;
        ERROR_DECL (emitted_error);
@@ -3631,7 +3636,31 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
        mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
        mono_method_get_marshal_info (method, mspecs);
 
-       mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, aot, check_exceptions, FALSE);
+#ifdef ENABLE_NETCORE
+       if (mono_class_try_get_suppress_gc_transition_attribute_class ()) {
+               MonoCustomAttrInfo *cinfo;
+               ERROR_DECL (error);
+
+               cinfo = mono_custom_attrs_from_method_checked (method, error);
+               mono_error_assert_ok (error);
+               gboolean found = FALSE;
+               if (cinfo) {
+                       for (i = 0; i < cinfo->num_attrs; ++i) {
+                               MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
+                               if (ctor_class == mono_class_try_get_suppress_gc_transition_attribute_class ()) {
+                                       found = TRUE;
+                                       break;
+                               }
+                       }
+               }
+               if (found)
+                       skip_gc_trans = TRUE;
+               if (cinfo && !cinfo->cached)
+                       mono_custom_attrs_free (cinfo);
+       }
+#endif
+
+       mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, aot, check_exceptions, FALSE, skip_gc_trans);
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PINVOKE);
        info->d.managed_to_native.method = method;
 
@@ -3686,7 +3715,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig
        mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
        mb->method->save_lmf = 1;
 
-       mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE, FALSE);
+       mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE, FALSE, FALSE);
 
        csig = mono_metadata_signature_dup_full (image, sig);
        csig->pinvoke = 0;
@@ -3749,7 +3778,7 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass)
        mb = mono_mb_new (invoke->klass, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
        mb->method->save_lmf = 1;
 
-       mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, FALSE, TRUE, TRUE);
+       mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, FALSE, TRUE, TRUE, FALSE);
 
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT);
        info->d.managed_to_native.method = invoke;
@@ -6414,14 +6443,14 @@ mono_marshal_get_type_object (MonoClass *klass)
 }
 
 void
-mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param)
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans)
 {
-       get_marshal_cb ()->emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, aot, check_exceptions, func_param);
+       get_marshal_cb ()->emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, aot, check_exceptions, func_param, skip_gc_trans);
 }
 
 #ifndef ENABLE_ILGEN
 static void
-emit_native_wrapper_noilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param)
+emit_native_wrapper_noilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans)
 {
 }
 #endif
index 50094c4..fa6a9ca 100644 (file)
@@ -323,7 +323,7 @@ typedef struct {
        void (*emit_virtual_stelemref) (MonoMethodBuilder *mb, const char **param_names, MonoStelemrefKind kind);
        void (*emit_stelemref) (MonoMethodBuilder *mb);
        void (*emit_array_address) (MonoMethodBuilder *mb, int rank, int elem_size);
-       void (*emit_native_wrapper) (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param);
+       void (*emit_native_wrapper) (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans);
        void (*emit_managed_wrapper) (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle);
        void (*emit_runtime_invoke_body) (MonoMethodBuilder *mb, const char **param_names, MonoImage *image, MonoMethod *method, MonoMethodSignature *sig, MonoMethodSignature *callsig, gboolean virtual_, gboolean need_direct_wrapper);
        void (*emit_runtime_invoke_dynamic) (MonoMethodBuilder *mb);
@@ -659,7 +659,7 @@ mono_signature_no_pinvoke (MonoMethod *method);
 /* Called from cominterop.c/remoting.c */
 
 void
-mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param);
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans);
 
 void
 mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle);