Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 40 additions & 30 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3794,6 +3794,31 @@ max_d (double lhs, double rhs)
return fmax (lhs, rhs);
}

#ifdef HOST_BROWSER
MONO_ALWAYS_INLINE static ptrdiff_t
mono_interp_tier_enter_jiterpreter (
JiterpreterThunk thunk, InterpFrame *frame, unsigned char *locals, ThreadContext *context,
const guint16 *ip
)
{
// g_assert(thunk);
ptrdiff_t offset = thunk(frame, locals);
/*
* Verify that the offset returned by the thunk is not total garbage
* FIXME: These constants might actually be too small since a method
* could have massive amounts of IL - maybe we should disable the jiterpreter
* for methods that big
*/
// g_assertf((offset >= -0xFFFFF) && (offset <= 0xFFFFF), "thunk returned an obviously invalid offset: %i", offset);
#ifdef ENABLE_EXPERIMENT_TIERED
if (offset < 0) {
mini_tiered_inc (frame->imethod->method, &frame->imethod->tiered_counter, 0);
}
#endif
return offset;
}
#endif // HOST_BROWSER

/*
* If CLAUSE_ARGS is non-null, start executing from it.
* The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
Expand Down Expand Up @@ -7640,6 +7665,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* table. when growing the function pointer table we will also need to synchronize that.
*/
JiterpreterThunk prepare_result = mono_interp_tier_prepare_jiterpreter_fast(frame, frame->imethod->method, ip, frame->imethod->jinfo->code_start, frame->imethod->jinfo->code_size);
ptrdiff_t offset;
switch ((guint32)(void*)prepare_result) {
case JITERPRETER_TRAINING:
// jiterpreter still updating hit count before deciding to generate a trace,
Expand All @@ -7648,9 +7674,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
break;
case JITERPRETER_NOT_JITTED:
// Patch opcode to disable it because this trace failed to JIT.
mono_memory_barrier();
mono_memory_barrier ();
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier();
mono_memory_barrier ();
ip += 3;
break;
default:
Expand All @@ -7663,11 +7689,17 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
* here so that implementing thread support will be easier later.)
*/
*mutable_ip = MINT_TIER_NOP_JITERPRETER;
mono_memory_barrier();
mono_memory_barrier ();
*(volatile JiterpreterThunk*)(ip + 1) = prepare_result;
mono_memory_barrier();
mono_memory_barrier ();
*mutable_ip = MINT_TIER_ENTER_JITERPRETER;
ip += 3;
// now execute the trace
// this isn't important for performance, but it makes it easier to use the
// jiterpreter early in automated tests where code only runs once
offset = mono_interp_tier_enter_jiterpreter (
prepare_result, frame, locals, context, ip
);
ip = (guint16*) (((guint8*)ip) + offset);
break;
}
} else {
Expand All @@ -7679,31 +7711,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;

MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER) {
JiterpreterThunk thunk = (void*)READ32(ip + 1);
gboolean trace_requires_safepoint = FALSE;
g_assert(thunk);
ptrdiff_t offset = thunk(frame, locals);
/*
* The trace signals that we need to perform a safepoint by adding a very
* large amount to the relative displacement. This is because setting a bit
* in JS via the | operator doesn't work for negative numbers
*/
if (offset >= 0xE000000) {
offset -= 0xF000000;
trace_requires_safepoint = TRUE;
}
/*
* Verify that the offset returned by the thunk is not total garbage
* FIXME: These constants might actually be too small since a method
* could have massive amounts of IL - maybe we should disable the jiterpreter
* for methods that big
*/
g_assertf((offset >= -0xFFFFF) && (offset <= 0xFFFFF), "thunk returned an obviously invalid offset: %i", offset);
if (offset <= 0) {
BACK_BRANCH_PROFILE (offset);
}
if (trace_requires_safepoint) {
SAFEPOINT;
}
ptrdiff_t offset = mono_interp_tier_enter_jiterpreter (
thunk, frame, locals, context, ip
);
ip = (guint16*) (((guint8*)ip) + offset);
MINT_IN_BREAK;
}
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/interp/jiterpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
case MINT_INTRINS_TRY_GET_HASHCODE:
case MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE:
case MINT_INTRINS_ENUM_HASFLAG:
case MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII:
case MINT_ADD_MUL_I4_IMM:
case MINT_ADD_MUL_I8_IMM:
case MINT_ARRAY_RANK:
Expand Down
10 changes: 2 additions & 8 deletions src/mono/wasm/runtime/jiterpreter-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,9 @@ export class WasmBuilder {
}
}

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

i52_const (value: number) {
Expand Down
45 changes: 39 additions & 6 deletions src/mono/wasm/runtime/jiterpreter-trace-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,37 @@ export function generate_wasm_body (
builder.callImport("hascsize");
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
break;

case MintOpcode.MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII: {
builder.local("pLocals");
// valueA (cache in lhs32, we need it again later)
append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load);
builder.local("math_lhs32", WasmOpcode.tee_local);
// valueB
append_ldloc(builder, getArgU16(ip, 3), WasmOpcode.i32_load);
// compute differentBits = (valueA ^ valueB) << 2
builder.appendU8(WasmOpcode.i32_xor);
builder.i32_const(2);
builder.appendU8(WasmOpcode.i32_shl);
builder.local("math_rhs32", WasmOpcode.set_local);
// compute indicator
builder.local("math_lhs32");
builder.i32_const(0x00050005);
builder.appendU8(WasmOpcode.i32_add);
builder.i32_const(0x00A000A0);
builder.appendU8(WasmOpcode.i32_or);
builder.i32_const(0x001A001A);
builder.appendU8(WasmOpcode.i32_add);
builder.i32_const(-8388737); // 0xFF7FFF7F == 4286578559U == -8388737
builder.appendU8(WasmOpcode.i32_or);
// result = (differentBits & indicator) == 0
builder.local("math_rhs32");
builder.appendU8(WasmOpcode.i32_and);
builder.appendU8(WasmOpcode.i32_eqz);
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
break;
}

case MintOpcode.MINT_ARRAY_RANK: {
builder.block();
// dest, src
Expand Down Expand Up @@ -1602,8 +1633,10 @@ const unopTable : { [opcode: number]: OpRec3 | undefined } = {

[MintOpcode.MINT_CONV_R4_I4]: [WasmOpcode.f32_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f32_store],
[MintOpcode.MINT_CONV_R8_I4]: [WasmOpcode.f64_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f64_store],
[MintOpcode.MINT_CONV_R_UN_I4]: [WasmOpcode.f64_convert_u_i32, WasmOpcode.i32_load, WasmOpcode.f64_store],
[MintOpcode.MINT_CONV_R4_I8]: [WasmOpcode.f32_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f32_store],
[MintOpcode.MINT_CONV_R8_I8]: [WasmOpcode.f64_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f64_store],
[MintOpcode.MINT_CONV_R_UN_I8]: [WasmOpcode.f64_convert_u_i64, WasmOpcode.i64_load, WasmOpcode.f64_store],
[MintOpcode.MINT_CONV_R8_R4]: [WasmOpcode.f64_promote_f32, WasmOpcode.f32_load, WasmOpcode.f64_store],
[MintOpcode.MINT_CONV_R4_R8]: [WasmOpcode.f32_demote_f64, WasmOpcode.f64_load, WasmOpcode.f32_store],

Expand Down Expand Up @@ -2169,10 +2202,10 @@ function emit_branch (
builder.appendULeb(0);

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

function append_bailout (builder: WasmBuilder, ip: MintOpcodePtr, reason: BailoutReason, highBit?: boolean) {
builder.ip_const(ip, highBit);
function append_bailout (builder: WasmBuilder, ip: MintOpcodePtr, reason: BailoutReason) {
builder.ip_const(ip);
if (builder.options.countBailouts) {
builder.i32_const(reason);
builder.callImport("bailout");
Expand Down
1 change: 0 additions & 1 deletion src/mono/wasm/runtime/jiterpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,6 @@ export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {
continue;

// not worth implementing / too difficult
case "intrins_ordinal_ignore_case_ascii":
case "intrins_marvin_block":
case "intrins_ascii_chars_to_uppercase":
case "newarr":
Expand Down