Skip to content

Commit

Permalink
[wasm] Outline exception throws in the interp and ifdef out unreachab…
Browse files Browse the repository at this point in the history
…le opcodes (#79239)

* Outline THROW_EX_GENERAL and ifdef out unreachable opcodes in the wasm version of the mono interpreter for better performance
* Introduce IROPDEF for intermediate opcodes that are only used during code generation
* Move IR opcodes to the end of the table and don't generate jump targets for them
* Add an include guard to mintops.def to ensure that config.h is always included when it is used
* Make the jiterp opcodes platform specific, fix a bug in genmintops that produced wrong ordering
* Fix jiterpreter heuristic erroneously rejecting mov opcodes
  • Loading branch information
kg authored Dec 14, 2022
1 parent d607096 commit d316bb4
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 51 deletions.
40 changes: 16 additions & 24 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1145,15 +1145,25 @@ INTERP_GET_EXCEPTION(array_type_mismatch)
INTERP_GET_EXCEPTION(arithmetic)
INTERP_GET_EXCEPTION_CHAR_ARG(argument_out_of_range)

// Inlining throw logic into interp_exec_method makes it bigger and could push us up against
// internal limits in things like WASM compilers
static MONO_NEVER_INLINE void
interp_throw_ex_general (
MonoException *__ex, ThreadContext *context, InterpFrame *frame, const guint16 *ex_ip, gboolean rethrow
)
{
HANDLE_FUNCTION_ENTER ();
MonoExceptionHandle tmp_handle = MONO_HANDLE_NEW (MonoException, __ex);
interp_throw (context, MONO_HANDLE_RAW(tmp_handle), (frame), (ex_ip), (rethrow));
HANDLE_FUNCTION_RETURN ();
}

// We conservatively pin exception object here to avoid tweaking the
// numerous call sites of this macro, even though, in a few cases,
// this is not needed.
#define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
do { \
MonoException *__ex = (exception); \
MONO_HANDLE_ASSIGN_RAW (tmp_handle, (MonoObject*)__ex); \
interp_throw (context, __ex, (frame), (ex_ip), (rethrow)); \
MONO_HANDLE_ASSIGN_RAW (tmp_handle, (MonoObject*)NULL); \
interp_throw_ex_general (exception, context, frame, ex_ip, rethrow); \
goto resume; \
} while (0)

Expand Down Expand Up @@ -3720,6 +3730,7 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause
#if USE_COMPUTED_GOTO
static void * const in_labels[] = {
#define OPDEF(a,b,c,d,e,f) &&LAB_ ## a,
#define IROPDEF(a,b,c,d,e,f)
#include "mintops.def"
};
#endif
Expand Down Expand Up @@ -3794,19 +3805,6 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause
memset (locals + ip [1], 0, ip [2]);
ip += 3;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_NOP)
MINT_IN_CASE(MINT_IL_SEQ_POINT)
MINT_IN_CASE(MINT_NIY)
MINT_IN_CASE(MINT_DEF)
MINT_IN_CASE(MINT_DUMMY_USE)
MINT_IN_CASE(MINT_TIER_PATCHPOINT_DATA)
#ifndef HOST_BROWSER
MINT_IN_CASE(MINT_TIER_NOP_JITERPRETER)
MINT_IN_CASE(MINT_TIER_PREPARE_JITERPRETER)
MINT_IN_CASE(MINT_TIER_ENTER_JITERPRETER)
#endif
g_assert_not_reached ();
MINT_IN_BREAK;
MINT_IN_CASE(MINT_BREAK)
++ip;
SAVE_INTERP_STATE (frame);
Expand Down Expand Up @@ -7227,12 +7225,6 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
ip += 3;
MINT_IN_BREAK;

MINT_IN_CASE(MINT_MOV_SRC_OFF)
MINT_IN_CASE(MINT_MOV_DST_OFF)
// This opcode is resolved to a normal MINT_MOV when emitting compacted instructions
g_assert_not_reached ();
MINT_IN_BREAK;

#define MOV(argtype1,argtype2) \
LOCAL_VAR (ip [1], argtype1) = LOCAL_VAR (ip [2], argtype2); \
ip += 3;
Expand Down Expand Up @@ -7571,7 +7563,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
#if !USE_COMPUTED_GOTO
default:
interp_error_xsx ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname (*ip), GPTRDIFF_TO_INT (ip - frame->imethod->code));
#endif
#endif // USE_COMPUTED_GOTO
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/mono/mono/mini/interp/jiterpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,11 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
case MINT_SAFEPOINT:
return TRACE_ABORT;

case MINT_MOV_SRC_OFF:
case MINT_MOV_DST_OFF:
// These opcodes will turn into supported MOVs later
return TRACE_CONTINUE;

default:
if (
// branches
Expand Down Expand Up @@ -746,7 +751,7 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
)
return TRACE_CONTINUE;
else if (
(opcode >= MINT_MOV_SRC_OFF) &&
(opcode >= MINT_MOV_I4_I1) &&
(opcode <= MINT_MOV_8_4)
)
return TRACE_CONTINUE;
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/interp/mintops.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
#include <glib.h>
#include <stdio.h>
#include "config.h"
#include "mintops.h"

// This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
Expand Down
47 changes: 34 additions & 13 deletions src/mono/mono/mini/interp/mintops.def
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
*
* OPDEF (opsymbol, opstring, oplength (in uint16s), num_dregs (0 or 1), num_sregs, optype)
* optype describes the contents of the instruction, following the dreg/sreg offsets.
*/

/*
*
* IROPDEF is like OPDEF but for instructions that are never executed by the interpreter,
* meant for use by transform.c and other internals. They *must* be defined at the end after
* all regular OPDEFs.
*
* This file is parsed by genmintops.py to generate typescript during the wasm build process,
* so if you make any changes to its syntax you will need to update that script.
* Any preprocessing directives are removed without being parsed!
*/

OPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
OPDEF(MINT_NIY, "niy", 1, 0, 0, MintOpNoArgs)
OPDEF(MINT_DEF, "def", 2, 1, 0, MintOpNoArgs)
OPDEF(MINT_IL_SEQ_POINT, "il_seq_point", 1, 0, 0, MintOpNoArgs)
OPDEF(MINT_DUMMY_USE, "dummy_use", 2, 0, 1, MintOpNoArgs)
OPDEF(MINT_TIER_PATCHPOINT_DATA, "tier_patchpoint_data", 2, 0, 0, MintOpShortInt)
#ifndef __MONO_CONFIG_H__
#error You must include config.h before including mintops.def
#endif

// Compatibility shim for old code
#ifndef IROPDEF
#define __DEFINED_IROPDEF__
#define IROPDEF(opsymbol, opstring, oplength, num_dregs, num_sregs, optype) OPDEF(opsymbol, opstring, oplength, num_dregs, num_sregs, optype)
#endif // IROPDEF

OPDEF(MINT_BREAK, "break", 1, 0, 0, MintOpNoArgs)
OPDEF(MINT_BREAKPOINT, "breakpoint", 1, 0, 0, MintOpNoArgs)

Expand Down Expand Up @@ -112,9 +119,6 @@ OPDEF(MINT_STSFLD_W, "stsfld.w", 8, 0, 1, MintOpTwoInts)
OPDEF(MINT_LDSFLDA, "ldsflda", 4, 1, 0, MintOpTwoShorts)
OPDEF(MINT_LDTSFLDA, "ldtsflda", 4, 1, 0, MintOpInt)

OPDEF(MINT_MOV_SRC_OFF, "mov.src.off", 6, 1, 1, MintOpTwoShorts)
OPDEF(MINT_MOV_DST_OFF, "mov.dst.off", 6, 1, 1, MintOpTwoShorts)

OPDEF(MINT_MOV_I4_I1, "mov.i4.i1", 3, 1, 1, MintOpNoArgs)
OPDEF(MINT_MOV_I4_U1, "mov.i4.u1", 3, 1, 1, MintOpNoArgs)
OPDEF(MINT_MOV_I4_I2, "mov.i4.i2", 3, 1, 1, MintOpNoArgs)
Expand Down Expand Up @@ -794,7 +798,24 @@ OPDEF(MINT_INTRINS_WIDEN_ASCII_TO_UTF16, "intrins_widen_ascii_to_utf16", 5, 1, 3

OPDEF(MINT_METADATA_UPDATE_LDFLDA, "metadata_update.ldflda", 5, 1, 1, MintOpTwoShorts)

// TODO: Make this wasm only
// This ifdef is fine because genmintops.py is generating output for HOST_BROWSER
#if HOST_BROWSER
OPDEF(MINT_TIER_PREPARE_JITERPRETER, "tier_prepare_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_NOP_JITERPRETER, "tier_nop_jiterpreter", 3, 0, 0, MintOpInt)
OPDEF(MINT_TIER_ENTER_JITERPRETER, "tier_enter_jiterpreter", 3, 0, 0, MintOpInt)
#endif // HOST_BROWSER

IROPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs)
IROPDEF(MINT_NIY, "niy", 1, 0, 0, MintOpNoArgs)
IROPDEF(MINT_DEF, "def", 2, 1, 0, MintOpNoArgs)
IROPDEF(MINT_IL_SEQ_POINT, "il_seq_point", 1, 0, 0, MintOpNoArgs)
IROPDEF(MINT_DUMMY_USE, "dummy_use", 2, 0, 1, MintOpNoArgs)
IROPDEF(MINT_TIER_PATCHPOINT_DATA, "tier_patchpoint_data", 2, 0, 0, MintOpShortInt)
// These two opcodes are resolved to a normal MINT_MOV when emitting compacted instructions
IROPDEF(MINT_MOV_SRC_OFF, "mov.src.off", 6, 1, 1, MintOpTwoShorts)
IROPDEF(MINT_MOV_DST_OFF, "mov.dst.off", 6, 1, 1, MintOpTwoShorts)

#ifdef __DEFINED_IROPDEF__
#undef IROPDEF
#undef __DEFINED_IROPDEF__
#endif // __DEFINED_IROPDEF__
10 changes: 6 additions & 4 deletions src/mono/wasm/runtime/genmintops.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
src = open(src_header_path, 'r')

tab = " "
header = tab + src.read().replace("\n", "\n" + tab)
header_lines = src.read().splitlines()
# strip preprocessing directives and add indentation for tslint/eslint
header = "\n".join((tab + l) for l in header_lines if not l.startswith("#"))
src.close()

opdef_regex = r'OPDEF\((\w+),\s*(.+?),\s*(MintOp\w+)\)'
opdef_regex = r'\s(IR)?OPDEF\((\w+),\s*(.+?),\s*(MintOp\w+)\)'
enum_values = re.sub(
opdef_regex, lambda m : f"{m.group(1)}{' = 0' if (m.group(1) == 'MINT_NOP') else ''},", header
opdef_regex, lambda m : f"{m.group(2)},", header
)
metadata_table = re.sub(
opdef_regex, lambda m : f"[MintOpcode.{m.group(1)}]: [{m.group(2)}, MintOpArgType.{m.group(3)}],", header
opdef_regex, lambda m : f"[MintOpcode.{m.group(2)}]: [{m.group(3)}, MintOpArgType.{m.group(4)}],", header
)

generated = f"""
Expand Down
12 changes: 3 additions & 9 deletions src/mono/wasm/runtime/jiterpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1210,9 +1210,7 @@ function generate_wasm_body (
break;

default:
if (
opname.startsWith("ret")
) {
if (opname.startsWith("ret")) {
if ((builder.branchTargets.size > 0) || trapTraceErrors || builder.options.countBailouts)
append_bailout(builder, ip, BailoutReason.Return);
else
Expand All @@ -1230,14 +1228,10 @@ function generate_wasm_body (
) {
if (!emit_binop(builder, ip, opcode))
ip = abort;
} else if (
unopTable[opcode]
) {
} else if (unopTable[opcode]) {
if (!emit_unop(builder, ip, opcode))
ip = abort;
} else if (
relopbranchTable[opcode]
) {
} else if (relopbranchTable[opcode]) {
if (!emit_relop_branch(builder, ip, opcode))
ip = abort;
} else if (
Expand Down

0 comments on commit d316bb4

Please sign in to comment.