From 4689875b63820da31c03ccf07a52e85edcb8ba03 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Sep 2021 16:45:00 -0400 Subject: [PATCH] [release/6.0-rc2] [interp] Add wide data item index static load and stores (#59262) 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 | 6 ++++ src/mono/mono/mini/interp/interp.c | 20 ++++++++++++ src/mono/mono/mini/interp/mintops.def | 2 ++ src/mono/mono/mini/interp/mintops.h | 1 + src/mono/mono/mini/interp/transform.c | 57 +++++++++++++++++++++++++++++------ 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index b4a1946..cbabe1f 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -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 (); diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 7734c06..c2c423b 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -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); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 04ff11b..9ef942e 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -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) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index 82c78ac..6de5e8c 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -23,6 +23,7 @@ typedef enum MintOpFieldToken, MintOpClassToken, MintOpTwoShorts, + MintOpTwoInts, MintOpShortAndInt, MintOpShortAndShortBranch, MintOpPair2, diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 952cfa5..885deac 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -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); + } } } -- 2.7.4