diff --git a/src/mono/mono/mini/decompose.c b/src/mono/mono/mini/decompose.c
index b4570cc0c7429..55ed38e29d50c 100644
--- a/src/mono/mono/mini/decompose.c
+++ b/src/mono/mono/mini/decompose.c
@@ -1545,16 +1545,24 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
ins->inst_imm, ins->flags);
MONO_ADD_INS (cfg->cbb, dest);
break;
- case OP_BOUNDS_CHECK:
+ case OP_BOUNDS_CHECK: {
+ gboolean need_sext = ins->backend.need_sext;
MONO_EMIT_NULL_CHECK (cfg, ins->sreg1, FALSE);
if (COMPILE_LLVM (cfg)) {
- int index2_reg = alloc_preg (cfg);
- MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, ins->sreg2);
+ int index2_reg;
+ if (need_sext) {
+ index2_reg = alloc_preg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, ins->sreg2);
+ } else {
+ index2_reg = ins->sreg2;
+ }
MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, GINT32_TO_UINT32(ins->inst_imm), index2_reg, ins->flags & MONO_INST_FAULT, ins->inst_p0);
} else {
+ g_assert (!need_sext);
MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->inst_p0);
}
break;
+ }
case OP_NEWARR: {
ERROR_DECL (vt_error);
MonoClass *array_class = mono_class_create_array (ins->inst_newa_class, 1);
diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c
index 1b832de431db0..2baf668181952 100644
--- a/src/mono/mono/mini/interp/interp.c
+++ b/src/mono/mono/mini/interp/interp.c
@@ -1211,27 +1211,6 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
return pos;
}
-static MonoException*
-ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
-{
- MonoObject *o = sp->data.o;
- MonoArray *ao = (MonoArray *) o;
- MonoClass *ac = o->vtable->klass;
-
- g_assert (m_class_get_rank (ac) >= 1);
-
- gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
- if (pos == -1)
- return mono_get_exception_index_out_of_range ();
-
- gint32 esize = mono_array_element_size (ac);
- gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
-
- MonoType *mt = sig->ret;
- stackval_from_data (mt, retval, ea, FALSE);
- return NULL;
-}
-
static MonoException*
ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, gpointer *ret, stackval *sp, gboolean needs_typecheck)
{
diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c
index b1e5e76723147..d57dd90337ae1 100644
--- a/src/mono/mono/mini/intrinsics.c
+++ b/src/mono/mono/mini/intrinsics.c
@@ -356,9 +356,10 @@ emit_span_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
/* Similar to mini_emit_ldelema_1_ins () */
int size = mono_class_array_element_size (param_class);
- int index_reg = mini_emit_sext_index_reg (cfg, args [1]);
+ gboolean need_sext;
+ int index_reg = mini_emit_sext_index_reg (cfg, args [1], &need_sext);
- mini_emit_bounds_check_offset (cfg, span_reg, length_field->offset - MONO_ABI_SIZEOF (MonoObject), index_reg, NULL);
+ mini_emit_bounds_check_offset (cfg, span_reg, length_field->offset - MONO_ABI_SIZEOF (MonoObject), index_reg, NULL, need_sext);
// FIXME: Sign extend index ?
@@ -849,7 +850,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
#else
index_reg = args [1]->dreg;
#endif
- MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
+ MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg, FALSE);
#if defined(TARGET_X86) || defined(TARGET_AMD64)
EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
diff --git a/src/mono/mono/mini/ir-emit.h b/src/mono/mono/mini/ir-emit.h
index 6b88e959e3852..0889a79efb956 100644
--- a/src/mono/mono/mini/ir-emit.h
+++ b/src/mono/mono/mini/ir-emit.h
@@ -971,11 +971,12 @@ static int ccount = 0;
#endif
static inline void
-mini_emit_bounds_check_offset (MonoCompile *cfg, int array_reg, int array_length_offset, int index_reg, const char *ex_name)
+mini_emit_bounds_check_offset (MonoCompile *cfg, int array_reg, int array_length_offset, int index_reg, const char *ex_name, gboolean need_sext)
{
if (!(cfg->opt & MONO_OPT_UNSAFE)) {
ex_name = ex_name ? ex_name : "IndexOutOfRangeException";
if (!(cfg->opt & MONO_OPT_ABCREM)) {
+ g_assert (!need_sext);
MONO_EMIT_NULL_CHECK (cfg, array_reg, FALSE);
if (COMPILE_LLVM (cfg))
MONO_EMIT_DEFAULT_BOUNDS_CHECK ((cfg), (array_reg), GINT_TO_UINT(array_length_offset), (index_reg), TRUE, ex_name);
@@ -988,6 +989,7 @@ mini_emit_bounds_check_offset (MonoCompile *cfg, int array_reg, int array_length
ins->sreg2 = index_reg;
ins->inst_p0 = (gpointer)ex_name;
ins->inst_imm = (array_length_offset);
+ ins->backend.need_sext = need_sext;
ins->flags |= MONO_INST_FAULT;
MONO_ADD_INS ((cfg)->cbb, ins);
(cfg)->flags |= MONO_CFG_NEEDS_DECOMPOSE;
@@ -1002,8 +1004,8 @@ mini_emit_bounds_check_offset (MonoCompile *cfg, int array_reg, int array_length
* array_length_field is the field in the previous struct with the length
* index_reg is the vreg holding the index
*/
-#define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
- mini_emit_bounds_check_offset ((cfg), (array_reg), MONO_STRUCT_OFFSET (array_type, array_length_field), (index_reg), NULL); \
+#define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg, need_sext) do { \
+ mini_emit_bounds_check_offset ((cfg), (array_reg), MONO_STRUCT_OFFSET (array_type, array_length_field), (index_reg), NULL, need_sext); \
} while (0)
#endif
diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c
index b5f75ea1c3133..3633ee1abdb88 100644
--- a/src/mono/mono/mini/method-to-ir.c
+++ b/src/mono/mono/mini/method-to-ir.c
@@ -4211,20 +4211,27 @@ mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoCla
}
int
-mini_emit_sext_index_reg (MonoCompile *cfg, MonoInst *index)
+mini_emit_sext_index_reg (MonoCompile *cfg, MonoInst *index, gboolean *need_sext)
{
int index_reg = index->dreg;
int index2_reg;
+ *need_sext = FALSE;
+
#if SIZEOF_REGISTER == 8
+ // If index is not I4 don't sign extend otherwise we lose high word
+ if (index->type != STACK_I4)
+ return index_reg;
+
/* The array reg is 64 bits but the index reg is only 32 */
- if (COMPILE_LLVM (cfg)) {
+ if (cfg->opt & MONO_OPT_ABCREM) {
/*
* abcrem can't handle the OP_SEXT_I4, so add this after abcrem,
* during OP_BOUNDS_CHECK decomposition, and in the implementation
* of OP_X86_LEA for llvm.
*/
index2_reg = index_reg;
+ *need_sext = TRUE;
} else {
index2_reg = alloc_preg (cfg);
MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
@@ -4259,7 +4266,9 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
mult_reg = alloc_preg (cfg);
array_reg = arr->dreg;
- realidx2_reg = index2_reg = mini_emit_sext_index_reg (cfg, index);
+ gboolean need_sext;
+
+ realidx2_reg = index2_reg = mini_emit_sext_index_reg (cfg, index, &need_sext);
if (bounded) {
bounds_reg = alloc_preg (cfg);
@@ -4283,7 +4292,7 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
}
if (bcheck)
- MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, realidx2_reg);
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, realidx2_reg, need_sext);
#if defined(TARGET_X86) || defined(TARGET_AMD64)
if (size == 1 || size == 2 || size == 4 || size == 8) {
@@ -4444,8 +4453,18 @@ mini_emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboole
if (sp [2]->type != STACK_OBJ)
return NULL;
+ MonoInst *index_ins = sp [1];
+#if SIZEOF_REGISTER == 8
+ if (sp [1]->type == STACK_I4) {
+ // stelemref wrapper receives index as native int, sign extend it
+ guint32 dreg = alloc_preg (cfg);
+ guint32 sreg = index_ins->dreg;
+ EMIT_NEW_UNALU (cfg, index_ins, OP_SEXT_I4, dreg, sreg);
+ }
+#endif
+
iargs [2] = sp [2];
- iargs [1] = sp [1];
+ iargs [1] = index_ins;
iargs [0] = sp [0];
MonoClass *array_class = sp [0]->klass;
@@ -4483,7 +4502,7 @@ mini_emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboole
MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
if (safety_checks)
- MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg, FALSE);
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, m_class_get_byval_arg (klass), array_reg, (target_mgreg_t)offset, sp [2]->dreg);
} else {
MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks, FALSE);
@@ -10588,7 +10607,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
- MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg, FALSE);
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, m_class_get_byval_arg (klass), array_reg, (target_mgreg_t)offset);
} else {
addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE, FALSE);
diff --git a/src/mono/mono/mini/mini-amd64.h b/src/mono/mono/mini/mini-amd64.h
index 80c570e58f5be..2c775c1585545 100644
--- a/src/mono/mono/mini/mini-amd64.h
+++ b/src/mono/mono/mini/mini-amd64.h
@@ -480,16 +480,6 @@ typedef struct {
/* Used for optimization, not complete */
#define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
-#define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg, ex_name) do { \
- MonoInst *inst; \
- MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
- inst->inst_basereg = array_reg; \
- inst->inst_offset = offset; \
- inst->sreg2 = index_reg; \
- MONO_ADD_INS ((cfg)->cbb, inst); \
- MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, ex_name); \
- } while (0)
-
// Does the ABI have a volatile non-parameter register, so tailcall
// can pass context to generics or interfaces?
#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1
diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h
index eee8fd39bd5a5..5629513af9283 100644
--- a/src/mono/mono/mini/mini.h
+++ b/src/mono/mono/mini/mini.h
@@ -753,6 +753,7 @@ struct MonoInst {
gpointer data;
gint shift_amount;
gboolean is_pinvoke; /* for variables in the unmanaged marshal format */
+ gboolean need_sext; /* for OP_BOUNDS_CHECK */
gboolean record_cast_details; /* For CEE_CASTCLASS */
MonoInst *spill_var; /* for OP_MOVE_I4_TO_F/F_TO_I4 and OP_FCONV_TO_R8_X */
guint16 source_opcode; /*OP_XCONV_R8_TO_I4 needs to know which op was used to do proper widening*/
@@ -2316,7 +2317,7 @@ void mini_emit_memset (MonoCompile *cfg, int destreg, int offset, i
void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
void mini_emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype);
-int mini_emit_sext_index_reg (MonoCompile *cfg, MonoInst *index);
+int mini_emit_sext_index_reg (MonoCompile *cfg, MonoInst *index, gboolean *need_sext);
MonoInst* mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck, gboolean bounded);
MonoInst* mini_emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
MonoInst* mini_emit_get_rgctx_method (MonoCompile *cfg, int context_used,
diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c
index 1b6fe4d2447b5..3e3c2eb26feb3 100644
--- a/src/mono/mono/mini/simd-intrinsics.c
+++ b/src/mono/mono/mini/simd-intrinsics.c
@@ -3240,12 +3240,12 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
}
/* Emit bounds check for the index (index >= 0) */
- mini_emit_bounds_check_offset (cfg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), index_ins->dreg, "ArgumentOutOfRangeException");
+ mini_emit_bounds_check_offset (cfg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), index_ins->dreg, "ArgumentOutOfRangeException", FALSE);
/* Emit bounds check for the end (index + len - 1 < array length) */
end_index_reg = alloc_ireg (cfg);
EMIT_NEW_BIALU_IMM (cfg, ins, OP_IADD_IMM, end_index_reg, index_ins->dreg, len - 1);
- mini_emit_bounds_check_offset (cfg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), end_index_reg, "ArgumentOutOfRangeException");
+ mini_emit_bounds_check_offset (cfg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), end_index_reg, "ArgumentOutOfRangeException", FALSE);
/* Load the array slice into the simd reg */
ldelema_ins = mini_emit_ldelema_1_ins (cfg, mono_class_from_mono_type_internal (etype), array_ins, index_ins, FALSE, FALSE);
@@ -3274,7 +3274,7 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
}
/* CopyTo () does complicated argument checks */
- mini_emit_bounds_check_offset (cfg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), index_ins->dreg, "ArgumentOutOfRangeException");
+ mini_emit_bounds_check_offset (cfg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), index_ins->dreg, "ArgumentOutOfRangeException", FALSE);
end_index_reg = alloc_ireg (cfg);
int len_reg = alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, len_reg, array_ins->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length), MONO_INST_INVARIANT_LOAD);
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 09e50e73c7dd3..71f5b5fab57c0 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -1203,9 +1203,6 @@
https://github.com/dotnet/runtime/issues/74223
-
- https://github.com/dotnet/runtime/issues/71656
-
https://github.com/dotnet/runtime/issues/54176
@@ -2233,6 +2230,9 @@
https://github.com/dotnet/runtime/issues/74687
+
+ https://github.com/dotnet/runtime/issues/71656
+