diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 7725b25946369..4c161f4669457 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -176,6 +176,7 @@ struct _MonoArray { } name; MONO_DEFINE_SPAN_OF_T (MonoSpanOfObjects, MonoObject*) +MONO_DEFINE_SPAN_OF_T (MonoSpanOfVoid, void) #define MONO_SIZEOF_MONO_ARRAY (MONO_STRUCT_OFFSET_CONSTANT (MonoArray, vector)) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 0efeb187b99af..52ccda878605b 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -6061,23 +6061,33 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_BREAK; } MINT_IN_CASE(MINT_GETITEM_SPAN) { - guint8 *span = LOCAL_VAR (ip [2], guint8*); + MonoSpanOfVoid *span = LOCAL_VAR (ip [2], MonoSpanOfVoid*); int index = LOCAL_VAR (ip [3], int); NULL_CHECK (span); - gsize offset_length = (gsize)(gint16)ip [5]; - - const gint32 length = *(gint32 *) (span + offset_length); + gint32 length = span->_length; if (index < 0 || index >= length) THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); gsize element_size = (gsize)(gint16)ip [4]; - gsize offset_pointer = (gsize)(gint16)ip [6]; + LOCAL_VAR (ip [1], gpointer) = (guint8*)span->_reference + index * element_size; - const gpointer pointer = *(gpointer *)(span + offset_pointer); - LOCAL_VAR (ip [1], gpointer) = (guint8 *) pointer + index * element_size; + ip += 5; + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_GETITEM_LOCALSPAN) { + // Same as getitem span but we know the offset of the span structure on the stack + MonoSpanOfVoid *span = (MonoSpanOfVoid*)(locals + ip [2]); + int index = LOCAL_VAR (ip [3], int); - ip += 7; + gint32 length = span->_length; + if (index < 0 || index >= length) + THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); + + gsize element_size = (gsize)(gint16)ip [4]; + LOCAL_VAR (ip [1], gpointer) = (guint8*)span->_reference + index * element_size; + + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STRLEN) { diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index d6188995716a2..016f263d5c377 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -414,7 +414,8 @@ OPDEF(MINT_STELEM_VT, "stelem.vt", 6, 0, 3, MintOpTwoShorts) OPDEF(MINT_LDLEN, "ldlen", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_GETITEM_SPAN, "getitem.span", 7, 1, 2, MintOpTwoShorts) +OPDEF(MINT_GETITEM_SPAN, "getitem.span", 5, 1, 2, MintOpTwoShorts) +OPDEF(MINT_GETITEM_LOCALSPAN, "getitem.localspan", 5, 1, 2, MintOpTwoShorts) /* binops */ OPDEF(MINT_ADD_I4, "add.i4", 4, 1, 2, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 725e993d392c9..e4fcb8c6f3ff7 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2134,16 +2134,16 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoClassField *length_field = mono_class_get_field_from_name_full (target_method->klass, "_length", NULL); g_assert (length_field); int offset_length = m_field_get_offset (length_field) - sizeof (MonoObject); + g_assert (offset_length == TARGET_SIZEOF_VOID_P); MonoClassField *ptr_field = mono_class_get_field_from_name_full (target_method->klass, "_reference", NULL); g_assert (ptr_field); int offset_pointer = m_field_get_offset (ptr_field) - sizeof (MonoObject); + g_assert (offset_pointer == 0); int size = mono_class_array_element_size (param_class); interp_add_ins (td, MINT_GETITEM_SPAN); td->last_ins->data [0] = GINT_TO_UINT16 (size); - td->last_ins->data [1] = GINT_TO_UINT16 (offset_length); - td->last_ins->data [2] = GINT_TO_UINT16 (offset_pointer); td->sp -= 2; interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); @@ -8996,6 +8996,17 @@ interp_cprop (TransformData *td) } needs_retry = TRUE; } + } else if (opcode == MINT_GETITEM_SPAN) { + InterpInst *ldloca = local_defs [sregs [0]].ins; + if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int local = ldloca->sregs [0]; + // Allow ldloca instruction to be killed + local_ref_count [sregs [0]]--; + // Instead of loading from the indirect pointer pass directly the vt var + ins->opcode = MINT_GETITEM_LOCALSPAN; + sregs [0] = local; + needs_retry = TRUE; + } } ins_index++; }