From 23e4de7e905f11a0caffe8fdc49bc8c17796560b Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Sat, 29 Apr 2023 23:08:43 -0700 Subject: [PATCH] Update jiterpreter interp_entry wrapper generator and re-enable jiterp --- src/mono/mono/mini/interp/interp-internals.h | 7 +++- src/mono/mono/mini/interp/interp.c | 26 +++++++----- src/mono/mono/mini/interp/jiterpreter.c | 3 ++ src/mono/mono/mini/interp/jiterpreter.h | 3 +- src/mono/mono/utils/options-def.h | 14 +++---- src/mono/wasm/runtime/cwraps.ts | 2 + .../wasm/runtime/jiterpreter-interp-entry.ts | 42 +++++++++---------- src/mono/wasm/runtime/jiterpreter-support.ts | 1 + 8 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index 6ef795a277c39..fb8e9e3fd236a 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -339,12 +339,15 @@ mono_jiterp_overflow_check_u4 (guint32 lhs, guint32 rhs, int opcode); void mono_jiterp_ld_delegate_method_ptr (gpointer *destination, MonoDelegate **source); -int +void mono_jiterp_stackval_to_data (MonoType *type, stackval *val, void *data); -int +void mono_jiterp_stackval_from_data (MonoType *type, stackval *result, const void *data); +int +mono_jiterp_get_arg_offset (InterpMethod *imethod, MonoMethodSignature *sig, int index); + gpointer mono_jiterp_frame_data_allocator_alloc (FrameDataAllocator *stack, InterpFrame *frame, int size); diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index ffc0ef8f3a135..32b6c4b470b86 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -8687,18 +8687,22 @@ mono_ee_interp_init (const char *opts) } #ifdef HOST_BROWSER -EMSCRIPTEN_KEEPALIVE int +EMSCRIPTEN_KEEPALIVE void mono_jiterp_stackval_to_data (MonoType *type, stackval *val, void *data) { - g_error ("FIXME"); - return 0; //stackval_to_data (type, val, data, FALSE); + stackval_to_data (type, val, data, FALSE); } -EMSCRIPTEN_KEEPALIVE int +EMSCRIPTEN_KEEPALIVE void mono_jiterp_stackval_from_data (MonoType *type, stackval *result, const void *data) { - g_error ("FIXME"); - return 0; //stackval_from_data (type, result, data, FALSE); + stackval_from_data (type, result, data, FALSE); +} + +EMSCRIPTEN_KEEPALIVE int +mono_jiterp_get_arg_offset (InterpMethod *imethod, MonoMethodSignature *sig, int index) +{ + return get_arg_offset_fast (imethod, sig, index); } EMSCRIPTEN_KEEPALIVE int @@ -8778,7 +8782,7 @@ mono_jiterp_isinst (MonoObject* object, MonoClass* klass) // in the correct place and compute the stack offset, then it passes that in to this // function in order to actually enter the interpreter and process the return value EMSCRIPTEN_KEEPALIVE void -mono_jiterp_interp_entry (JiterpEntryData *_data, stackval *sp_args, void *res) +mono_jiterp_interp_entry (JiterpEntryData *_data, void *res) { JiterpEntryDataHeader header; MonoType *type; @@ -8791,7 +8795,6 @@ mono_jiterp_interp_entry (JiterpEntryData *_data, stackval *sp_args, void *res) g_assert(header.rmethod); g_assert(header.rmethod->method); - g_assert(sp_args); stackval *sp = (stackval*)header.context->stack_pointer; @@ -8800,8 +8803,11 @@ mono_jiterp_interp_entry (JiterpEntryData *_data, stackval *sp_args, void *res) frame.stack = sp; frame.retval = sp; - header.context->stack_pointer = (guchar*)sp_args; - g_assert ((guchar*)sp_args < header.context->stack_end); + int params_size = get_arg_offset_fast (header.rmethod, NULL, header.params_count); + // g_printf ("jiterp_interp_entry: rmethod=%d, params_count=%d, params_size=%d\n", header.rmethod, header.params_count, params_size); + header.context->stack_pointer = (guchar*)ALIGN_TO ((guchar*)sp + params_size, MINT_STACK_ALIGNMENT); +; + g_assert (header.context->stack_pointer < header.context->stack_end); MONO_ENTER_GC_UNSAFE; mono_interp_exec_method (&frame, header.context, NULL); diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c index d61e78ef88551..5133210f74457 100644 --- a/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/mono/mono/mini/interp/jiterpreter.c @@ -1169,6 +1169,7 @@ mono_jiterp_trace_transfer ( #define JITERP_MEMBER_BACKWARD_BRANCH_OFFSETS 10 #define JITERP_MEMBER_BACKWARD_BRANCH_OFFSETS_COUNT 11 #define JITERP_MEMBER_CLAUSE_DATA_OFFSETS 12 +#define JITERP_MEMBER_PARAMS_COUNT 13 // we use these helpers at JIT time to figure out where to do memory loads and stores EMSCRIPTEN_KEEPALIVE size_t @@ -1196,6 +1197,8 @@ mono_jiterp_get_member_offset (int member) { return offsetof (InterpMethod, clause_data_offsets); case JITERP_MEMBER_RMETHOD: return offsetof (JiterpEntryDataHeader, rmethod); + case JITERP_MEMBER_PARAMS_COUNT: + return offsetof (JiterpEntryDataHeader, params_count); case JITERP_MEMBER_SPAN_LENGTH: return offsetof (MonoSpanOfVoid, _length); case JITERP_MEMBER_SPAN_DATA: diff --git a/src/mono/mono/mini/interp/jiterpreter.h b/src/mono/mono/mini/interp/jiterpreter.h index 896387b608a89..857307218891a 100644 --- a/src/mono/mono/mini/interp/jiterpreter.h +++ b/src/mono/mono/mini/interp/jiterpreter.h @@ -106,6 +106,7 @@ typedef struct { ThreadContext *context; gpointer orig_domain; gpointer attach_cookie; + int params_count; } JiterpEntryDataHeader; // we optimize delegate calls by attempting to cache the delegate invoke @@ -136,7 +137,7 @@ void mono_jiterp_do_safepoint (InterpFrame *frame, guint16 *ip); void -mono_jiterp_interp_entry (JiterpEntryData *_data, stackval *sp_args, void *res); +mono_jiterp_interp_entry (JiterpEntryData *_data, void *res); gpointer mono_jiterp_imethod_to_ftnptr (InterpMethod *imethod); diff --git a/src/mono/mono/utils/options-def.h b/src/mono/mono/utils/options-def.h index 87988c0577e71..b73ec8b2810f8 100644 --- a/src/mono/mono/utils/options-def.h +++ b/src/mono/mono/utils/options-def.h @@ -73,11 +73,11 @@ DEFINE_BOOL(interp_simd_packedsimd, "interp-simd-packedsimd", FALSE, "Enable int // and wasm modules between threads. before these can be enabled we need to implement all that #ifdef DISABLE_THREADS // traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces -DEFINE_BOOL(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", FALSE, "JIT interpreter opcode traces into WASM") +DEFINE_BOOL(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", TRUE, "JIT interpreter opcode traces into WASM") // interp_entry_enabled controls whether specialized interp_entry wrappers will be jitted -DEFINE_BOOL(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled", FALSE, "JIT specialized WASM interp_entry wrappers") +DEFINE_BOOL(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled", TRUE, "JIT specialized WASM interp_entry wrappers") // jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites -DEFINE_BOOL(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", FALSE, "JIT specialized WASM do_jit_call trampolines") +DEFINE_BOOL(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", TRUE, "JIT specialized WASM do_jit_call trampolines") #else // traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces DEFINE_BOOL_READONLY(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", FALSE, "JIT interpreter opcode traces into WASM") @@ -101,7 +101,7 @@ DEFINE_BOOL(jiterpreter_call_resume_enabled, "jiterpreter-call-resume-enabled", // stats for options like estimateHeat, but raises overhead. DEFINE_BOOL(jiterpreter_disable_heuristic, "jiterpreter-disable-heuristic", FALSE, "Always insert trace entry points for more accurate statistics") // Automatically prints stats at app exit or when jiterpreter_dump_stats is called -DEFINE_BOOL(jiterpreter_stats_enabled, "jiterpreter-stats-enabled", FALSE, "Automatically print jiterpreter statistics") +DEFINE_BOOL(jiterpreter_stats_enabled, "jiterpreter-stats-enabled", TRUE, "Automatically print jiterpreter statistics") // Continue counting hits for traces that fail to compile and use it to estimate // the relative importance of the opcode that caused them to abort DEFINE_BOOL(jiterpreter_estimate_heat, "jiterpreter-estimate-heat", FALSE, "Maintain accurate hit count for all trace entry points") @@ -145,12 +145,12 @@ DEFINE_INT(jiterpreter_jit_call_trampoline_hit_count, "jiterpreter-jit-call-hit- // After a do_jit_call call site is hit this many times without being jitted, we will flush the JIT queue DEFINE_INT(jiterpreter_jit_call_queue_flush_threshold, "jiterpreter-jit-call-queue-flush-threshold", 5000, "Flush the do_jit_call JIT queue after an unJITted call site has this many hits") // After a generic interp_entry wrapper is hit this many times, we will queue it to be jitted -DEFINE_INT(jiterpreter_interp_entry_trampoline_hit_count, "jiterpreter-interp-entry-hit-count", 1000, "Queue specialized interp_entry wrapper for JIT after this many hits") +DEFINE_INT(jiterpreter_interp_entry_trampoline_hit_count, "jiterpreter-interp-entry-hit-count", 1, "Queue specialized interp_entry wrapper for JIT after this many hits") // After a generic interp_entry wrapper is hit this many times without being jitted, we will flush the JIT queue -DEFINE_INT(jiterpreter_interp_entry_queue_flush_threshold, "jiterpreter-interp-entry-queue-flush-threshold", 3000, "Flush the interp_entry JIT queue after an unJITted call site has this many hits") +DEFINE_INT(jiterpreter_interp_entry_queue_flush_threshold, "jiterpreter-interp-entry-queue-flush-threshold", 300, "Flush the interp_entry JIT queue after an unJITted call site has this many hits") // In degenerate cases the jiterpreter could end up generating lots of WASM, so shut off jitting once it reaches this limit // Each wasm byte likely maps to multiple bytes of native code, so it's important for this limit not to be too high -DEFINE_INT(jiterpreter_wasm_bytes_limit, "jiterpreter-wasm-bytes-limit", 6 * 1024 * 1024, "Disable jiterpreter code generation once this many bytes of WASM have been generated") +DEFINE_INT(jiterpreter_wasm_bytes_limit, "jiterpreter-wasm-bytes-limit", 16 * 1024 * 1024, "Disable jiterpreter code generation once this many bytes of WASM have been generated") #endif // HOST_BROWSER #ifdef TARGET_WASM diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts index 3b0a98261edf4..d13d10ccbb33f 100644 --- a/src/mono/wasm/runtime/cwraps.ts +++ b/src/mono/wasm/runtime/cwraps.ts @@ -127,6 +127,7 @@ const fn_signatures: SigLine[] = [ [true, "mono_jiterp_get_opcode_value_table_entry", "number", ["number"]], [true, "mono_jiterp_get_simd_intrinsic", "number", ["number", "number"]], [true, "mono_jiterp_get_simd_opcode", "number", ["number", "number"]], + [true, "mono_jiterp_get_arg_offset", "number", ["number", "number", "number"]], ...legacy_interop_cwraps ]; @@ -250,6 +251,7 @@ export interface t_Cwraps { mono_jiterp_get_opcode_value_table_entry(opcode: number): number; mono_jiterp_get_simd_intrinsic(arity: number, index: number): VoidPtr; mono_jiterp_get_simd_opcode(arity: number, index: number): number; + mono_jiterp_get_arg_offset (imethod: number, sig: number, index: number): number; } const wrapped_c_functions: t_Cwraps = {}; diff --git a/src/mono/wasm/runtime/jiterpreter-interp-entry.ts b/src/mono/wasm/runtime/jiterpreter-interp-entry.ts index 14651ad27e970..ed94dc0283549 100644 --- a/src/mono/wasm/runtime/jiterpreter-interp-entry.ts +++ b/src/mono/wasm/runtime/jiterpreter-interp-entry.ts @@ -5,7 +5,7 @@ import { mono_assert, MonoMethod, MonoType } from "./types"; import { NativePointer } from "./types/emscripten"; import { Module } from "./globals"; import { - getU32_unaligned, _zero_region + setI32, getU32_unaligned, _zero_region } from "./memory"; import { WasmOpcode } from "./jiterpreter-opcodes"; import cwraps from "./cwraps"; @@ -36,6 +36,7 @@ typedef struct { ThreadContext *context; // 4 gpointer orig_domain; // 8 gpointer attach_cookie; // 12 + int params_count; // 16 } JiterpEntryDataHeader; */ @@ -231,7 +232,6 @@ function flush_wasm_entry_trampoline_jit_queue() { "interp_entry", { "pData": WasmValtype.i32, - "sp_args": WasmValtype.i32, "res": WasmValtype.i32, }, WasmValtype.void, true @@ -243,7 +243,7 @@ function flush_wasm_entry_trampoline_jit_queue() { "result": WasmValtype.i32, "value": WasmValtype.i32 }, - WasmValtype.i32, true + WasmValtype.void, true ); } else builder.clear(constantSlots); @@ -411,10 +411,10 @@ function flush_wasm_entry_trampoline_jit_queue() { } function append_stackval_from_data( - builder: WasmBuilder, type: MonoType, valueName: string + builder: WasmBuilder, imethod: number, type: MonoType, valueName: string, argIndex: number ) { - const stackvalSize = cwraps.mono_jiterp_get_size_of_stackval(); const rawSize = cwraps.mono_jiterp_type_get_raw_value_size(type); + const offset = cwraps.mono_jiterp_get_arg_offset(imethod, 0, argIndex); switch (rawSize) { case 256: { @@ -423,10 +423,7 @@ function append_stackval_from_data( builder.local(valueName); builder.appendU8(WasmOpcode.i32_store); - builder.appendMemarg(0, 2); - - // Fixed stackval size - builder.i32_const(stackvalSize); + builder.appendMemarg(offset, 2); break; } @@ -465,18 +462,18 @@ function append_stackval_from_data( } builder.appendU8(WasmOpcode.i32_store); - builder.appendMemarg(0, 2); - - // Fixed stackval size - builder.i32_const(stackvalSize); + builder.appendMemarg(offset, 2); break; } default: { - // Call stackval_from_data to copy the value and get its size + // Call stackval_from_data to copy the value builder.ptr_const(type); // result builder.local("sp_args"); + // apply offset + builder.i32_const(offset); + builder.appendU8(WasmOpcode.i32_add); // value builder.local(valueName); @@ -484,11 +481,6 @@ function append_stackval_from_data( break; } } - - // Value size is on the stack, add it to sp_args and update it - builder.local("sp_args"); - builder.appendU8(WasmOpcode.i32_add); - builder.local("sp_args", WasmOpcode.set_local); } function generate_wasm_body( @@ -505,6 +497,13 @@ function generate_wasm_body( const scratchBuffer = Module._malloc(sizeOfJiterpEntryData); _zero_region(scratchBuffer, sizeOfJiterpEntryData); + // Initialize the parameter count in the data blob. This is used to calculate the new value of sp + // before entering the interpreter + setI32( + scratchBuffer + getMemberOffset(JiterpMember.ParamsCount), + info.paramTypes.length + (info.hasThisReference ? 1 : 0) + ); + // the this-reference may be a boxed struct that needs to be unboxed, for example calling // methods like object.ToString on structs will end up with the unbox flag set // instead of passing an extra 'unbox' argument to every wrapper, though, the flag is hidden @@ -559,7 +558,7 @@ function generate_wasm_body( if (info.hasThisReference) { // null type for raw ptr copy - append_stackval_from_data(builder, 0, "this_arg"); + append_stackval_from_data(builder, info.imethod, 0, "this_arg", 0); } /* @@ -576,11 +575,10 @@ function generate_wasm_body( for (let i = 0; i < info.paramTypes.length; i++) { const type = info.paramTypes[i]; - append_stackval_from_data(builder, type, `arg${i}`); + append_stackval_from_data(builder, info.imethod, type, `arg${i}`, i + (info.hasThisReference ? 1 : 0)); } builder.local("scratchBuffer"); - builder.local("sp_args"); if (info.hasReturnValue) builder.local("res"); else diff --git a/src/mono/wasm/runtime/jiterpreter-support.ts b/src/mono/wasm/runtime/jiterpreter-support.ts index 306757573a59e..bc4df330047f3 100644 --- a/src/mono/wasm/runtime/jiterpreter-support.ts +++ b/src/mono/wasm/runtime/jiterpreter-support.ts @@ -1666,6 +1666,7 @@ export const enum JiterpMember { BackwardBranchOffsets = 10, BackwardBranchOffsetsCount = 11, ClauseDataOffsets = 12, + ParamsCount = 13, } const memberOffsets: { [index: number]: number } = {};