[mono] Disable gsharing when Unsafe.ReadUnaligned/WriteUnaligned () is used with...
authorZoltan Varga <vargaz@gmail.com>
Tue, 25 Jul 2023 21:26:43 +0000 (17:26 -0400)
committerGitHub <noreply@github.com>
Tue, 25 Jul 2023 21:26:43 +0000 (16:26 -0500)
Fixes https://github.com/dotnet/runtime/issues/89398.

For a method like
```
    static void Write<T>(ref byte b, T value) => Unsafe.WriteUnaligned<T>(ref b, value);
```
And an instance ```Write<GStruct<string>>```, generic sharing will create a ```Write<T_INST>```
instance where T_INST is constrained to GStruct<T_REF>. The JIT currently calls
```mini_get_underlying_type ()``` in many places which transform T_INST into GStruct<T_REF>.
This causes problems at runtime in the generic sharing code, which expects to find T_INST.
I.e. ```inflate_info ()``` can inflate ```T_INST``` to ```GStruct<string>```, but it can't inflate
```GStruct<T_REF>``` to ```GStruct<string>```.

As a workaround, disable gsharing in (some) of these cases.

src/mono/mono/mini/intrinsics.c

index 68dc78b..0230105 100644 (file)
@@ -554,6 +554,8 @@ MONO_RESTORE_WARNING
 
                t = ctx->method_inst->type_argv [0];
                t = mini_get_underlying_type (t);
+               if (cfg->gshared && t != ctx->method_inst->type_argv [0] && MONO_TYPE_ISSTRUCT (t) && mono_class_check_context_used (mono_class_from_mono_type_internal (t)))
+                       cfg->prefer_instances = TRUE;
                return mini_emit_memory_load (cfg, t, args [0], 0, MONO_INST_UNALIGNED);
        } else if (!strcmp (cmethod->name, "WriteUnaligned")) {
                g_assert (ctx);
@@ -562,7 +564,10 @@ MONO_RESTORE_WARNING
                g_assert (fsig->param_count == 2);
 
                t = ctx->method_inst->type_argv [0];
+
                t = mini_get_underlying_type (t);
+               if (cfg->gshared && t != ctx->method_inst->type_argv [0] && MONO_TYPE_ISSTRUCT (t) && mono_class_check_context_used (mono_class_from_mono_type_internal (t)))
+                       cfg->prefer_instances = TRUE;
                mini_emit_memory_store (cfg, t, args [0], args [1], MONO_INST_UNALIGNED);
                MONO_INST_NEW (cfg, ins, OP_NOP);
                MONO_ADD_INS (cfg->cbb, ins);