diff --git a/src/mono/browser/runtime/jiterpreter-opcodes.ts b/src/mono/browser/runtime/jiterpreter-opcodes.ts index de98528709353..d535070df2ae8 100644 --- a/src/mono/browser/runtime/jiterpreter-opcodes.ts +++ b/src/mono/browser/runtime/jiterpreter-opcodes.ts @@ -36,6 +36,7 @@ export const enum MintOpArgType { MintOpFloat, MintOpDouble, MintOpBranch, + MintOpShortBranch, MintOpSwitch, MintOpMethodToken, MintOpFieldToken, @@ -44,7 +45,7 @@ export const enum MintOpArgType { MintOpTwoShorts, MintOpTwoInts, MintOpShortAndInt, - MintOpShortAndBranch, + MintOpShortAndShortBranch, MintOpPair2, MintOpPair3, MintOpPair4 diff --git a/src/mono/browser/runtime/jiterpreter-tables.ts b/src/mono/browser/runtime/jiterpreter-tables.ts index 76a76798f7ea8..a345844e9d904 100644 --- a/src/mono/browser/runtime/jiterpreter-tables.ts +++ b/src/mono/browser/runtime/jiterpreter-tables.ts @@ -194,16 +194,16 @@ export const binopTable: { [opcode: number]: OpRec3 | OpRec4 | undefined } = { }; export const relopbranchTable: { [opcode: number]: [comparisonOpcode: MintOpcode, immediateOpcode: WasmOpcode | false, isSafepoint: boolean] | MintOpcode | undefined } = { - [MintOpcode.MINT_BEQ_I4]: MintOpcode.MINT_CEQ_I4, - [MintOpcode.MINT_BNE_UN_I4]: MintOpcode.MINT_CNE_I4, - [MintOpcode.MINT_BGT_I4]: MintOpcode.MINT_CGT_I4, - [MintOpcode.MINT_BGT_UN_I4]: MintOpcode.MINT_CGT_UN_I4, - [MintOpcode.MINT_BLT_I4]: MintOpcode.MINT_CLT_I4, - [MintOpcode.MINT_BLT_UN_I4]: MintOpcode.MINT_CLT_UN_I4, - [MintOpcode.MINT_BGE_I4]: MintOpcode.MINT_CGE_I4, - [MintOpcode.MINT_BGE_UN_I4]: MintOpcode.MINT_CGE_UN_I4, - [MintOpcode.MINT_BLE_I4]: MintOpcode.MINT_CLE_I4, - [MintOpcode.MINT_BLE_UN_I4]: MintOpcode.MINT_CLE_UN_I4, + [MintOpcode.MINT_BEQ_I4_S]: MintOpcode.MINT_CEQ_I4, + [MintOpcode.MINT_BNE_UN_I4_S]: MintOpcode.MINT_CNE_I4, + [MintOpcode.MINT_BGT_I4_S]: MintOpcode.MINT_CGT_I4, + [MintOpcode.MINT_BGT_UN_I4_S]: MintOpcode.MINT_CGT_UN_I4, + [MintOpcode.MINT_BLT_I4_S]: MintOpcode.MINT_CLT_I4, + [MintOpcode.MINT_BLT_UN_I4_S]: MintOpcode.MINT_CLT_UN_I4, + [MintOpcode.MINT_BGE_I4_S]: MintOpcode.MINT_CGE_I4, + [MintOpcode.MINT_BGE_UN_I4_S]: MintOpcode.MINT_CGE_UN_I4, + [MintOpcode.MINT_BLE_I4_S]: MintOpcode.MINT_CLE_I4, + [MintOpcode.MINT_BLE_UN_I4_S]: MintOpcode.MINT_CLE_UN_I4, [MintOpcode.MINT_BEQ_I4_SP]: [MintOpcode.MINT_CEQ_I4, false, true], [MintOpcode.MINT_BNE_UN_I4_SP]: [MintOpcode.MINT_CNE_I4, false, true], @@ -227,16 +227,16 @@ export const relopbranchTable: { [opcode: number]: [comparisonOpcode: MintOpcode [MintOpcode.MINT_BLE_I4_IMM_SP]: [MintOpcode.MINT_CLE_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BLE_UN_I4_IMM_SP]: [MintOpcode.MINT_CLE_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BEQ_I8]: MintOpcode.MINT_CEQ_I8, - [MintOpcode.MINT_BNE_UN_I8]: MintOpcode.MINT_CNE_I8, - [MintOpcode.MINT_BGT_I8]: MintOpcode.MINT_CGT_I8, - [MintOpcode.MINT_BGT_UN_I8]: MintOpcode.MINT_CGT_UN_I8, - [MintOpcode.MINT_BLT_I8]: MintOpcode.MINT_CLT_I8, - [MintOpcode.MINT_BLT_UN_I8]: MintOpcode.MINT_CLT_UN_I8, - [MintOpcode.MINT_BGE_I8]: MintOpcode.MINT_CGE_I8, - [MintOpcode.MINT_BGE_UN_I8]: MintOpcode.MINT_CGE_UN_I8, - [MintOpcode.MINT_BLE_I8]: MintOpcode.MINT_CLE_I8, - [MintOpcode.MINT_BLE_UN_I8]: MintOpcode.MINT_CLE_UN_I8, + [MintOpcode.MINT_BEQ_I8_S]: MintOpcode.MINT_CEQ_I8, + [MintOpcode.MINT_BNE_UN_I8_S]: MintOpcode.MINT_CNE_I8, + [MintOpcode.MINT_BGT_I8_S]: MintOpcode.MINT_CGT_I8, + [MintOpcode.MINT_BGT_UN_I8_S]: MintOpcode.MINT_CGT_UN_I8, + [MintOpcode.MINT_BLT_I8_S]: MintOpcode.MINT_CLT_I8, + [MintOpcode.MINT_BLT_UN_I8_S]: MintOpcode.MINT_CLT_UN_I8, + [MintOpcode.MINT_BGE_I8_S]: MintOpcode.MINT_CGE_I8, + [MintOpcode.MINT_BGE_UN_I8_S]: MintOpcode.MINT_CGE_UN_I8, + [MintOpcode.MINT_BLE_I8_S]: MintOpcode.MINT_CLE_I8, + [MintOpcode.MINT_BLE_UN_I8_S]: MintOpcode.MINT_CLE_UN_I8, [MintOpcode.MINT_BEQ_I8_IMM_SP]: [MintOpcode.MINT_CEQ_I8, WasmOpcode.i64_const, true], // FIXME: Missing compare opcode @@ -250,27 +250,27 @@ export const relopbranchTable: { [opcode: number]: [comparisonOpcode: MintOpcode [MintOpcode.MINT_BLE_I8_IMM_SP]: [MintOpcode.MINT_CLE_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BLE_UN_I8_IMM_SP]: [MintOpcode.MINT_CLE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BEQ_R4]: MintOpcode.MINT_CEQ_R4, - [MintOpcode.MINT_BNE_UN_R4]: JiterpSpecialOpcode.CNE_UN_R4, - [MintOpcode.MINT_BGT_R4]: MintOpcode.MINT_CGT_R4, - [MintOpcode.MINT_BGT_UN_R4]: MintOpcode.MINT_CGT_UN_R4, - [MintOpcode.MINT_BLT_R4]: MintOpcode.MINT_CLT_R4, - [MintOpcode.MINT_BLT_UN_R4]: MintOpcode.MINT_CLT_UN_R4, - [MintOpcode.MINT_BGE_R4]: MintOpcode.MINT_CGE_R4, - [MintOpcode.MINT_BGE_UN_R4]: JiterpSpecialOpcode.CGE_UN_R4, - [MintOpcode.MINT_BLE_R4]: MintOpcode.MINT_CLE_R4, - [MintOpcode.MINT_BLE_UN_R4]: JiterpSpecialOpcode.CLE_UN_R4, - - [MintOpcode.MINT_BEQ_R8]: MintOpcode.MINT_CEQ_R8, - [MintOpcode.MINT_BNE_UN_R8]: JiterpSpecialOpcode.CNE_UN_R8, - [MintOpcode.MINT_BGT_R8]: MintOpcode.MINT_CGT_R8, - [MintOpcode.MINT_BGT_UN_R8]: MintOpcode.MINT_CGT_UN_R8, - [MintOpcode.MINT_BLT_R8]: MintOpcode.MINT_CLT_R8, - [MintOpcode.MINT_BLT_UN_R8]: MintOpcode.MINT_CLT_UN_R8, - [MintOpcode.MINT_BGE_R8]: MintOpcode.MINT_CGE_R8, - [MintOpcode.MINT_BGE_UN_R8]: JiterpSpecialOpcode.CGE_UN_R8, - [MintOpcode.MINT_BLE_R8]: MintOpcode.MINT_CLE_R8, - [MintOpcode.MINT_BLE_UN_R8]: JiterpSpecialOpcode.CLE_UN_R8, + [MintOpcode.MINT_BEQ_R4_S]: MintOpcode.MINT_CEQ_R4, + [MintOpcode.MINT_BNE_UN_R4_S]: JiterpSpecialOpcode.CNE_UN_R4, + [MintOpcode.MINT_BGT_R4_S]: MintOpcode.MINT_CGT_R4, + [MintOpcode.MINT_BGT_UN_R4_S]: MintOpcode.MINT_CGT_UN_R4, + [MintOpcode.MINT_BLT_R4_S]: MintOpcode.MINT_CLT_R4, + [MintOpcode.MINT_BLT_UN_R4_S]: MintOpcode.MINT_CLT_UN_R4, + [MintOpcode.MINT_BGE_R4_S]: MintOpcode.MINT_CGE_R4, + [MintOpcode.MINT_BGE_UN_R4_S]: JiterpSpecialOpcode.CGE_UN_R4, + [MintOpcode.MINT_BLE_R4_S]: MintOpcode.MINT_CLE_R4, + [MintOpcode.MINT_BLE_UN_R4_S]: JiterpSpecialOpcode.CLE_UN_R4, + + [MintOpcode.MINT_BEQ_R8_S]: MintOpcode.MINT_CEQ_R8, + [MintOpcode.MINT_BNE_UN_R8_S]: JiterpSpecialOpcode.CNE_UN_R8, + [MintOpcode.MINT_BGT_R8_S]: MintOpcode.MINT_CGT_R8, + [MintOpcode.MINT_BGT_UN_R8_S]: MintOpcode.MINT_CGT_UN_R8, + [MintOpcode.MINT_BLT_R8_S]: MintOpcode.MINT_CLT_R8, + [MintOpcode.MINT_BLT_UN_R8_S]: MintOpcode.MINT_CLT_UN_R8, + [MintOpcode.MINT_BGE_R8_S]: MintOpcode.MINT_CGE_R8, + [MintOpcode.MINT_BGE_UN_R8_S]: JiterpSpecialOpcode.CGE_UN_R8, + [MintOpcode.MINT_BLE_R8_S]: MintOpcode.MINT_CLE_R8, + [MintOpcode.MINT_BLE_UN_R8_S]: JiterpSpecialOpcode.CLE_UN_R8, }; export const mathIntrinsicTable: { [opcode: number]: [isUnary: boolean, isF32: boolean, opcodeOrFuncName: WasmOpcode | string] } = { diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index 2a4471b20899a..e81c9b6683cbc 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -218,6 +218,7 @@ export function generateBackwardBranchTable ( switch (opcode) { case MintOpcode.MINT_CALL_HANDLER: + case MintOpcode.MINT_CALL_HANDLER_S: // While this formally isn't a backward branch target, we want to record // the offset of its following instruction so that the jiterpreter knows // to generate the necessary dispatch code to enable branching back to it. @@ -505,15 +506,21 @@ export function generateWasmBody ( } // Other conditional branch types are handled by the relop table. + case MintOpcode.MINT_BRFALSE_I4_S: + case MintOpcode.MINT_BRTRUE_I4_S: case MintOpcode.MINT_BRFALSE_I4_SP: case MintOpcode.MINT_BRTRUE_I4_SP: + case MintOpcode.MINT_BRFALSE_I8_S: + case MintOpcode.MINT_BRTRUE_I8_S: if (!emit_branch(builder, ip, frame, opcode)) ip = abort; else isConditionallyExecuted = true; break; + case MintOpcode.MINT_BR_S: case MintOpcode.MINT_CALL_HANDLER: + case MintOpcode.MINT_CALL_HANDLER_S: if (!emit_branch(builder, ip, frame, opcode)) ip = abort; else { @@ -1286,6 +1293,7 @@ export function generateWasmBody ( // These are generated in place of regular LEAVEs inside of the body of a catch clause. // We can safely assume that during normal execution, catch clauses won't be running. case MintOpcode.MINT_LEAVE_CHECK: + case MintOpcode.MINT_LEAVE_S_CHECK: append_bailout(builder, ip, BailoutReason.LeaveCheck); pruneOpcodes = true; break; @@ -2735,9 +2743,10 @@ function emit_unop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) function append_call_handler_store_ret_ip ( builder: WasmBuilder, ip: MintOpcodePtr, - frame: NativePointer + frame: NativePointer, opcode: MintOpcode ) { - const retIp = ip + (4 * 2), + const shortOffset = (opcode === MintOpcode.MINT_CALL_HANDLER_S), + retIp = shortOffset ? ip + (3 * 2) : ip + (4 * 2), clauseIndex = getU16(retIp - 2), clauseDataOffset = get_imethod_clause_data_offset(frame, clauseIndex); @@ -2752,21 +2761,6 @@ function append_call_handler_store_ret_ip ( builder.callHandlerReturnAddresses.push(retIp); } -function getBranchImmediate ( - ip: MintOpcodePtr, opcode: MintOpcode -): number | undefined { - const opArgType = cwraps.mono_jiterp_get_opcode_info(opcode, OpcodeInfoType.OpArgType), - payloadOffset = cwraps.mono_jiterp_get_opcode_info(opcode, OpcodeInfoType.Sregs), - payloadAddress = ip + 2 + (payloadOffset * 2); - - switch (opArgType) { - case MintOpArgType.MintOpShortAndBranch: - return getI16(payloadAddress); - default: - return undefined; - } -} - function getBranchDisplacement ( ip: MintOpcodePtr, opcode: MintOpcode ): number | undefined { @@ -2779,8 +2773,11 @@ function getBranchDisplacement ( case MintOpArgType.MintOpBranch: result = getI32_unaligned(payloadAddress); break; - case MintOpArgType.MintOpShortAndBranch: - result = getI32_unaligned(payloadAddress + 2); + case MintOpArgType.MintOpShortBranch: + result = getI16(payloadAddress); + break; + case MintOpArgType.MintOpShortAndShortBranch: + result = getI16(payloadAddress + 2); break; default: return undefined; @@ -2800,10 +2797,8 @@ function emit_branch ( (opcode <= MintOpcode.MINT_BLT_UN_I8_IMM_SP); const displacement = getBranchDisplacement(ip, opcode); - if (typeof (displacement) !== "number") { - // mono_log_info(`Failed to decode branch displacement for ${getOpcodeName(opcode)}`); + if (typeof (displacement) !== "number") return false; - } // If the branch is taken we bail out to allow the interpreter to do it. // So for brtrue, we want to do 'cond == 0' to produce a bailout only @@ -2813,8 +2808,11 @@ function emit_branch ( // branch target (if possible), bailing out at the end otherwise switch (opcode) { case MintOpcode.MINT_CALL_HANDLER: - case MintOpcode.MINT_BR: { - const isCallHandler = opcode === MintOpcode.MINT_CALL_HANDLER; + case MintOpcode.MINT_CALL_HANDLER_S: + case MintOpcode.MINT_BR: + case MintOpcode.MINT_BR_S: { + const isCallHandler = (opcode === MintOpcode.MINT_CALL_HANDLER) || + (opcode === MintOpcode.MINT_CALL_HANDLER_S); const destination = ip + (displacement * 2); @@ -2826,7 +2824,7 @@ function emit_branch ( if (builder.backBranchTraceLevel > 1) mono_log_info(`0x${(ip).toString(16)} performing backward branch to 0x${destination.toString(16)}`); if (isCallHandler) - append_call_handler_store_ret_ip(builder, ip, frame); + append_call_handler_store_ret_ip(builder, ip, frame, opcode); builder.cfg.branch(destination, true, CfgBranchType.Unconditional); modifyCounter(JiterpCounter.BackBranchesEmitted, 1); return true; @@ -2851,32 +2849,32 @@ function emit_branch ( // the current branch block after updating eip builder.branchTargets.add(destination); if (isCallHandler) - append_call_handler_store_ret_ip(builder, ip, frame); + append_call_handler_store_ret_ip(builder, ip, frame, opcode); builder.cfg.branch(destination, false, CfgBranchType.Unconditional); return true; } } - case MintOpcode.MINT_BRTRUE_I4: - case MintOpcode.MINT_BRFALSE_I4: + case MintOpcode.MINT_BRTRUE_I4_S: + case MintOpcode.MINT_BRFALSE_I4_S: case MintOpcode.MINT_BRTRUE_I4_SP: case MintOpcode.MINT_BRFALSE_I4_SP: - case MintOpcode.MINT_BRTRUE_I8: - case MintOpcode.MINT_BRFALSE_I8: { - const is64 = (opcode === MintOpcode.MINT_BRTRUE_I8) || - (opcode === MintOpcode.MINT_BRFALSE_I8); + case MintOpcode.MINT_BRTRUE_I8_S: + case MintOpcode.MINT_BRFALSE_I8_S: { + const is64 = (opcode === MintOpcode.MINT_BRTRUE_I8_S) || + (opcode === MintOpcode.MINT_BRFALSE_I8_S); // Load the condition append_ldloc(builder, getArgU16(ip, 1), is64 ? WasmOpcode.i64_load : WasmOpcode.i32_load); if ( - (opcode === MintOpcode.MINT_BRFALSE_I4) || + (opcode === MintOpcode.MINT_BRFALSE_I4_S) || (opcode === MintOpcode.MINT_BRFALSE_I4_SP) ) builder.appendU8(WasmOpcode.i32_eqz); - else if (opcode === MintOpcode.MINT_BRFALSE_I8) { + else if (opcode === MintOpcode.MINT_BRFALSE_I8_S) { builder.appendU8(WasmOpcode.i64_eqz); - } else if (opcode === MintOpcode.MINT_BRTRUE_I8) { + } else if (opcode === MintOpcode.MINT_BRTRUE_I8_S) { // do (i64 == 0) == 0 because br_if can only branch on an i32 operand builder.appendU8(WasmOpcode.i64_eqz); builder.appendU8(WasmOpcode.i32_eqz); @@ -2891,6 +2889,9 @@ function emit_branch ( if (relopbranchTable[opcode] === undefined) throw new Error(`Unsupported relop branch opcode: ${getOpcodeName(opcode)}`); + if (cwraps.mono_jiterp_get_opcode_info(opcode, OpcodeInfoType.Length) !== 4) + throw new Error(`Unsupported long branch opcode: ${getOpcodeName(opcode)}`); + break; } } @@ -2934,10 +2935,8 @@ function emit_relop_branch ( frame: NativePointer, opcode: MintOpcode ): boolean { const relopBranchInfo = relopbranchTable[opcode]; - if (!relopBranchInfo) { - // mono_log_info(`No info for relop branch ${getOpcodeName(opcode)}`); + if (!relopBranchInfo) return false; - } const relop = Array.isArray(relopBranchInfo) ? relopBranchInfo[0] @@ -2946,10 +2945,8 @@ function emit_relop_branch ( const relopInfo = binopTable[relop]; const intrinsicFpBinop = intrinsicFpBinops[relop]; - if (!relopInfo && !intrinsicFpBinop) { - // mono_log_info(`No info for relop ${getOpcodeName(opcode)} -> ${getOpcodeName(relop)}`); + if (!relopInfo && !intrinsicFpBinop) return false; - } const operandLoadOp = relopInfo ? relopInfo[1] @@ -2966,13 +2963,11 @@ function emit_relop_branch ( // Compare with immediate if (Array.isArray(relopBranchInfo) && relopBranchInfo[1]) { - const immediate = getBranchImmediate(ip, opcode); - mono_assert(immediate !== undefined, `Failed to decode immediate for branch opcode ${getOpcodeName(opcode)}`); // For i8 immediates we need to generate an i64.const even though // the immediate is 16 bits, so we store the relevant opcode // in the relop branch info table builder.appendU8(relopBranchInfo[1]); - builder.appendLeb(immediate); + builder.appendLeb(getArgI16(ip, 2)); } else append_ldloc(builder, getArgU16(ip, 2), operandLoadOp); diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index cb951d6206a6c..61e1ff55d2f9b 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -4474,6 +4474,12 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause #define BACK_BRANCH_PROFILE(offset) #endif + MINT_IN_CASE(MINT_BR_S) { + short br_offset = (short) *(ip + 1); + BACK_BRANCH_PROFILE (br_offset); + ip += br_offset; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BR) { gint32 br_offset = (gint32) READ32(ip + 1); BACK_BRANCH_PROFILE (br_offset); @@ -4481,6 +4487,14 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause MINT_IN_BREAK; } +#define ZEROP_S(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op 0) { \ + gint16 br_offset = (gint16) ip [2]; \ + BACK_BRANCH_PROFILE (br_offset); \ + ip += br_offset; \ + } else \ + ip += 3; + #define ZEROP(datatype, op) \ if (LOCAL_VAR (ip [1], datatype) op 0) { \ gint32 br_offset = (gint32)READ32(ip + 2); \ @@ -4489,18 +4503,39 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause } else \ ip += 4; + MINT_IN_CASE(MINT_BRFALSE_I4_S) + ZEROP_S(gint32, ==); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRFALSE_I8_S) + ZEROP_S(gint64, ==); + MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_I4) ZEROP(gint32, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_I8) ZEROP(gint64, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_I4_S) + ZEROP_S(gint32, !=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BRTRUE_I8_S) + ZEROP_S(gint64, !=); + MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_I4) ZEROP(gint32, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_I8) ZEROP(gint64, !=); MINT_IN_BREAK; +#define CONDBR_S(cond) \ + if (cond) { \ + gint16 br_offset = (gint16) ip [3]; \ + BACK_BRANCH_PROFILE (br_offset); \ + ip += br_offset; \ + } else \ + ip += 4; +#define BRELOP_S(datatype, op) \ + CONDBR_S(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) #define CONDBR(cond) \ if (cond) { \ @@ -4513,6 +4548,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause #define BRELOP(datatype, op) \ CONDBR(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) + MINT_IN_CASE(MINT_BEQ_I4_S) + BRELOP_S(gint32, ==) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8_S) + BRELOP_S(gint64, ==) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 == f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BEQ_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 == d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BEQ_I4) BRELOP(gint32, ==) MINT_IN_BREAK; @@ -4531,6 +4584,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(!mono_isunordered (d1, d2) && d1 == d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BGE_I4_S) + BRELOP_S(gint32, >=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8_S) + BRELOP_S(gint64, >=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 >= f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BGE_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 >= d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGE_I4) BRELOP(gint32, >=) MINT_IN_BREAK; @@ -4549,6 +4620,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(!mono_isunordered (d1, d2) && d1 >= d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BGT_I4_S) + BRELOP_S(gint32, >) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8_S) + BRELOP_S(gint64, >) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 > f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BGT_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 > d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGT_I4) BRELOP(gint32, >) MINT_IN_BREAK; @@ -4567,6 +4656,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(!mono_isunordered (d1, d2) && d1 > d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BLT_I4_S) + BRELOP_S(gint32, <) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8_S) + BRELOP_S(gint64, <) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 < f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BLT_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 < d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLT_I4) BRELOP(gint32, <) MINT_IN_BREAK; @@ -4585,6 +4692,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(!mono_isunordered (d1, d2) && d1 < d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BLE_I4_S) + BRELOP_S(gint32, <=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8_S) + BRELOP_S(gint64, <=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 <= f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BLE_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 <= d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLE_I4) BRELOP(gint32, <=) MINT_IN_BREAK; @@ -4603,6 +4728,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(!mono_isunordered (d1, d2) && d1 <= d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BNE_UN_I4_S) + BRELOP_S(gint32, !=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8_S) + BRELOP_S(gint64, !=) + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 != f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BNE_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 != d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BNE_UN_I4) BRELOP(gint32, !=) MINT_IN_BREAK; @@ -4622,6 +4765,14 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause MINT_IN_BREAK; } +#define BRELOP_S_CAST(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) { \ + gint16 br_offset = (gint16) ip [3]; \ + BACK_BRANCH_PROFILE (br_offset); \ + ip += br_offset; \ + } else \ + ip += 4; + #define BRELOP_CAST(datatype, op) \ if (LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) { \ gint32 br_offset = (gint32)READ32(ip + 3); \ @@ -4630,6 +4781,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause } else \ ip += 5; + MINT_IN_CASE(MINT_BGE_UN_I4_S) + BRELOP_S_CAST(guint32, >=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8_S) + BRELOP_S_CAST(guint64, >=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 >= f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BGE_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 >= d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGE_UN_I4) BRELOP_CAST(guint32, >=); MINT_IN_BREAK; @@ -4648,6 +4817,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(mono_isunordered (d1, d2) || d1 >= d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BGT_UN_I4_S) + BRELOP_S_CAST(guint32, >); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8_S) + BRELOP_S_CAST(guint64, >); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 > f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BGT_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 > d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGT_UN_I4) BRELOP_CAST(guint32, >); MINT_IN_BREAK; @@ -4666,6 +4853,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(mono_isunordered (d1, d2) || d1 > d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BLE_UN_I4_S) + BRELOP_S_CAST(guint32, <=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8_S) + BRELOP_S_CAST(guint64, <=); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 <= f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BLE_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 <= d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLE_UN_I4) BRELOP_CAST(guint32, <=); MINT_IN_BREAK; @@ -4684,6 +4889,24 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause CONDBR(mono_isunordered (d1, d2) || d1 <= d2) MINT_IN_BREAK; } + MINT_IN_CASE(MINT_BLT_UN_I4_S) + BRELOP_S_CAST(guint32, <); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8_S) + BRELOP_S_CAST(guint64, <); + MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 < f2) + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_BLT_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 < d2) + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLT_UN_I4) BRELOP_CAST(guint32, <); MINT_IN_BREAK; @@ -4705,12 +4928,12 @@ mono_interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClause #define ZEROP_SP(datatype, op) \ if (LOCAL_VAR (ip [1], datatype) op 0) { \ - gint32 br_offset = (gint32)READ32(ip + 2); \ + gint16 br_offset = (gint16) ip [2]; \ BACK_BRANCH_PROFILE (br_offset); \ SAFEPOINT; \ ip += br_offset; \ } else \ - ip += 4; + ip += 3; MINT_IN_CASE(MINT_BRFALSE_I4_SP) ZEROP_SP(gint32, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_I8_SP) ZEROP_SP(gint64, ==); MINT_IN_BREAK; @@ -4719,12 +4942,12 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; #define CONDBR_SP(cond) \ if (cond) { \ - gint32 br_offset = (gint32)READ32(ip + 3); \ + gint16 br_offset = (gint16) ip [3]; \ BACK_BRANCH_PROFILE (br_offset); \ SAFEPOINT; \ ip += br_offset; \ } else \ - ip += 5; + ip += 4; #define BRELOP_SP(datatype, op) \ CONDBR_SP(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) @@ -6905,25 +7128,31 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; ip = ret_ip; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CALL_HANDLER) { - const guint16 *ret_ip = ip + 4; + MINT_IN_CASE(MINT_CALL_HANDLER) + MINT_IN_CASE(MINT_CALL_HANDLER_S) { + gboolean short_offset = *ip == MINT_CALL_HANDLER_S; + const guint16 *ret_ip = short_offset ? (ip + 3) : (ip + 4); guint16 clause_index = *(ret_ip - 1); *(const guint16**)(locals + frame->imethod->clause_data_offsets [clause_index]) = ret_ip; // jump to clause - ip += (gint32)READ32 (ip + 1); + ip += short_offset ? (gint16)*(ip + 1) : (gint32)READ32 (ip + 1); MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LEAVE_CHECK) { + MINT_IN_CASE(MINT_LEAVE_CHECK) + MINT_IN_CASE(MINT_LEAVE_S_CHECK) { + int leave_opcode = *ip; + if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) { MonoException *abort_exc = mono_interp_leave (frame); if (abort_exc) THROW_EX (abort_exc, ip); } - ip += (gint32)READ32 (ip + 1); + gboolean const short_offset = leave_opcode == MINT_LEAVE_S_CHECK; + ip += short_offset ? (gint16)*(ip + 1) : (gint32)READ32 (ip + 1); MINT_IN_BREAK; } MINT_IN_CASE(MINT_ICALL) { diff --git a/src/mono/mono/mini/interp/jiterpreter-opcode-values.h b/src/mono/mono/mini/interp/jiterpreter-opcode-values.h index 3c0abb17c08a9..c3926ccb4c479 100644 --- a/src/mono/mono/mini/interp/jiterpreter-opcode-values.h +++ b/src/mono/mono/mini/interp/jiterpreter-opcode-values.h @@ -25,8 +25,8 @@ // // Put ranges first so we can override individual opcodes after // -OP(MINT_BR, BEGIN_BRANCH_BLOCK) -OP(MINT_CALL_HANDLER, BEGIN_BRANCH_BLOCK) +OPRANGE(MINT_BR, MINT_BR_S, BEGIN_BRANCH_BLOCK) +OPRANGE(MINT_CALL_HANDLER, MINT_CALL_HANDLER_S, BEGIN_BRANCH_BLOCK) OPRANGE(MINT_BRFALSE_I4, MINT_BLT_UN_I8_IMM_SP, BEGIN_BRANCH_BLOCK) OPRANGE(MINT_CALL, MINT_CALLI_NAT_FAST, ABORT_OUTSIDE_BRANCH_BLOCK_NONE) @@ -85,6 +85,7 @@ OP(MINT_SDB_SEQ_POINT, NONE) // These are only generated inside catch clauses, so it's safe to assume that // during normal execution they won't run, and compile them as a bailout. OP(MINT_LEAVE_CHECK, NONE) +OP(MINT_LEAVE_S_CHECK, NONE) OP(MINT_CKNULL, NORMAL) OP(MINT_LDLOCA_S, NORMAL) diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c index f3891f4b0eb9b..43b71e70cd3d5 100644 --- a/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/mono/mono/mini/interp/jiterpreter.c @@ -636,7 +636,9 @@ jiterp_get_opcode_value (InterpInst *ins, gboolean *inside_branch_block) // operations please put them in the values table header // Please keep this in sync with jiterpreter.ts:generate_wasm_body case MINT_BR: + case MINT_BR_S: case MINT_CALL_HANDLER: + case MINT_CALL_HANDLER_S: // Detect backwards branches if (ins->info.target_bb->il_offset <= ins->il_offset) { if (*inside_branch_block) diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index eca8c5727665f..7edb4f53e3fb7 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -179,8 +179,11 @@ OPDEF(MINT_STIND_OFFSET_IMM_I4, "stind_off_imm.i4", 4, 0, 2, MintOpShortInt) OPDEF(MINT_STIND_OFFSET_IMM_I8, "stind_off_imm.i8", 4, 0, 2, MintOpShortInt) OPDEF(MINT_BR, "br", 3, 0, 0, MintOpBranch) +OPDEF(MINT_BR_S, "br.s", 2, 0, 0, MintOpShortBranch) OPDEF(MINT_LEAVE_CHECK, "leave.check", 3, 0, 0, MintOpBranch) +OPDEF(MINT_LEAVE_S_CHECK, "leave.s.check", 2, 0, 0, MintOpShortBranch) OPDEF(MINT_CALL_HANDLER, "call_handler", 4, 0, 0, MintOpBranch) +OPDEF(MINT_CALL_HANDLER_S, "call_handler.s", 3, 0, 0, MintOpShortBranch) OPDEF(MINT_THROW, "throw", 2, 0, 1, MintOpNoArgs) OPDEF(MINT_RETHROW, "rethrow", 2, 0, 0, MintOpUShortInt) @@ -194,6 +197,11 @@ OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 4, 0, 1, MintOpBranch) OPDEF(MINT_BRTRUE_I4, "brtrue.i4", 4, 0, 1, MintOpBranch) OPDEF(MINT_BRTRUE_I8, "brtrue.i8", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRFALSE_I4_S, "brfalse.i4.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I8_S, "brfalse.i8.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I4_S, "brtrue.i4.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I8_S, "brtrue.i8.s", 3, 0, 1, MintOpShortBranch) + OPDEF(MINT_BEQ_I4, "beq.i4", 5, 0, 2, MintOpBranch) OPDEF(MINT_BEQ_I8, "beq.i8", 5, 0, 2, MintOpBranch) OPDEF(MINT_BEQ_R4, "beq.r4", 5, 0, 2, MintOpBranch) @@ -236,54 +244,96 @@ OPDEF(MINT_BLT_UN_I8, "blt.un.i8", 5, 0, 2, MintOpBranch) OPDEF(MINT_BLT_UN_R4, "blt.un.r4", 5, 0, 2, MintOpBranch) OPDEF(MINT_BLT_UN_R8, "blt.un.r8", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BRFALSE_I4_SP, "brfalse.i4.sp", 4, 0, 1, MintOpBranch) -OPDEF(MINT_BRFALSE_I8_SP, "brfalse.i8.sp", 4, 0, 1, MintOpBranch) -OPDEF(MINT_BRTRUE_I4_SP, "brtrue.i4.sp", 4, 0, 1, MintOpBranch) -OPDEF(MINT_BRTRUE_I8_SP, "brtrue.i8.sp", 4, 0, 1, MintOpBranch) - -OPDEF(MINT_BEQ_I4_SP, "beq.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BEQ_I8_SP, "beq.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGE_I4_SP, "bge.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGE_I8_SP, "bge.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGT_I4_SP, "bgt.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGT_I8_SP, "bgt.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLT_I4_SP, "blt.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLT_I8_SP, "blt.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLE_I4_SP, "ble.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLE_I8_SP, "ble.i8.sp", 5, 0, 2, MintOpBranch) - -OPDEF(MINT_BNE_UN_I4_SP, "bne.un.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BNE_UN_I8_SP, "bne.un.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGE_UN_I4_SP, "bge.un.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGE_UN_I8_SP, "bge.un.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGT_UN_I4_SP, "bgt.un.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BGT_UN_I8_SP, "bgt.un.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLE_UN_I4_SP, "ble.un.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLE_UN_I8_SP, "ble.un.i8.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLT_UN_I4_SP, "blt.un.i4.sp", 5, 0, 2, MintOpBranch) -OPDEF(MINT_BLT_UN_I8_SP, "blt.un.i8.sp", 5, 0, 2, MintOpBranch) - -OPDEF(MINT_BEQ_I4_IMM_SP, "beq.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BEQ_I8_IMM_SP, "beq.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGE_I4_IMM_SP, "bge.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGE_I8_IMM_SP, "bge.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGT_I4_IMM_SP, "bgt.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGT_I8_IMM_SP, "bgt.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLT_I4_IMM_SP, "blt.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLT_I8_IMM_SP, "blt.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLE_I4_IMM_SP, "ble.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLE_I8_IMM_SP, "ble.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) - -OPDEF(MINT_BNE_UN_I4_IMM_SP, "bne.un.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BNE_UN_I8_IMM_SP, "bne.un.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGE_UN_I4_IMM_SP, "bge.un.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGE_UN_I8_IMM_SP, "bge.un.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGT_UN_I4_IMM_SP, "bgt.un.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BGT_UN_I8_IMM_SP, "bgt.un.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLE_UN_I4_IMM_SP, "ble.un.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLE_UN_I8_IMM_SP, "ble.un.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLT_UN_I4_IMM_SP, "blt.un.i4.imm.sp", 5, 0, 1, MintOpShortAndBranch) -OPDEF(MINT_BLT_UN_I8_IMM_SP, "blt.un.i8.imm.sp", 5, 0, 1, MintOpShortAndBranch) +OPDEF(MINT_BEQ_I4_S, "beq.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_I8_S, "beq.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_R4_S, "beq.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_R8_S, "beq.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I4_S, "bge.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I8_S, "bge.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_R4_S, "bge.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_R8_S, "bge.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I4_S, "bgt.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I8_S, "bgt.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_R4_S, "bgt.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_R8_S, "bgt.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I4_S, "blt.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I8_S, "blt.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_R4_S, "blt.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_R8_S, "blt.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I4_S, "ble.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I8_S, "ble.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_R4_S, "ble.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_R8_S, "ble.r8.s", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BNE_UN_I4_S, "bne.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_I8_S, "bne.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_R4_S, "bne.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_R8_S, "bne.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I4_S, "bge.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I8_S, "bge.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_R4_S, "bge.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_R8_S, "bge.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I4_S, "bgt.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I8_S, "bgt.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_R4_S, "bgt.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_R8_S, "bgt.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I4_S, "ble.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I8_S, "ble.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_R4_S, "ble.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_R8_S, "ble.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I4_S, "blt.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_R4_S, "blt.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BRFALSE_I4_SP, "brfalse.i4.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I8_SP, "brfalse.i8.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I4_SP, "brtrue.i4.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I8_SP, "brtrue.i8.sp", 3, 0, 1, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4_SP, "beq.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_I8_SP, "beq.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I4_SP, "bge.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I8_SP, "bge.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I4_SP, "bgt.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I8_SP, "bgt.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I4_SP, "blt.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I8_SP, "blt.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I4_SP, "ble.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I8_SP, "ble.i8.sp", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BNE_UN_I4_SP, "bne.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_I8_SP, "bne.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I4_SP, "bge.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I8_SP, "bge.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I4_SP, "bgt.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I8_SP, "bgt.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I4_SP, "ble.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I8_SP, "ble.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I4_SP, "blt.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I8_SP, "blt.un.i8.sp", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4_IMM_SP, "beq.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BEQ_I8_IMM_SP, "beq.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_I4_IMM_SP, "bge.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_I8_IMM_SP, "bge.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_I4_IMM_SP, "bgt.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_I8_IMM_SP, "bgt.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_I4_IMM_SP, "blt.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_I8_IMM_SP, "blt.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_I4_IMM_SP, "ble.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_I8_IMM_SP, "ble.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) + +OPDEF(MINT_BNE_UN_I4_IMM_SP, "bne.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BNE_UN_I8_IMM_SP, "bne.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_UN_I4_IMM_SP, "bge.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_UN_I8_IMM_SP, "bge.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_UN_I4_IMM_SP, "bgt.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_UN_I8_IMM_SP, "bgt.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_UN_I4_IMM_SP, "ble.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_UN_I8_IMM_SP, "ble.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_UN_I4_IMM_SP, "blt.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_UN_I8_IMM_SP, "blt.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) OPDEF(MINT_SWITCH, "switch", 0, 0, 1, MintOpSwitch) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index e289e60197cd6..5acc555b3a4ee 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -19,6 +19,7 @@ typedef enum MintOpFloat, MintOpDouble, MintOpBranch, + MintOpShortBranch, MintOpSwitch, MintOpMethodToken, MintOpFieldToken, @@ -27,7 +28,7 @@ typedef enum MintOpTwoShorts, MintOpTwoInts, MintOpShortAndInt, - MintOpShortAndBranch, + MintOpShortAndShortBranch, MintOpPair2, MintOpPair3, MintOpPair4 @@ -211,10 +212,10 @@ typedef enum { #define MINT_IS_NOP(op) ((op) == MINT_NOP || (op) == MINT_DEF || (op) == MINT_DEF_ARG || (op) == MINT_DUMMY_USE || (op) == MINT_IL_SEQ_POINT) #define MINT_IS_EMIT_NOP(op) ((op) == MINT_NOP || (op) == MINT_DEF || (op) == MINT_DEF_ARG || (op) == MINT_DEF_TIER_VAR || (op) == MINT_DUMMY_USE) #define MINT_IS_MOV(op) ((op) >= MINT_MOV_I4_I1 && (op) <= MINT_MOV_VT) -#define MINT_IS_UNCONDITIONAL_BRANCH(op) ((op) >= MINT_BR && (op) <= MINT_CALL_HANDLER) -#define MINT_IS_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BLT_UN_R8) -#define MINT_IS_UNOP_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BRTRUE_I8) -#define MINT_IS_BINOP_CONDITIONAL_BRANCH(op) ((op) >= MINT_BEQ_I4 && (op) <= MINT_BLT_UN_R8) +#define MINT_IS_UNCONDITIONAL_BRANCH(op) ((op) >= MINT_BR && (op) <= MINT_CALL_HANDLER_S) +#define MINT_IS_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BLT_UN_R8_S) +#define MINT_IS_UNOP_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BRTRUE_I8_S) +#define MINT_IS_BINOP_CONDITIONAL_BRANCH(op) ((op) >= MINT_BEQ_I4 && (op) <= MINT_BLT_UN_R8_S) #define MINT_IS_COMPARE(op) ((op) >= MINT_CEQ_I4 && (op) <= MINT_CLT_UN_R8) #define MINT_IS_SUPER_BRANCH(op) ((op) >= MINT_BRFALSE_I4_SP && (op) <= MINT_BLT_UN_I8_IMM_SP) #define MINT_IS_CALL(op) ((op) >= MINT_CALL && (op) <= MINT_JIT_CALL) diff --git a/src/mono/mono/mini/interp/transform-opt.c b/src/mono/mono/mini/interp/transform-opt.c index 7b74e4ac5485e..b259e116c1440 100644 --- a/src/mono/mono/mini/interp/transform-opt.c +++ b/src/mono/mono/mini/interp/transform-opt.c @@ -3387,12 +3387,15 @@ can_propagate_var_def (TransformData *td, int var, InterpLivenessPosition cur_li static void interp_super_instructions (TransformData *td) { + interp_compute_native_offset_estimates (td, FALSE); + // Add some actual super instructions for (int bb_dfs_index = 0; bb_dfs_index < td->bblocks_count_eh; bb_dfs_index++) { InterpBasicBlock *bb = td->bblocks [bb_dfs_index]; // Set cbb since we do some instruction inserting below td->cbb = bb; + int noe = bb->native_offset_estimate; InterpLivenessPosition current_liveness; current_liveness.bb_dfs_index = bb->dfs_index; current_liveness.ins_index = 0; @@ -3717,7 +3720,7 @@ interp_super_instructions (TransformData *td) interp_clear_ins (def); td->var_values [obj_sreg].ref_count--; } - } else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (opcode)) { + } else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (opcode) && interp_is_short_offset (noe, ins->info.target_bb->native_offset_estimate)) { gint32 imm; int imm_mt; int sreg_imm = ins->sregs [1]; @@ -3754,7 +3757,7 @@ interp_super_instructions (TransformData *td) } } } - } else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (opcode)) { + } else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (opcode) && interp_is_short_offset (noe, ins->info.target_bb->native_offset_estimate)) { if (opcode == MINT_BRFALSE_I4 || opcode == MINT_BRTRUE_I4) { gboolean negate = opcode == MINT_BRFALSE_I4; int cond_sreg = ins->sregs [0]; @@ -3864,6 +3867,7 @@ interp_super_instructions (TransformData *td) } } } + noe += interp_get_ins_length (ins); } } } diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index a08933678de5b..1af7c2d514b23 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1424,6 +1424,15 @@ interp_dump_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, i g_string_append_printf (str, " %g", * (double *)&tmp); break; } + case MintOpShortBranch: + if (ins) { + /* the target IL is already embedded in the instruction */ + g_string_append_printf (str, " BB%d", ins->info.target_bb->index); + } else { + target = ins_offset + *(gint16*)data; + g_string_append_printf (str, " IR_%04x", target); + } + break; case MintOpBranch: if (ins) { g_string_append_printf (str, " BB%d", ins->info.target_bb->index); @@ -1450,12 +1459,12 @@ interp_dump_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, i g_string_append_printf (str, ")"); break; } - case MintOpShortAndBranch: + case MintOpShortAndShortBranch: if (ins) { /* the target IL is already embedded in the instruction */ g_string_append_printf (str, " %u, BB%d", *(guint16*)data, ins->info.target_bb->index); } else { - target = ins_offset + (gint32)READ32 (data + 1); + target = ins_offset + *(gint16*)(data + 1); g_string_append_printf (str, " %u, IR_%04x", *(guint16*)data, target); } break; @@ -8652,6 +8661,10 @@ handle_relocations (TransformData *td) int offset = reloc->target_bb->native_offset - reloc->offset; switch (reloc->type) { + case RELOC_SHORT_BRANCH: + g_assert (td->new_code [reloc->offset + reloc->skip + 1] == 0xdead); + td->new_code [reloc->offset + reloc->skip + 1] = GINT_TO_UINT16 (offset); + break; case RELOC_LONG_BRANCH: { guint16 *v = (guint16 *)&offset; g_assert (td->new_code [reloc->offset + reloc->skip + 1] == 0xdead); @@ -8738,14 +8751,18 @@ interp_foreach_ins_var (TransformData *td, InterpInst *ins, gpointer data, void } int -interp_compute_native_offset_estimates (TransformData *td) +interp_compute_native_offset_estimates (TransformData *td, gboolean final_code) { InterpBasicBlock *bb; int noe = 0; for (bb = td->entry_bb; bb != NULL; bb = bb->next_bb) { InterpInst *ins; - + // FIXME This doesn't currently hold because of bblock reordering potentially + // inserting additional instructions after the estimate is computed. + // + // if (bb->native_offset_estimate) + // g_assert (bb->native_offset_estimate >= noe); bb->native_offset_estimate = noe; if (!td->optimized && bb->patchpoint_bb) noe += 2; @@ -8765,6 +8782,19 @@ interp_compute_native_offset_estimates (TransformData *td) continue; noe += interp_get_ins_length (ins); + if (!final_code && td->optimized && + (ins->flags & INTERP_INST_FLAG_CALL) && + ins->info.call_info && + ins->info.call_info->call_args) { + // When code is optimized, for a call, the offset allocator + // might end up inserting additional moves for the arguments + int *call_args = ins->info.call_info->call_args; + while (*call_args != -1) { + noe += 4; // mono_interp_oplen [MINT_MOV_VT]; + call_args++; + } + } + if (!td->optimized) interp_foreach_ins_var (td, ins, NULL, alloc_unopt_global_local); } @@ -8777,6 +8807,39 @@ interp_compute_native_offset_estimates (TransformData *td) return noe; } +gboolean +interp_is_short_offset (int src_offset, int dest_offset) +{ + int diff = dest_offset - src_offset; + if (diff >= G_MININT16 && diff <= G_MAXINT16) + return TRUE; + return FALSE; +} + +static int +get_short_brop (int opcode) +{ + if (MINT_IS_UNCONDITIONAL_BRANCH (opcode)) { + if (opcode == MINT_BR) + return MINT_BR_S; + else if (opcode == MINT_LEAVE_CHECK) + return MINT_LEAVE_S_CHECK; + else if (opcode == MINT_CALL_HANDLER) + return MINT_CALL_HANDLER_S; + else + return opcode; + } + + if (opcode >= MINT_BRFALSE_I4 && opcode <= MINT_BRTRUE_I8) + return opcode + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4; + + if (opcode >= MINT_BEQ_I4 && opcode <= MINT_BLT_UN_R8) + return opcode + MINT_BEQ_I4_S - MINT_BEQ_I4; + + // Already short branch + return opcode; +} + static void interp_mark_ref_slots_for_vt (TransformData *td, int base_offset, MonoClass *klass) { @@ -8932,20 +8995,45 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in if (ins->info.target_bb->native_offset >= 0) { int offset = ins->info.target_bb->native_offset - br_offset; - WRITE32 (ip, &offset); + // Backwards branch. We can already patch it. + if (interp_is_short_offset (br_offset, ins->info.target_bb->native_offset)) { + // Replace the long opcode we added at the start + *start_ip = GINT_TO_OPCODE (get_short_brop (opcode)); + *ip++ = GINT_TO_UINT16 (ins->info.target_bb->native_offset - br_offset); + } else { + WRITE32 (ip, &offset); + } } else if (opcode == MINT_BR && ins->info.target_bb == td->cbb->next_bb) { // Ignore branch to the next basic block. Revert the added MINT_BR. ip--; } else { + // If the estimate offset is short, then surely the real offset is short + // otherwise we conservatively have to use long branch opcodes + int cur_estimation_error = td->cbb->native_offset_estimate - td->cbb->native_offset; + int target_bb_estimated_offset = ins->info.target_bb->native_offset_estimate - cur_estimation_error; + gboolean is_short = interp_is_short_offset (br_offset, target_bb_estimated_offset); + if (is_short) + *start_ip = GINT_TO_OPCODE (get_short_brop (opcode)); + else if (MINT_IS_SUPER_BRANCH (opcode)) { + g_printf ( + "long superbranch detected with opcode %d (%s) in method %s.%s\n", + opcode, mono_interp_opname (opcode), + m_class_get_name (td->method->klass), td->method->name + ); + // FIXME missing handling for long branch + g_assert (FALSE); + } + // We don't know the in_offset of the target, add a reloc Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc)); - reloc->type = RELOC_LONG_BRANCH; + reloc->type = is_short ? RELOC_SHORT_BRANCH : RELOC_LONG_BRANCH; reloc->skip = mono_interp_op_sregs [opcode] + has_imm; reloc->offset = br_offset; reloc->target_bb = ins->info.target_bb; g_ptr_array_add (td->relocs, reloc); *ip++ = 0xdead; - *ip++ = 0xbeef; + if (!is_short) + *ip++ = 0xbeef; } if (opcode == MINT_CALL_HANDLER) *ip++ = ins->data [2]; @@ -9145,7 +9233,9 @@ generate_compacted_code (InterpMethod *rtm, TransformData *td) td->relocs = g_ptr_array_new (); InterpBasicBlock *bb; - size = interp_compute_native_offset_estimates (td); + // This iteration could be avoided at the cost of less precise size result, following + // super instruction pass + size = interp_compute_native_offset_estimates (td, TRUE); // Generate the compacted stream of instructions td->new_code = ip = (guint16*)imethod_alloc0 (td, size * sizeof (guint16)); diff --git a/src/mono/mono/mini/interp/transform.h b/src/mono/mono/mini/interp/transform.h index 9432eebf39614..0379cf1682f6a 100644 --- a/src/mono/mono/mini/interp/transform.h +++ b/src/mono/mono/mini/interp/transform.h @@ -182,6 +182,7 @@ struct _InterpCallInfo { }; typedef enum { + RELOC_SHORT_BRANCH, RELOC_LONG_BRANCH, RELOC_SWITCH } RelocType; @@ -521,7 +522,7 @@ void interp_link_bblocks (TransformData *td, InterpBasicBlock *from, InterpBasicBlock *to); int -interp_compute_native_offset_estimates (TransformData *td); +interp_compute_native_offset_estimates (TransformData *td, gboolean final_code); void interp_optimize_code (TransformData *td);