Skip to content

Commit b01311b

Browse files
authored
[wasm] Better support for automated tests in jiterpreter; more opcodes (#82281)
* [jiterp] Move enter_jiterpreter into a helper function, and call it immediately after compiling traces This allows running tests under jiterp with hitcount=1 and tiering off * Implement CONV_R_UN opcodes * Implement INTRINS_ORDINAL_IGNORE_CASE_ASCII * Remove the safepoint from tier_enter_jiterpreter, do it in traces instead
1 parent d3921a9 commit b01311b

File tree

5 files changed

+82
-45
lines changed

5 files changed

+82
-45
lines changed

src/mono/mono/mini/interp/interp.c

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,6 +3794,31 @@ max_d (double lhs, double rhs)
37943794
return fmax (lhs, rhs);
37953795
}
37963796

3797+
#ifdef HOST_BROWSER
3798+
MONO_ALWAYS_INLINE static ptrdiff_t
3799+
mono_interp_tier_enter_jiterpreter (
3800+
JiterpreterThunk thunk, InterpFrame *frame, unsigned char *locals, ThreadContext *context,
3801+
const guint16 *ip
3802+
)
3803+
{
3804+
// g_assert(thunk);
3805+
ptrdiff_t offset = thunk(frame, locals);
3806+
/*
3807+
* Verify that the offset returned by the thunk is not total garbage
3808+
* FIXME: These constants might actually be too small since a method
3809+
* could have massive amounts of IL - maybe we should disable the jiterpreter
3810+
* for methods that big
3811+
*/
3812+
// g_assertf((offset >= -0xFFFFF) && (offset <= 0xFFFFF), "thunk returned an obviously invalid offset: %i", offset);
3813+
#ifdef ENABLE_EXPERIMENT_TIERED
3814+
if (offset < 0) {
3815+
mini_tiered_inc (frame->imethod->method, &frame->imethod->tiered_counter, 0);
3816+
}
3817+
#endif
3818+
return offset;
3819+
}
3820+
#endif // HOST_BROWSER
3821+
37973822
/*
37983823
* If CLAUSE_ARGS is non-null, start executing from it.
37993824
* The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
@@ -7640,6 +7665,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
76407665
* table. when growing the function pointer table we will also need to synchronize that.
76417666
*/
76427667
JiterpreterThunk prepare_result = mono_interp_tier_prepare_jiterpreter_fast(frame, frame->imethod->method, ip, frame->imethod->jinfo->code_start, frame->imethod->jinfo->code_size);
7668+
ptrdiff_t offset;
76437669
switch ((guint32)(void*)prepare_result) {
76447670
case JITERPRETER_TRAINING:
76457671
// jiterpreter still updating hit count before deciding to generate a trace,
@@ -7648,9 +7674,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
76487674
break;
76497675
case JITERPRETER_NOT_JITTED:
76507676
// Patch opcode to disable it because this trace failed to JIT.
7651-
mono_memory_barrier();
7677+
mono_memory_barrier ();
76527678
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
7653-
mono_memory_barrier();
7679+
mono_memory_barrier ();
76547680
ip += 3;
76557681
break;
76567682
default:
@@ -7663,11 +7689,17 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
76637689
* here so that implementing thread support will be easier later.)
76647690
*/
76657691
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
7666-
mono_memory_barrier();
7692+
mono_memory_barrier ();
76677693
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
7668-
mono_memory_barrier();
7694+
mono_memory_barrier ();
76697695
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
7670-
ip += 3;
7696+
// now execute the trace
7697+
// this isn't important for performance, but it makes it easier to use the
7698+
// jiterpreter early in automated tests where code only runs once
7699+
offset = mono_interp_tier_enter_jiterpreter (
7700+
prepare_result, frame, locals, context, ip
7701+
);
7702+
ip = (guint16*) (((guint8*)ip) + offset);
76717703
break;
76727704
}
76737705
} else {
@@ -7679,31 +7711,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
76797711

76807712
MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
76817713
JiterpreterThunk thunk = (void*)READ32(ip + 1);
7682-
gboolean trace_requires_safepoint = FALSE;
7683-
g_assert(thunk);
7684-
ptrdiff_t offset = thunk(frame, locals);
7685-
/*
7686-
* The trace signals that we need to perform a safepoint by adding a very
7687-
* large amount to the relative displacement. This is because setting a bit
7688-
* in JS via the | operator doesn't work for negative numbers
7689-
*/
7690-
if (offset >= 0xE000000) {
7691-
offset -= 0xF000000;
7692-
trace_requires_safepoint = TRUE;
7693-
}
7694-
/*
7695-
* Verify that the offset returned by the thunk is not total garbage
7696-
* FIXME: These constants might actually be too small since a method
7697-
* could have massive amounts of IL - maybe we should disable the jiterpreter
7698-
* for methods that big
7699-
*/
7700-
g_assertf((offset >= -0xFFFFF) && (offset <= 0xFFFFF), "thunk returned an obviously invalid offset: %i", offset);
7701-
if (offset <= 0) {
7702-
BACK_BRANCH_PROFILE (offset);
7703-
}
7704-
if (trace_requires_safepoint) {
7705-
SAFEPOINT;
7706-
}
7714+
ptrdiff_t offset = mono_interp_tier_enter_jiterpreter (
7715+
thunk, frame, locals, context, ip
7716+
);
77077717
ip = (guint16*) (((guint8*)ip) + offset);
77087718
MINT_IN_BREAK;
77097719
}

src/mono/mono/mini/interp/jiterpreter.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
735735
case MINT_INTRINS_TRY_GET_HASHCODE:
736736
case MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE:
737737
case MINT_INTRINS_ENUM_HASFLAG:
738+
case MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII:
738739
case MINT_ADD_MUL_I4_IMM:
739740
case MINT_ADD_MUL_I8_IMM:
740741
case MINT_ARRAY_RANK:

src/mono/wasm/runtime/jiterpreter-support.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,9 @@ export class WasmBuilder {
194194
}
195195
}
196196

197-
ip_const (value: MintOpcodePtr, highBit?: boolean) {
197+
ip_const (value: MintOpcodePtr) {
198198
this.appendU8(WasmOpcode.i32_const);
199-
let relativeValue = <any>value - <any>this.base;
200-
if (highBit) {
201-
// it is impossible to do this in JS as far as i can tell
202-
// relativeValue |= 0x80000000;
203-
relativeValue += 0xF000000;
204-
}
205-
this.appendLeb(relativeValue);
199+
this.appendLeb(<any>value - <any>this.base);
206200
}
207201

208202
i52_const (value: number) {

src/mono/wasm/runtime/jiterpreter-trace-generator.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,37 @@ export function generate_wasm_body (
519519
builder.callImport("hascsize");
520520
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
521521
break;
522+
523+
case MintOpcode.MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII: {
524+
builder.local("pLocals");
525+
// valueA (cache in lhs32, we need it again later)
526+
append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load);
527+
builder.local("math_lhs32", WasmOpcode.tee_local);
528+
// valueB
529+
append_ldloc(builder, getArgU16(ip, 3), WasmOpcode.i32_load);
530+
// compute differentBits = (valueA ^ valueB) << 2
531+
builder.appendU8(WasmOpcode.i32_xor);
532+
builder.i32_const(2);
533+
builder.appendU8(WasmOpcode.i32_shl);
534+
builder.local("math_rhs32", WasmOpcode.set_local);
535+
// compute indicator
536+
builder.local("math_lhs32");
537+
builder.i32_const(0x00050005);
538+
builder.appendU8(WasmOpcode.i32_add);
539+
builder.i32_const(0x00A000A0);
540+
builder.appendU8(WasmOpcode.i32_or);
541+
builder.i32_const(0x001A001A);
542+
builder.appendU8(WasmOpcode.i32_add);
543+
builder.i32_const(-8388737); // 0xFF7FFF7F == 4286578559U == -8388737
544+
builder.appendU8(WasmOpcode.i32_or);
545+
// result = (differentBits & indicator) == 0
546+
builder.local("math_rhs32");
547+
builder.appendU8(WasmOpcode.i32_and);
548+
builder.appendU8(WasmOpcode.i32_eqz);
549+
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
550+
break;
551+
}
552+
522553
case MintOpcode.MINT_ARRAY_RANK: {
523554
builder.block();
524555
// dest, src
@@ -1602,8 +1633,10 @@ const unopTable : { [opcode: number]: OpRec3 | undefined } = {
16021633

16031634
[MintOpcode.MINT_CONV_R4_I4]: [WasmOpcode.f32_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f32_store],
16041635
[MintOpcode.MINT_CONV_R8_I4]: [WasmOpcode.f64_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f64_store],
1636+
[MintOpcode.MINT_CONV_R_UN_I4]: [WasmOpcode.f64_convert_u_i32, WasmOpcode.i32_load, WasmOpcode.f64_store],
16051637
[MintOpcode.MINT_CONV_R4_I8]: [WasmOpcode.f32_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f32_store],
16061638
[MintOpcode.MINT_CONV_R8_I8]: [WasmOpcode.f64_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f64_store],
1639+
[MintOpcode.MINT_CONV_R_UN_I8]: [WasmOpcode.f64_convert_u_i64, WasmOpcode.i64_load, WasmOpcode.f64_store],
16071640
[MintOpcode.MINT_CONV_R8_R4]: [WasmOpcode.f64_promote_f32, WasmOpcode.f32_load, WasmOpcode.f64_store],
16081641
[MintOpcode.MINT_CONV_R4_R8]: [WasmOpcode.f32_demote_f64, WasmOpcode.f64_load, WasmOpcode.f32_store],
16091642

@@ -2169,10 +2202,10 @@ function emit_branch (
21692202
builder.appendULeb(0);
21702203

21712204
if (displacement < 0) {
2172-
// This is a backwards branch, and right now we always bail out for those -
2173-
// so just return.
2174-
// FIXME: Why is this not a safepoint?
2175-
append_bailout(builder, destination, BailoutReason.BackwardBranch, true);
2205+
// This is a backwards branch, and right now we always bail out for those - so perform a
2206+
// safepoint and then return. (This removes a safepoint check from all trace returns.)
2207+
append_safepoint(builder, ip);
2208+
append_bailout(builder, destination, BailoutReason.BackwardBranch);
21762209
} else {
21772210
// Do a safepoint *before* changing our IP, if necessary
21782211
if (isSafepoint)
@@ -2763,8 +2796,8 @@ function emit_arrayop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpco
27632796
return true;
27642797
}
27652798

2766-
function append_bailout (builder: WasmBuilder, ip: MintOpcodePtr, reason: BailoutReason, highBit?: boolean) {
2767-
builder.ip_const(ip, highBit);
2799+
function append_bailout (builder: WasmBuilder, ip: MintOpcodePtr, reason: BailoutReason) {
2800+
builder.ip_const(ip);
27682801
if (builder.options.countBailouts) {
27692802
builder.i32_const(reason);
27702803
builder.callImport("bailout");

src/mono/wasm/runtime/jiterpreter.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,6 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {
993993
continue;
994994

995995
// not worth implementing / too difficult
996-
case "intrins_ordinal_ignore_case_ascii":
997996
case "intrins_marvin_block":
998997
case "intrins_ascii_chars_to_uppercase":
999998
case "newarr":

0 commit comments

Comments
 (0)