Skip to content

Commit

Permalink
[mono] Add unchecked version of stelem_ref interpreter opcode (#99829)
Browse files Browse the repository at this point in the history
* Introduce mint_stelem_ref_unchecked
* Inline most of stelem_ref_unchecked in jiterpreter traces
* Add more complete type check for stelem_ref_unchecked
* Correctness fix and simplification for stelem_ref_unchecked
  • Loading branch information
kg authored May 23, 2024
1 parent 4219e45 commit 8025156
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 4 deletions.
10 changes: 9 additions & 1 deletion src/mono/browser/runtime/jiterpreter-trace-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/mono/browser/runtime/jiterpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")),
];
Expand Down Expand Up @@ -649,7 +649,7 @@ function initialize_builder (builder: WasmBuilder) {
WasmValtype.void, true
);
builder.defineType(
"stelem_ref",
"stelemr",
{
"o": WasmValtype.i32,
"aindex": WasmValtype.i32,
Expand Down
9 changes: 8 additions & 1 deletion src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -6660,6 +6660,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;
Expand All @@ -6676,7 +6684,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);
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/interp/mintops.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
29 changes: 29 additions & 0 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -4945,6 +4945,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;
}

Expand Down

0 comments on commit 8025156

Please sign in to comment.