["safepoint", "safepoint", getRawCwrap("mono_jiterp_auto_safepoint")],
["hashcode", "hashcode", getRawCwrap("mono_jiterp_get_hashcode")],
["hascsize", "hascsize", getRawCwrap("mono_jiterp_object_has_component_size")],
+ ["hasflag", "hasflag", getRawCwrap("mono_jiterp_enum_hasflag")],
+ ["array_rank", "array_rank", getRawCwrap("mono_jiterp_get_array_rank")],
];
if (instrumentedMethodNames.length > 0) {
"ppObj": WasmValtype.i32,
}, WasmValtype.i32
);
+ builder.defineType(
+ "hasflag", {
+ "klass": WasmValtype.i32,
+ "dest": WasmValtype.i32,
+ "sp1": WasmValtype.i32,
+ "sp2": WasmValtype.i32,
+ }, WasmValtype.void
+ );
+ builder.defineType(
+ "array_rank", {
+ "destination": WasmValtype.i32,
+ "source": WasmValtype.i32,
+ }, WasmValtype.i32
+ );
builder.generateTypeSection();
compileStarted = _now();
const buffer = builder.getArrayView();
if (trace > 0)
- console.log(`${traceName} generated ${buffer.length} byte(s) of wasm`);
+ console.log(`${(<any>(builder.base)).toString(16)} ${traceName} generated ${buffer.length} byte(s) of wasm`);
counters.bytesGenerated += buffer.length;
const traceModule = new WebAssembly.Module(buffer);
else if (trace >= 2)
console.log(`${traceName} -> fn index ${idx}`);
+ // Ensure that a bit of ongoing diagnostic output is printed for very long-running test
+ // suites or benchmarks if you've enabled stats
+ if (builder.options.enableStats && (counters.tracesCompiled % 500) === 0)
+ jiterpreter_dump_stats(false, true);
+
return idx;
} catch (exc: any) {
threw = true;
append_ldloca(builder, getArgU16(ip, 2));
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
break;
+
case MintOpcode.MINT_LDTOKEN:
case MintOpcode.MINT_LDSTR:
+ case MintOpcode.MINT_LDFTN:
case MintOpcode.MINT_LDFTN_ADDR:
case MintOpcode.MINT_MONO_LDPTR: {
// Pre-load locals for the store op
builder.local("pLocals");
// frame->imethod->data_items [ip [2]]
- const data = get_imethod_data(frame, getArgU16(ip, 2));
+ let data = get_imethod_data(frame, getArgU16(ip, 2));
+ if (opcode === MintOpcode.MINT_LDFTN)
+ data = <any>cwraps.mono_jiterp_imethod_to_ftnptr(<any>data);
+
builder.ptr_const(data);
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
append_bailout(builder, ip, BailoutReason.NullCheck);
builder.endBlock();
break;
+ case MintOpcode.MINT_INTRINS_ENUM_HASFLAG: {
+ const klass = get_imethod_data(frame, getArgU16(ip, 4));
+ builder.ptr_const(klass);
+ append_ldloca(builder, getArgU16(ip, 1));
+ append_ldloca(builder, getArgU16(ip, 2));
+ append_ldloca(builder, getArgU16(ip, 3));
+ builder.callImport("hasflag");
+ break;
+ }
case MintOpcode.MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF: {
const offset = cwraps.mono_jiterp_get_offset_of_array_data();
builder.local("pLocals");
builder.callImport("hascsize");
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
break;
+ case MintOpcode.MINT_ARRAY_RANK: {
+ builder.block();
+ // dest, src
+ append_ldloca(builder, getArgU16(ip, 1));
+ append_ldloca(builder, getArgU16(ip, 2));
+ builder.callImport("array_rank");
+ // If the array was null we will bail out, otherwise continue
+ builder.appendU8(WasmOpcode.br_if);
+ builder.appendULeb(0);
+ append_bailout(builder, ip, BailoutReason.NullCheck);
+ builder.endBlock();
+ break;
+ }
case MintOpcode.MINT_CASTCLASS:
case MintOpcode.MINT_ISINST:
builder.endBlock();
break;
+ case MintOpcode.MINT_ADD_MUL_I4_IMM:
+ case MintOpcode.MINT_ADD_MUL_I8_IMM: {
+ const isI32 = opcode === MintOpcode.MINT_ADD_MUL_I4_IMM;
+ builder.local("pLocals");
+ append_ldloc(builder, getArgU16(ip, 2), isI32 ? WasmOpcode.i32_load : WasmOpcode.i64_load);
+ const rhs = getArgI16(ip, 3),
+ multiplier = getArgI16(ip, 4);
+ if (isI32)
+ builder.i32_const(rhs);
+ else
+ builder.i52_const(rhs);
+ builder.appendU8(isI32 ? WasmOpcode.i32_add : WasmOpcode.i64_add);
+ if (isI32)
+ builder.i32_const(multiplier);
+ else
+ builder.i52_const(multiplier);
+ builder.appendU8(isI32? WasmOpcode.i32_mul : WasmOpcode.i64_mul);
+ append_stloc_tail(builder, getArgU16(ip, 1), isI32 ? WasmOpcode.i32_store : WasmOpcode.i64_store);
+ break;
+ }
+
default:
if (opname.startsWith("ret")) {
if ((builder.branchTargets.size > 0) || trapTraceErrors || builder.options.countBailouts)
return JITERPRETER_TRAINING;
}
-export function jiterpreter_dump_stats (b?: boolean) {
+export function jiterpreter_dump_stats (b?: boolean, concise?: boolean) {
if (!mostRecentOptions || (b !== undefined))
mostRecentOptions = getOptions();
console.log(`// generated: ${counters.bytesGenerated} wasm bytes; ${counters.tracesCompiled} traces (${counters.traceCandidates} candidates, ${(counters.tracesCompiled / counters.traceCandidates * 100).toFixed(1)}%); ${counters.jitCallsCompiled} jit_calls (${(counters.directJitCallsCompiled / counters.jitCallsCompiled * 100).toFixed(1)}% direct); ${counters.entryWrappersCompiled} interp_entries`);
console.log(`// time spent: ${elapsedTimes.generation | 0}ms generating, ${elapsedTimes.compilation | 0}ms compiling wasm`);
+ if (concise)
+ return;
+
if (mostRecentOptions.countBailouts) {
for (let i = 0; i < BailoutReasonNames.length; i++) {
const bailoutCount = cwraps.mono_jiterp_get_trace_bailout_count(i);