Skip to content

Commit

Permalink
[wasm] Implement more jiterpreter opcodes (#82849)
Browse files Browse the repository at this point in the history
Implement the following opcodes:
* MINT_NEWSTR
* MINT_ARRAY_ELEMENT_SIZE
* MINT_DIV_I8
* MINT_REM_I8
  • Loading branch information
kg committed Mar 1, 2023
1 parent 9cfd11d commit ef0241e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 16 deletions.
24 changes: 24 additions & 0 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ mono_jiterp_try_newobj_inlined (MonoObject **destination, MonoVTable *vtable) {
return 1;
}

EMSCRIPTEN_KEEPALIVE int
mono_jiterp_try_newstr (MonoString **destination, int length) {
ERROR_DECL(error);
*destination = mono_string_new_size_checked(length, error);
if (!is_ok (error))
*destination = 0;
mono_error_cleanup (error); // FIXME: do not swallow the error
return *destination != 0;
}

EMSCRIPTEN_KEEPALIVE int
mono_jiterp_gettype_ref (
MonoObject **destination, MonoObject **source
Expand Down Expand Up @@ -667,6 +677,7 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
case MINT_BOX:
case MINT_BOX_VT:
case MINT_UNBOX:
case MINT_NEWSTR:
case MINT_NEWOBJ_INLINED:
case MINT_NEWOBJ_VT_INLINED:
case MINT_LD_DELEGATE_METHOD_PTR:
Expand All @@ -680,6 +691,7 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
case MINT_ADD_MUL_I4_IMM:
case MINT_ADD_MUL_I8_IMM:
case MINT_ARRAY_RANK:
case MINT_ARRAY_ELEMENT_SIZE:
case MINT_MONO_CMPXCHG_I4:
case MINT_MONO_CMPXCHG_I8:
return TRACE_CONTINUE;
Expand Down Expand Up @@ -1114,6 +1126,18 @@ mono_jiterp_get_array_rank (gint32 *dest, MonoObject **src)
return 1;
}

EMSCRIPTEN_KEEPALIVE int
mono_jiterp_get_array_element_size (gint32 *dest, MonoObject **src)
{
if (!src || !*src) {
*dest = 0;
return 0;
}

*dest = mono_array_element_size (mono_object_class (*src));
return 1;
}

// Returns 1 on success so that the trace can do br_if to bypass its bailout
EMSCRIPTEN_KEEPALIVE int
mono_jiterp_set_object_field (
Expand Down
53 changes: 37 additions & 16 deletions src/mono/wasm/runtime/jiterpreter-trace-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,12 +665,13 @@ export function generate_wasm_body (
break;
}

case MintOpcode.MINT_ARRAY_RANK: {
case MintOpcode.MINT_ARRAY_RANK:
case MintOpcode.MINT_ARRAY_ELEMENT_SIZE: {
builder.block();
// dest, src
append_ldloca(builder, getArgU16(ip, 1), 4, true);
append_ldloca(builder, getArgU16(ip, 2), 0);
builder.callImport("array_rank");
builder.callImport(opcode === MintOpcode.MINT_ARRAY_RANK ? "array_rank" : "a_elesize");
// If the array was null we will bail out, otherwise continue
builder.appendU8(WasmOpcode.br_if);
builder.appendULeb(0);
Expand Down Expand Up @@ -729,6 +730,21 @@ export function generate_wasm_body (
break;
}

case MintOpcode.MINT_NEWSTR: {
builder.block();
append_ldloca(builder, getArgU16(ip, 1), 4, true);
append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load);
builder.callImport("newstr");
// If the newstr operation succeeded, continue, otherwise bailout
// Note that this assumes the newstr operation will fail again when the interpreter does it
// (the only reason for a newstr to fail I can think of is an out-of-memory condition)
builder.appendU8(WasmOpcode.br_if);
builder.appendULeb(0);
append_bailout(builder, ip, BailoutReason.AllocFailed);
builder.endBlock();
break;
}

case MintOpcode.MINT_NEWOBJ_INLINED: {
builder.block();
// MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass));
Expand Down Expand Up @@ -1842,11 +1858,8 @@ const binopTable : { [opcode: number]: OpRec3 | OpRec4 | undefined } = {
[MintOpcode.MINT_ADD_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store],
[MintOpcode.MINT_SUB_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store],
[MintOpcode.MINT_MUL_I8]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store],
// Overflow check is too hard to do for int64 right now
/*
[MintOpcode.MINT_DIV_I8]: [WasmOpcode.i64_div_s, WasmOpcode.i64_load, WasmOpcode.i64_store],
[MintOpcode.MINT_REM_I8]: [WasmOpcode.i64_rem_s, WasmOpcode.i64_load, WasmOpcode.i64_store],
*/
[MintOpcode.MINT_DIV_UN_I8]: [WasmOpcode.i64_div_u, WasmOpcode.i64_load, WasmOpcode.i64_store],
[MintOpcode.MINT_REM_UN_I8]: [WasmOpcode.i64_rem_u, WasmOpcode.i64_load, WasmOpcode.i64_store],
[MintOpcode.MINT_AND_I8]: [WasmOpcode.i64_and, WasmOpcode.i64_load, WasmOpcode.i64_store],
Expand Down Expand Up @@ -2017,13 +2030,17 @@ function emit_binop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode

switch (opcode) {
case MintOpcode.MINT_DIV_I4:
case MintOpcode.MINT_DIV_I8:
case MintOpcode.MINT_DIV_UN_I4:
case MintOpcode.MINT_DIV_UN_I8:
case MintOpcode.MINT_REM_I4:
case MintOpcode.MINT_REM_I8:
case MintOpcode.MINT_REM_UN_I4:
case MintOpcode.MINT_REM_UN_I8: {
const is64 = (opcode === MintOpcode.MINT_DIV_UN_I8) ||
(opcode === MintOpcode.MINT_REM_UN_I8);
(opcode === MintOpcode.MINT_REM_UN_I8) ||
(opcode === MintOpcode.MINT_DIV_I8) ||
(opcode === MintOpcode.MINT_REM_I8);
lhsVar = is64 ? "math_lhs64" : "math_lhs32";
rhsVar = is64 ? "math_rhs64" : "math_rhs32";

Expand All @@ -2049,30 +2066,34 @@ function emit_binop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode
// Also perform overflow check for signed division operations
if (
(opcode === MintOpcode.MINT_DIV_I4) ||
(opcode === MintOpcode.MINT_REM_I4)
(opcode === MintOpcode.MINT_REM_I4) ||
(opcode === MintOpcode.MINT_DIV_I8) ||
(opcode === MintOpcode.MINT_REM_I8)
) {
builder.block();
builder.local(rhsVar);
// If rhs is -1 and lhs is MININT32 this is an overflow
builder.i32_const(-1);
builder.appendU8(WasmOpcode.i32_ne);
// If rhs is -1 and lhs is INTnn_MIN this is an overflow
if (is64)
builder.i52_const(-1);
else
builder.i32_const(-1);
builder.appendU8(is64 ? WasmOpcode.i64_ne : WasmOpcode.i32_ne);
builder.appendU8(WasmOpcode.br_if);
builder.appendULeb(0);
// rhs was -1 since the previous br_if didn't execute. Now check lhs.
builder.local(lhsVar);
// G_MININT32
builder.i32_const(-2147483647-1);
builder.appendU8(WasmOpcode.i32_ne);
// INTnn_MIN
builder.appendU8(is64 ? WasmOpcode.i64_const : WasmOpcode.i32_const);
builder.appendBoundaryValue(is64 ? 64 : 32, -1);
builder.appendU8(is64 ? WasmOpcode.i64_ne : WasmOpcode.i32_ne);
builder.appendU8(WasmOpcode.br_if);
builder.appendULeb(0);
append_bailout(builder, ip, BailoutReason.Overflow);
builder.endBlock();
}
break;
}
case MintOpcode.MINT_DIV_I8:
// We have to check lhs against MININT64 which is not 52-bit safe
return false;

case MintOpcode.MINT_ADD_OVF_I4:
case MintOpcode.MINT_ADD_OVF_UN_I4:
case MintOpcode.MINT_MUL_OVF_I4:
Expand Down
8 changes: 8 additions & 0 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ function getTraceImports () {
["ckovr_i4", "overflow_check_i4", getRawCwrap("mono_jiterp_overflow_check_i4")],
["ckovr_u4", "overflow_check_i4", getRawCwrap("mono_jiterp_overflow_check_u4")],
importDef("newobj_i", getRawCwrap("mono_jiterp_try_newobj_inlined")),
importDef("newstr", getRawCwrap("mono_jiterp_try_newstr")),
importDef("ld_del_ptr", getRawCwrap("mono_jiterp_ld_delegate_method_ptr")),
importDef("ldtsflda", getRawCwrap("mono_jiterp_ldtsflda")),
importDef("conv", getRawCwrap("mono_jiterp_conv")),
Expand All @@ -271,6 +272,7 @@ function getTraceImports () {
importDef("hascsize", getRawCwrap("mono_jiterp_object_has_component_size")),
importDef("hasflag", getRawCwrap("mono_jiterp_enum_hasflag")),
importDef("array_rank", getRawCwrap("mono_jiterp_get_array_rank")),
["a_elesize", "array_rank", getRawCwrap("mono_jiterp_get_array_element_size")],
importDef("stfld_o", getRawCwrap("mono_jiterp_set_object_field")),
importDef("transfer", getRawCwrap("mono_jiterp_trace_transfer")),
importDef("cmpxchg_i32", getRawCwrap("mono_jiterp_cas_i32")),
Expand Down Expand Up @@ -421,6 +423,12 @@ function initialize_builder (builder: WasmBuilder) {
"vtable": WasmValtype.i32,
}, WasmValtype.i32, true
);
builder.defineType(
"newstr", {
"ppDestination": WasmValtype.i32,
"length": WasmValtype.i32,
}, WasmValtype.i32, true
);
builder.defineType(
"localloc", {
"destination": WasmValtype.i32,
Expand Down

0 comments on commit ef0241e

Please sign in to comment.