diff --git a/Torch/Managers/PatchManager/DecoratedMethod.cs b/Torch/Managers/PatchManager/DecoratedMethod.cs index 5bbb249..e24fd04 100644 --- a/Torch/Managers/PatchManager/DecoratedMethod.cs +++ b/Torch/Managers/PatchManager/DecoratedMethod.cs @@ -197,7 +197,7 @@ namespace Torch.Managers.PatchManager lock (_log) { var instructions = context.Body.Instructions - .Select(b => new MsilInstruction(b)).ToList(); + .Select(b => b.ToMsilInstruction()).ToList(); LogTarget(PrintModeEnum.Patched, false, "========== Patched method =========="); MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), instructions, true); LogTarget(PrintModeEnum.Patched, false, gap); diff --git a/Torch/Managers/PatchManager/MSIL/InstructionExtensions.cs b/Torch/Managers/PatchManager/MSIL/InstructionExtensions.cs new file mode 100644 index 0000000..482ce46 --- /dev/null +++ b/Torch/Managers/PatchManager/MSIL/InstructionExtensions.cs @@ -0,0 +1,136 @@ +using System; +using System.Linq; +using System.Reflection; +using Mono.Cecil; +using Mono.Cecil.Cil; +using MonoMod.Utils; +using Torch.Managers.PatchManager.Transpile; +using OperandType = System.Reflection.Emit.OperandType; + +namespace Torch.Managers.PatchManager.MSIL; + +internal static class InstructionExtensions +{ + public static MsilInstruction ToMsilInstruction(this Instruction instruction) + { + static System.Reflection.Emit.Label CreateLabel(int pos) + { + var instance = Activator.CreateInstance(typeof(System.Reflection.Emit.Label), + BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null, + new object[] {pos}, null); + if (instance == null) + return default; + return (System.Reflection.Emit.Label) instance; + } + + var systemOpCode = MethodContext.OpCodeLookup[instruction.OpCode.Value]; + var msil = new MsilInstruction(systemOpCode); + if (instruction.Operand is null || instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineNone) + return msil; + + var opType = systemOpCode.OperandType; + + switch (instruction.Operand) + { + case Instruction targetInstruction when opType is OperandType.InlineBrTarget or OperandType.ShortInlineBrTarget: + msil.Operand = new MsilOperandBrTarget(msil) + { + Target = new MsilLabel(CreateLabel(targetInstruction.Offset)) + }; + break; + case FieldReference reference when opType == OperandType.InlineField: + msil.Operand = new MsilOperandInline.MsilOperandReflected(msil) + { + Value = reference.ResolveReflection() + }; + break; + case int int32 when opType is OperandType.InlineI or OperandType.ShortInlineI: + msil.Operand = new MsilOperandInline.MsilOperandInt32(msil) + { + Value = int32 + }; + break; + case long int64 when opType is OperandType.InlineI8: + msil.Operand = new MsilOperandInline.MsilOperandInt64(msil) + { + Value = int64 + }; + break; + case MethodReference methodReference when opType is OperandType.InlineMethod: + msil.Operand = new MsilOperandInline.MsilOperandReflected(msil) + { + Value = methodReference.ResolveReflection() + }; + break; + case double @double when opType is OperandType.InlineR: + msil.Operand = new MsilOperandInline.MsilOperandDouble(msil) + { + Value = @double + }; + break; + case null when opType is OperandType.InlineSig: + throw new NotSupportedException("InlineSignature is not supported by instruction converter"); + case string @string when opType == OperandType.InlineString: + msil.Operand = new MsilOperandInline.MsilOperandString(msil) + { + Value = @string + }; + break; + case Instruction[] targetInstructions when opType is OperandType.InlineSwitch: + msil.Operand = new MsilOperandSwitch(msil) + { + Labels = targetInstructions.Select(b => new MsilLabel(CreateLabel(b.Offset))).ToArray() + }; + break; + case MemberReference memberReference when opType is OperandType.InlineTok: + msil.Operand = new MsilOperandInline.MsilOperandReflected(msil) + { + Value = memberReference.ResolveReflection() + }; + break; + case TypeReference typeReference when opType is OperandType.InlineType: + msil.Operand = new MsilOperandInline.MsilOperandReflected(msil) + { + Value = typeReference.ResolveReflection() + }; + break; + case VariableDefinition variableDefinition when opType is OperandType.InlineVar or OperandType.ShortInlineVar: + if (systemOpCode.IsLocalStore() || systemOpCode.IsLocalLoad() || systemOpCode.IsLocalLoadByRef()) + msil.Operand = new MsilOperandInline.MsilOperandLocal(msil) + { + Value = new MsilLocal(variableDefinition.Index) + }; + else + msil.Operand = new MsilOperandInline.MsilOperandArgument(msil) + { + Value = new MsilArgument(variableDefinition.Index) + }; + break; + case ParameterDefinition parameterDefinition when opType is OperandType.InlineVar or OperandType.ShortInlineVar: + if (systemOpCode.IsLocalStore() || systemOpCode.IsLocalLoad() || systemOpCode.IsLocalLoadByRef()) + msil.Operand = new MsilOperandInline.MsilOperandLocal(msil) + { + Value = new MsilLocal(parameterDefinition.Index) + }; + else + msil.Operand = new MsilOperandInline.MsilOperandArgument(msil) + { + Value = new MsilArgument(parameterDefinition.Index) + }; + break; + case float @float when opType == OperandType.ShortInlineR: + msil.Operand = new MsilOperandInline.MsilOperandSingle(msil) + { + Value = @float + }; + break; +#pragma warning disable 618 + case null when opType == OperandType.InlinePhi: +#pragma warning restore 618 + default: + throw new ArgumentOutOfRangeException(nameof(instruction.Operand), instruction.Operand, "Invalid operand type"); + } + + return msil; + } +} \ No newline at end of file diff --git a/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs b/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs index af636b6..cc0af95 100644 --- a/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs +++ b/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs @@ -88,132 +88,6 @@ namespace Torch.Managers.PatchManager.MSIL throw new ArgumentOutOfRangeException(); } } - - public MsilInstruction(Instruction instruction) - { - Label CreateLabel(int pos) - { - var instance = Activator.CreateInstance(typeof(Label), - BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null, - new object[] {pos}, null); - if (instance == null) - return default; - return (Label) instance; - } - - if (!MethodContext.OpCodeLookup.TryGetValue(instruction.OpCode.Value, out var opCode)) - return; - OpCode = opCode; - - var opType = opCode.OperandType; - if (opType == OperandType.InlineNone) - { - Operand = null; - return; - } - switch (instruction.Operand) - { - case OperandType.InlineNone: - break; - case Instruction targetInstruction when opType == OperandType.InlineBrTarget || opType == OperandType.ShortInlineBrTarget: - Operand = new MsilOperandBrTarget(this) - { - Target = new MsilLabel(CreateLabel(targetInstruction.Offset)) - }; - break; - case FieldReference reference when opType == OperandType.InlineField: - Operand = new MsilOperandInline.MsilOperandReflected(this) - { - Value = reference.ResolveReflection() - }; - break; - case int int32 when opType == OperandType.InlineI || opType == OperandType.ShortInlineI: - Operand = new MsilOperandInline.MsilOperandInt32(this) - { - Value = int32 - }; - break; - case long int64 when opType == OperandType.InlineI8: - Operand = new MsilOperandInline.MsilOperandInt64(this) - { - Value = int64 - }; - break; - case MethodReference methodReference when opType == OperandType.InlineMethod: - Operand = new MsilOperandInline.MsilOperandReflected(this) - { - Value = methodReference.ResolveReflection() - }; - break; - case double @double when opType == OperandType.InlineR: - Operand = new MsilOperandInline.MsilOperandDouble(this) - { - Value = @double - }; - break; - case null when opType == OperandType.InlineSig: - throw new NotSupportedException("InlineSignature is not supported by instruction converter"); - case string @string when opType == OperandType.InlineString: - Operand = new MsilOperandInline.MsilOperandString(this) - { - Value = @string - }; - break; - case Instruction[] targetInstructions when opType == OperandType.InlineSwitch: - Operand = new MsilOperandSwitch(this) - { - Labels = targetInstructions.Select(b => new MsilLabel(CreateLabel(b.Offset))).ToArray() - }; - break; - case MemberReference memberReference when opType == OperandType.InlineTok: - Operand = new MsilOperandInline.MsilOperandReflected(this) - { - Value = memberReference.ResolveReflection() - }; - break; - case TypeReference typeReference when opType == OperandType.InlineType: - Operand = new MsilOperandInline.MsilOperandReflected(this) - { - Value = typeReference.ResolveReflection() - }; - break; - case VariableDefinition variableDefinition when opType == OperandType.InlineVar || opType == OperandType.ShortInlineVar: - if (OpCode.IsLocalStore() || OpCode.IsLocalLoad() || OpCode.IsLocalLoadByRef()) - Operand = new MsilOperandInline.MsilOperandLocal(this) - { - Value = new MsilLocal(variableDefinition.Index) - }; - else - Operand = new MsilOperandInline.MsilOperandArgument(this) - { - Value = new MsilArgument(variableDefinition.Index) - }; - break; - case ParameterDefinition parameterDefinition when opType == OperandType.InlineVar || opType == OperandType.ShortInlineVar: - if (OpCode.IsLocalStore() || OpCode.IsLocalLoad() || OpCode.IsLocalLoadByRef()) - Operand = new MsilOperandInline.MsilOperandLocal(this) - { - Value = new MsilLocal(parameterDefinition.Index) - }; - else - Operand = new MsilOperandInline.MsilOperandArgument(this) - { - Value = new MsilArgument(parameterDefinition.Index) - }; - break; - case float @float when opType == OperandType.ShortInlineR: - Operand = new MsilOperandInline.MsilOperandSingle(this) - { - Value = @float - }; - break; -#pragma warning disable 618 - case null when opType == OperandType.InlinePhi: -#pragma warning restore 618 - default: - throw new ArgumentOutOfRangeException(nameof(instruction.Operand), instruction.Operand, "Invalid operand type"); - } - } /// /// Opcode of this instruction @@ -228,7 +102,7 @@ namespace Torch.Managers.PatchManager.MSIL /// /// The operand for this instruction, or null. /// - public MsilOperand Operand { get; } + public MsilOperand Operand { get; internal set; } /// /// Labels pointing to this instruction.