internal static void EmitMethod(IReadOnlyList <MsilInstruction> source, LoggingIlGenerator target) { var instructions = source.ToArray(); var offsets = new int[instructions.Length]; // Calc worst case offsets { var j = 0; for (var i = 0; i < instructions.Length; i++) { offsets[i] = j; j += instructions[i].MaxBytes; } } // Perform label markup var targets = new Dictionary <MsilLabel, int>(); for (var i = 0; i < instructions.Length; i++) { foreach (var label in instructions[i].Labels) { if (targets.TryGetValue(label, out var other)) { _log.Warn($"Label {label} is applied to ({i}: {instructions[i]}) and ({other}: {instructions[other]})"); } targets[label] = i; } } // Simplify branch instructions for (var i = 0; i < instructions.Length; i++) { var existing = instructions[i]; if (existing.Operand is MsilOperandBrTarget brOperand && _longToShortBranch.TryGetValue(existing.OpCode, out var shortOpcode)) { var targetIndex = targets[brOperand.Target]; var delta = offsets[targetIndex] - offsets[i]; if (sbyte.MinValue < delta && delta < sbyte.MaxValue) { instructions[i] = instructions[i].CopyWith(shortOpcode); } } } for (var i = 0; i < instructions.Length; i++) { MsilInstruction il = instructions[i]; foreach (var tro in il.TryCatchOperations) { switch (tro.Type) { case MsilTryCatchOperationType.BeginExceptionBlock: target.BeginExceptionBlock(); break; case MsilTryCatchOperationType.BeginClauseBlock: target.BeginCatchBlock(tro.CatchType); break; case MsilTryCatchOperationType.BeginFaultBlock: target.BeginFaultBlock(); break; case MsilTryCatchOperationType.BeginFinallyBlock: target.BeginFinallyBlock(); break; case MsilTryCatchOperationType.EndExceptionBlock: target.EndExceptionBlock(); break; default: throw new ArgumentOutOfRangeException(); } } foreach (MsilLabel label in il.Labels) { target.MarkLabel(label.LabelFor(target)); } MsilInstruction ilNext = i < instructions.Length - 1 ? instructions[i + 1] : null; // Leave opcodes emitted by these: if (il.OpCode == OpCodes.Endfilter && ilNext != null && ilNext.TryCatchOperations.Any(x => x.Type == MsilTryCatchOperationType.BeginClauseBlock)) { continue; } if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) && ilNext != null && ilNext.TryCatchOperations.Any(x => x.Type == MsilTryCatchOperationType.EndExceptionBlock || x.Type == MsilTryCatchOperationType.BeginClauseBlock || x.Type == MsilTryCatchOperationType.BeginFaultBlock || x.Type == MsilTryCatchOperationType.BeginFinallyBlock)) { continue; } if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S || il.OpCode == OpCodes.Endfinally) && ilNext != null && ilNext.TryCatchOperations.Any(x => x.Type == MsilTryCatchOperationType.EndExceptionBlock)) { continue; } if (il.OpCode == OpCodes.Endfinally && ilNext != null && ilNext.TryCatchOperations.Any(x => x.Type == MsilTryCatchOperationType.EndExceptionBlock)) { continue; } if (il.Operand != null) { il.Operand.Emit(target); } else { target.Emit(il.OpCode); } } }
internal static void EmitMethod(IReadOnlyList <MsilInstruction> instructions, LoggingIlGenerator target) { for (var i = 0; i < instructions.Count; i++) { MsilInstruction il = instructions[i]; if (il.TryCatchOperation != null) { switch (il.TryCatchOperation.Type) { case MsilTryCatchOperationType.BeginExceptionBlock: target.BeginExceptionBlock(); break; case MsilTryCatchOperationType.BeginClauseBlock: target.BeginCatchBlock(il.TryCatchOperation.CatchType); break; case MsilTryCatchOperationType.BeginFaultBlock: target.BeginFaultBlock(); break; case MsilTryCatchOperationType.BeginFinallyBlock: target.BeginFinallyBlock(); break; case MsilTryCatchOperationType.EndExceptionBlock: target.EndExceptionBlock(); break; default: throw new ArgumentOutOfRangeException(); } } foreach (MsilLabel label in il.Labels) { target.MarkLabel(label.LabelFor(target)); } MsilInstruction ilNext = i < instructions.Count - 1 ? instructions[i + 1] : null; // Leave opcodes emitted by these: if (il.OpCode == OpCodes.Endfilter && ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginClauseBlock) { continue; } if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) && (ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock || ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginClauseBlock || ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFaultBlock || ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFinallyBlock)) { continue; } if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S || il.OpCode == OpCodes.Endfinally) && ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock) { continue; } if (il.Operand != null) { il.Operand.Emit(target); } else { target.Emit(il.OpCode); } } }