diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c index e20017b11ac5d..af7778f9620e7 100644 --- a/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/mono/mono/mini/interp/jiterpreter.c @@ -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 @@ -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: @@ -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; @@ -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 ( diff --git a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts index de253d3949405..cb9d44c19ef26 100644 --- a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts @@ -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); @@ -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)); @@ -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], @@ -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"; @@ -2049,20 +2066,26 @@ 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); @@ -2070,9 +2093,7 @@ function emit_binop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode } 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: diff --git a/src/mono/wasm/runtime/jiterpreter.ts b/src/mono/wasm/runtime/jiterpreter.ts index 1698d359df7c1..35f54004a64dc 100644 --- a/src/mono/wasm/runtime/jiterpreter.ts +++ b/src/mono/wasm/runtime/jiterpreter.ts @@ -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")), @@ -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")), @@ -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,