[release/6.0-rc2] [interp] Add wide data item index static load and stores (#59262)
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Tue, 21 Sep 2021 20:45:00 +0000 (16:45 -0400)
committerGitHub <noreply@github.com>
Tue, 21 Sep 2021 20:45:00 +0000 (16:45 -0400)
Backport of #59220

Add ldsdfld.w and stsfld.w opcodes to the interpreter. These are needed for some machine-generated methods in Android projects that use AndroidX, MAUI, SkiaSharp or other toolkits. The app's Resource::UpdateIdValues can grow to exceed 64k interpreter data items, which means that 16-bit data item indices will roll over.

Resolves https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1398069

src/mono/mono/metadata/object.c
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/interp/mintops.def
src/mono/mono/mini/interp/mintops.h
src/mono/mono/mini/interp/transform.c

index b4a1946..cbabe1f 100644 (file)
@@ -397,6 +397,7 @@ mono_runtime_run_module_cctor (MonoImage *image, MonoError *error)
                        MonoClass *module_klass;
                        MonoVTable *module_vtable;
 
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_TYPE, "Running module .cctor for '%s'", image->name);
                        module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, error);
                        if (!module_klass) {
                                return FALSE;
@@ -522,6 +523,11 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
        if (do_initialization) {
                MonoException *exc = NULL;
 
+               if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_TYPE)) {
+                       char* type_name = mono_type_full_name (m_class_get_byval_arg (klass));
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_TYPE, "Running class .cctor for %s from '%s'", type_name, m_class_get_image (klass)->name);
+                       g_free (type_name);
+               }
                /* We are holding the per-vtable lock, do the actual initialization */
 
                mono_threads_begin_abort_protected_block ();
index 7734c06..c2c423b 100644 (file)
@@ -5418,6 +5418,16 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                        MINT_IN_BREAK;
                }
 
+               MINT_IN_CASE(MINT_LDSFLD_W) {
+                       MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [READ32 (ip + 2)];
+                       INIT_VTABLE (vtable);
+                       gpointer addr = frame->imethod->data_items [READ32 (ip + 4)];
+                       MonoClass *klass = frame->imethod->data_items [READ32 (ip + 6)];
+                       stackval_from_data (m_class_get_byval_arg (klass), (stackval*)(locals + ip [1]), addr, FALSE);
+                       ip += 8;
+                       MINT_IN_BREAK;
+               }
+
 #define STSFLD(datatype, fieldtype) { \
        MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; \
        INIT_VTABLE (vtable); \
@@ -5444,6 +5454,16 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                        MINT_IN_BREAK;
                }
 
+               MINT_IN_CASE(MINT_STSFLD_W) {
+                       MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [READ32 (ip + 2)];
+                       INIT_VTABLE (vtable);
+                       gpointer addr = frame->imethod->data_items [READ32 (ip + 4)];
+                       MonoClass *klass = frame->imethod->data_items [READ32 (ip + 6)];
+                       stackval_to_data (m_class_get_byval_arg (klass), (stackval*)(locals + ip [1]), addr, FALSE);
+                       ip += 8;
+                       MINT_IN_BREAK;
+               }
+
                MINT_IN_CASE(MINT_STOBJ_VT) {
                        MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]];
                        mono_value_copy_internal (LOCAL_VAR (ip [1], gpointer), locals + ip [2], c);
index 04ff11b..9ef942e 100644 (file)
@@ -85,6 +85,7 @@ OPDEF(MINT_LDSFLD_R4, "ldsfld.r4", 4, 1, 0, MintOpUShortInt)
 OPDEF(MINT_LDSFLD_R8, "ldsfld.r8", 4, 1, 0, MintOpUShortInt)
 OPDEF(MINT_LDSFLD_O, "ldsfld.o", 4, 1, 0, MintOpUShortInt)
 OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 5, 1, 0, MintOpTwoShorts)
+OPDEF(MINT_LDSFLD_W, "ldsfld.w", 8, 1, 0, MintOpTwoInts)
 
 OPDEF(MINT_STSFLD_I1, "stsfld.i1", 4, 0, 1, MintOpUShortInt)
 OPDEF(MINT_STSFLD_U1, "stsfld.u1", 4, 0, 1, MintOpUShortInt)
@@ -96,6 +97,7 @@ OPDEF(MINT_STSFLD_R4, "stsfld.r4", 4, 0, 1, MintOpUShortInt)
 OPDEF(MINT_STSFLD_R8, "stsfld.r8", 4, 0, 1, MintOpUShortInt)
 OPDEF(MINT_STSFLD_O, "stsfld.o", 4, 0, 1, MintOpUShortInt)
 OPDEF(MINT_STSFLD_VT, "stsfld.vt", 5, 0, 1, MintOpTwoShorts)
+OPDEF(MINT_STSFLD_W, "stsfld.w", 8, 0, 1, MintOpTwoInts)
 OPDEF(MINT_LDSFLDA, "ldsflda", 4, 1, 0, MintOpTwoShorts)
 OPDEF(MINT_LDTSFLDA, "ldtsflda", 4, 1, 0, MintOpInt)
 
index 82c78ac..6de5e8c 100644 (file)
@@ -23,6 +23,7 @@ typedef enum
        MintOpFieldToken,
        MintOpClassToken,
        MintOpTwoShorts,
+       MintOpTwoInts,
        MintOpShortAndInt,
        MintOpShortAndShortBranch,
        MintOpPair2,
index 952cfa5..885deac 100644 (file)
@@ -1093,11 +1093,11 @@ store_local (TransformData *td, int local)
                td->last_ins->data [0] = td->locals [local].size;
 }
 
-static guint16
-get_data_item_index (TransformData *td, void *ptr)
+static guint32
+get_data_item_wide_index (TransformData *td, void *ptr)
 {
        gpointer p = g_hash_table_lookup (td->data_hash, ptr);
-       guint index;
+       guint32 index;
        if (p != NULL)
                return GPOINTER_TO_UINT (p) - 1;
        if (td->max_data_items == td->n_data_items) {
@@ -1112,6 +1112,20 @@ get_data_item_index (TransformData *td, void *ptr)
 }
 
 static guint16
+get_data_item_index (TransformData *td, void *ptr)
+{
+       guint32 index = get_data_item_wide_index (td, ptr);
+       g_assertf (index <= G_MAXUINT16, "Interpreter data item index 0x%x for method '%s' overflows", index, td->method->name);
+       return (guint16)index;
+}
+
+static gboolean
+is_data_item_wide_index (guint32 data_item_index)
+{
+       return data_item_index > G_MAXUINT16;
+}
+
+static guint16
 get_data_item_index_nonshared (TransformData *td, void *ptr)
 {
        guint index;
@@ -1347,6 +1361,9 @@ dump_interp_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, g
        case MintOpTwoShorts:
                g_string_append_printf (str, " %u,%u", *(guint16*)data, *(guint16 *)(data + 1));
                break;
+       case MintOpTwoInts:
+               g_string_append_printf (str, " %u,%u", (guint32)READ32(data), (guint32)READ32(data + 2));
+               break;
        case MintOpShortAndInt:
                g_string_append_printf (str, " %u,%u", *(guint16*)data, (guint32)READ32(data + 1));
                break;
@@ -4199,7 +4216,20 @@ interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *fi
                                if (interp_emit_load_const (td, field_addr, mt))
                                        return;
                        }
-                       if (mt == MINT_TYPE_VT) {
+               }
+               guint32 vtable_index = get_data_item_wide_index (td, vtable);
+               guint32 addr_index = get_data_item_wide_index (td, (char*)field_addr);
+               gboolean wide_data = is_data_item_wide_index (vtable_index) || is_data_item_wide_index (addr_index);
+               guint32 klass_index = !wide_data ? 0 : get_data_item_wide_index (td, field_class);
+               if (is_load) {
+                       if (G_UNLIKELY (wide_data)) {
+                               interp_add_ins (td, MINT_LDSFLD_W);
+                               if (mt == MINT_TYPE_VT) {
+                                       push_type_vt (td, field_class, size);
+                               } else {
+                                       push_type (td, stack_type [mt], field_class);
+                               }
+                       } else if (mt == MINT_TYPE_VT) {
                                interp_add_ins (td, MINT_LDSFLD_VT);
                                push_type_vt (td, field_class, size);
                        } else {
@@ -4208,15 +4238,24 @@ interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *fi
                        }
                        interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
                } else {
-                       interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_STSFLD_VT : (MINT_STSFLD_I1 + mt - MINT_TYPE_I1));
+                       if (G_LIKELY (!wide_data))
+                               interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_STSFLD_VT : (MINT_STSFLD_I1 + mt - MINT_TYPE_I1));
+                       else
+                               interp_add_ins (td, MINT_STSFLD_W);
                        td->sp--;
                        interp_ins_set_sreg (td->last_ins, td->sp [0].local);
                }
 
-               td->last_ins->data [0] = get_data_item_index (td, vtable);
-               td->last_ins->data [1] = get_data_item_index (td, (char*)field_addr);
-               if (mt == MINT_TYPE_VT)
-                       td->last_ins->data [2] = size;
+               if (G_LIKELY (!wide_data)) {
+                       td->last_ins->data [0] = (guint16) vtable_index;
+                       td->last_ins->data [1] = (guint16) addr_index;
+                       if (mt == MINT_TYPE_VT)
+                               td->last_ins->data [2] = size;
+               } else {
+                       WRITE32_INS (td->last_ins, 0, &vtable_index);
+                       WRITE32_INS (td->last_ins, 2, &addr_index);
+                       WRITE32_INS (td->last_ins, 4, &klass_index);
+               }
 
        }
 }