diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index 3e9fba479e1b72..230c67733badff 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -3347,13 +3347,21 @@ function emit_arrayop (builder: WasmBuilder, frame: NativePointer, ip: MintOpcod append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); // value append_ldloc(builder, getArgU16(ip, 3), WasmOpcode.i32_load); - builder.callImport("stelem_ref"); + builder.callImport("stelemr_tc"); builder.appendU8(WasmOpcode.br_if); builder.appendULeb(0); append_bailout(builder, ip, BailoutReason.ArrayStoreFailed); builder.endBlock(); return true; } + case MintOpcode.MINT_STELEM_REF_UNCHECKED: { + // dest + append_getelema1(builder, ip, objectOffset, indexOffset, 4); + // &value (src) + append_ldloca(builder, valueOffset, 0); + builder.callImport("copy_ptr"); + return true; + } case MintOpcode.MINT_LDELEM_REF: elementSize = 4; elementGetter = WasmOpcode.i32_load; diff --git a/src/mono/browser/runtime/jiterpreter.ts b/src/mono/browser/runtime/jiterpreter.ts index bf77f289603845..9fc538c03f62d3 100644 --- a/src/mono/browser/runtime/jiterpreter.ts +++ b/src/mono/browser/runtime/jiterpreter.ts @@ -285,7 +285,7 @@ function getTraceImports () { importDef("stfld_o", getRawCwrap("mono_jiterp_set_object_field")), importDef("cmpxchg_i32", getRawCwrap("mono_jiterp_cas_i32")), importDef("cmpxchg_i64", getRawCwrap("mono_jiterp_cas_i64")), - importDef("stelem_ref", getRawCwrap("mono_jiterp_stelem_ref")), + ["stelemr_tc", "stelemr", getRawCwrap("mono_jiterp_stelem_ref")], importDef("fma", getRawCwrap("fma")), importDef("fmaf", getRawCwrap("fmaf")), ]; @@ -649,7 +649,7 @@ function initialize_builder (builder: WasmBuilder) { WasmValtype.void, true ); builder.defineType( - "stelem_ref", + "stelemr", { "o": WasmValtype.i32, "aindex": WasmValtype.i32, diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 7de2bf84d84852..e1f2f5c06c86c2 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -6628,6 +6628,14 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_STELEM_I8) STELEM(gint64, gint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_STELEM_R4) STELEM(float, float); MINT_IN_BREAK; MINT_IN_CASE(MINT_STELEM_R8) STELEM(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_REF_UNCHECKED) { + MonoArray *o; + guint32 aindex; + STELEM_PROLOG(o, aindex); + mono_array_setref_fast ((MonoArray *) o, aindex, LOCAL_VAR (ip [3], MonoObject*)); + ip += 4; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_STELEM_REF) { MonoArray *o; guint32 aindex; @@ -6644,7 +6652,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_STELEM_VT) { MonoArray *o = LOCAL_VAR (ip [1], MonoArray*); NULL_CHECK (o); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index d79d5cd30acac2..7edb4f53e3fb70 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -413,6 +413,7 @@ OPDEF(MINT_STELEM_R8, "stelem.r8", 4, 0, 3, MintOpNoArgs) OPDEF(MINT_STELEM_REF, "stelem.ref", 4, 0, 3, MintOpNoArgs) OPDEF(MINT_STELEM_VT, "stelem.vt", 6, 0, 3, MintOpTwoShorts) OPDEF(MINT_STELEM_VT_NOREF, "stelem.vt.noref", 6, 0, 3, MintOpTwoShorts) +OPDEF(MINT_STELEM_REF_UNCHECKED, "stelem.ref.unchecked", 4, 0, 3, MintOpNoArgs) OPDEF(MINT_LDLEN, "ldlen", 3, 1, 1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index be1d722f146408..d1fa661ae1fe25 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -4808,6 +4808,35 @@ handle_stelem (TransformData *td, int op) interp_add_ins (td, op); td->sp -= 3; interp_ins_set_sregs3 (td->last_ins, td->sp [0].var, td->sp [1].var, td->sp [2].var); + + if (op == MINT_STELEM_REF) { + InterpVar *array_var = &td->vars [td->last_ins->sregs [0]], + *value_var = &td->vars [td->last_ins->sregs [2]]; + MonoClass *array_var_klass = mono_class_from_mono_type_internal (array_var->type), + *value_var_klass = mono_class_from_mono_type_internal (value_var->type); + + if (m_class_is_array (array_var_klass)) { + MonoClass *array_element_klass = m_class_get_element_class (array_var_klass); + // If lhs is T[] and rhs is T and T is sealed, we can skip the runtime typecheck + if ( + (array_element_klass == value_var_klass) && + m_class_is_sealed(value_var_klass) && + // HACK: Arrays are sealed, but it's possible to downcast string[][] to object[][], + // so we don't want to treat elements of array types as actually sealed. + // Our lhs of type object[][] might actually be of a different reference type. + !m_class_is_array(value_var_klass) + ){ + if (td->verbose_level > 2) + g_printf ( + "MINT_STELEM_REF_UNCHECKED for %s in %s::%s\n", + m_class_get_name (value_var_klass), + m_class_get_name (td->method->klass), td->method->name + ); + td->last_ins->opcode = MINT_STELEM_REF_UNCHECKED; + } + } + } + ++td->ip; }