[interp] Add unaligned version for ldfld.vt opcodes (#38173)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Sat, 20 Jun 2020 11:09:52 +0000 (07:09 -0400)
committerGitHub <noreply@github.com>
Sat, 20 Jun 2020 11:09:52 +0000 (14:09 +0300)
Regressed recently with the addition of specialized ldfld.vt opcodes

Co-authored-by: BrzVlad <BrzVlad@users.noreply.github.com>
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/interp/mintops.def
src/mono/mono/mini/interp/transform.c

index 4ffa96b..22f27a2 100644 (file)
@@ -5333,13 +5333,18 @@ call_newobj:
                        MINT_IN_BREAK;
                }
 
-#define LDFLD_VT(datamem, fieldtype) do { \
+#define LDFLD_VT_UNALIGNED(datamem, fieldtype, unaligned) do { \
        gpointer p = sp [-1].data.p; \
        vt_sp -= ip [2]; \
-       sp [-1].data.datamem = * (fieldtype *)((char *)p + ip [1]); \
+       if (unaligned) \
+               memcpy (&sp[-1].data.datamem, (char *)p + ip [1], sizeof (fieldtype)); \
+       else \
+               sp [-1].data.datamem = * (fieldtype *)((char *)p + ip [1]); \
        ip += 3; \
 } while (0)
 
+#define LDFLD_VT(datamem, fieldtype) LDFLD_VT_UNALIGNED(datamem, fieldtype, FALSE)
+
                MINT_IN_CASE(MINT_LDFLD_VT_I1) LDFLD_VT(i, gint8); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLD_VT_U1) LDFLD_VT(i, guint8); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLD_VT_I2) LDFLD_VT(i, gint16); MINT_IN_BREAK;
@@ -5349,6 +5354,8 @@ call_newobj:
                MINT_IN_CASE(MINT_LDFLD_VT_R4) LDFLD_VT(f_r4, float); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLD_VT_R8) LDFLD_VT(f, double); MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLD_VT_O) LDFLD_VT(p, gpointer); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_VT_I8_UNALIGNED) LDFLD_VT_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLD_VT_R8_UNALIGNED) LDFLD_VT_UNALIGNED(f, double, TRUE); MINT_IN_BREAK;
 
                MINT_IN_CASE(MINT_LDFLD_VT_VT) {
                        gpointer p = sp [-1].data.p;
index a5274a1..f342835 100644 (file)
@@ -83,6 +83,8 @@ OPDEF(MINT_LDFLD_VT_R4, "ldfld.vt.r4", 3, Pop1, Push1, MintOpTwoShorts)
 OPDEF(MINT_LDFLD_VT_R8, "ldfld.vt.r8", 3, Pop1, Push1, MintOpTwoShorts)
 OPDEF(MINT_LDFLD_VT_O, "ldfld.vt.o", 3, Pop1, Push1, MintOpTwoShorts)
 OPDEF(MINT_LDFLD_VT_VT, "ldfld.vt.vt", 4, Pop1, Push1, MintOpTwoShorts)
+OPDEF(MINT_LDFLD_VT_I8_UNALIGNED, "ldfld.vt.i8.unaligned", 3, Pop1, Push1, MintOpTwoShorts)
+OPDEF(MINT_LDFLD_VT_R8_UNALIGNED, "ldfld.vt.r8.unaligned", 3, Pop1, Push1, MintOpTwoShorts)
 
 OPDEF(MINT_LDFLD_I1, "ldfld.i1", 2, Pop1, Push1, MintOpUShortInt)
 OPDEF(MINT_LDFLD_U1, "ldfld.u1", 2, Pop1, Push1, MintOpUShortInt)
index 32c37a7..2a01c1c 100644 (file)
@@ -4907,8 +4907,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
                                        goto_if_nok (error, exit);
                                } else if (td->sp [-1].type == STACK_TYPE_VT) {
                                        /* First we pop the vt object from the stack. Then we push the field */
-                                       /* FIXME unaligned field load ? */
                                        int opcode = MINT_LDFLD_VT_I1 + mt - MINT_TYPE_I1;
+#ifdef NO_UNALIGNED_ACCESS
+                                       if (field->offset % SIZEOF_VOID_P != 0) {
+                                               if (mt == MINT_TYPE_I8)
+                                                       opcode = MINT_LDFLD_VT_I8_UNALIGNED;
+                                               else if (mt == MINT_TYPE_R8)
+                                                       opcode = MINT_LDFLD_VT_R8_UNALIGNED;
+                                       }
+#endif
                                        interp_add_ins (td, opcode);
                                        g_assert (m_class_is_valuetype (klass));
                                        td->last_ins->data [0] = field->offset - MONO_ABI_SIZEOF (MonoObject);