ReflectedMethodInfo allows non-public type names.
MsilInstructionExtensions to make life easier
This commit is contained in:
@@ -12,6 +12,6 @@
|
|||||||
<rules>
|
<rules>
|
||||||
<logger name="*" minlevel="Info" writeTo="main, console" />
|
<logger name="*" minlevel="Info" writeTo="main, console" />
|
||||||
<logger name="Chat" minlevel="Info" writeTo="chat" />
|
<logger name="Chat" minlevel="Info" writeTo="chat" />
|
||||||
<logger name="Torch.Managers.PatchManager.*" minlevel="Trace" writeTo="patch"/>
|
<!--<logger name="Torch.Managers.PatchManager.*" minlevel="Trace" writeTo="patch"/>-->
|
||||||
</rules>
|
</rules>
|
||||||
</nlog>
|
</nlog>
|
@@ -7,6 +7,7 @@ using System.Reflection.Emit;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
using Torch.Managers.PatchManager.Transpile;
|
using Torch.Managers.PatchManager.Transpile;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
target.EmitComment("Prefixes End");
|
target.EmitComment("Prefixes End");
|
||||||
|
|
||||||
target.EmitComment("Original Begin");
|
target.EmitComment("Original Begin");
|
||||||
MethodTranspiler.Transpile(_method, Transpilers, target, labelAfterOriginalContent);
|
MethodTranspiler.Transpile(_method, (type) => new MsilLocal(target.DeclareLocal(type)), Transpilers, target, labelAfterOriginalContent);
|
||||||
target.EmitComment("Original End");
|
target.EmitComment("Original End");
|
||||||
|
|
||||||
target.MarkLabel(labelAfterOriginalContent);
|
target.MarkLabel(labelAfterOriginalContent);
|
||||||
|
49
Torch/Managers/PatchManager/MSIL/MsilArgument.cs
Normal file
49
Torch/Managers/PatchManager/MSIL/MsilArgument.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.Managers.PatchManager.MSIL
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents metadata about a method's parameter
|
||||||
|
/// </summary>
|
||||||
|
public class MsilArgument
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The positon of this argument. Note, if the method is static, index 0 is the instance.
|
||||||
|
/// </summary>
|
||||||
|
public int Position { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of this parameter, or null if unknown.
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of this parameter, or null if unknown.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
internal MsilArgument(ParameterInfo local)
|
||||||
|
{
|
||||||
|
Position = (((MethodBase)local.Member).IsStatic ? 0 : 1) + local.Position;
|
||||||
|
Type = local.ParameterType;
|
||||||
|
Name = local.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an empty argument reference with the given position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">The argument's position</param>
|
||||||
|
public MsilArgument(int position)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Type = null;
|
||||||
|
Name = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -67,7 +67,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
if (OpCode.Name.IndexOf("loc", StringComparison.OrdinalIgnoreCase) != -1)
|
if (OpCode.Name.IndexOf("loc", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
Operand = new MsilOperandInline.MsilOperandLocal(this);
|
Operand = new MsilOperandInline.MsilOperandLocal(this);
|
||||||
else
|
else
|
||||||
Operand = new MsilOperandInline.MsilOperandParameter(this);
|
Operand = new MsilOperandInline.MsilOperandArgument(this);
|
||||||
break;
|
break;
|
||||||
case OperandType.ShortInlineI:
|
case OperandType.ShortInlineI:
|
||||||
Operand = OpCode == OpCodes.Ldc_I4_S
|
Operand = OpCode == OpCodes.Ldc_I4_S
|
||||||
@@ -193,66 +193,6 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
private static Func<OpCode, int> _stackChange;
|
private static Func<OpCode, int> _stackChange;
|
||||||
#pragma warning restore 169
|
#pragma warning restore 169
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an instruction that represents the inverse of this load or store instruction.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <example>
|
|
||||||
/// new MsilInstruction(OpCodes.Ldloc_0).StoreLoadInverse().OpCode == OpCodes.Stloc_0
|
|
||||||
/// </example>
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>Inverse</returns>
|
|
||||||
public MsilInstruction StoreLoadInverse()
|
|
||||||
{
|
|
||||||
if (OpCode == OpCodes.Ldloc)
|
|
||||||
return new MsilInstruction(OpCodes.Stloc).InlineValue(
|
|
||||||
((MsilOperandInline<LocalVariableInfo>)Operand).Value);
|
|
||||||
if (OpCode == OpCodes.Ldloc_S)
|
|
||||||
return new MsilInstruction(OpCodes.Stloc_S).InlineValue(
|
|
||||||
((MsilOperandInline<LocalVariableInfo>)Operand).Value);
|
|
||||||
if (OpCode == OpCodes.Ldloc_0)
|
|
||||||
return new MsilInstruction(OpCodes.Stloc_0);
|
|
||||||
if (OpCode == OpCodes.Ldloc_1)
|
|
||||||
return new MsilInstruction(OpCodes.Stloc_1);
|
|
||||||
if (OpCode == OpCodes.Ldloc_2)
|
|
||||||
return new MsilInstruction(OpCodes.Stloc_2);
|
|
||||||
if (OpCode == OpCodes.Ldloc_3)
|
|
||||||
return new MsilInstruction(OpCodes.Stloc_3);
|
|
||||||
|
|
||||||
if (OpCode == OpCodes.Stloc)
|
|
||||||
return new MsilInstruction(OpCodes.Ldloc).InlineValue(
|
|
||||||
((MsilOperandInline<LocalVariableInfo>)Operand).Value);
|
|
||||||
if (OpCode == OpCodes.Stloc_S)
|
|
||||||
return new MsilInstruction(OpCodes.Ldloc_S).InlineValue(
|
|
||||||
((MsilOperandInline<LocalVariableInfo>)Operand).Value);
|
|
||||||
if (OpCode == OpCodes.Stloc_0)
|
|
||||||
return new MsilInstruction(OpCodes.Ldloc_0);
|
|
||||||
if (OpCode == OpCodes.Stloc_1)
|
|
||||||
return new MsilInstruction(OpCodes.Ldloc_1);
|
|
||||||
if (OpCode == OpCodes.Stloc_2)
|
|
||||||
return new MsilInstruction(OpCodes.Ldloc_2);
|
|
||||||
if (OpCode == OpCodes.Stloc_3)
|
|
||||||
return new MsilInstruction(OpCodes.Ldloc_3);
|
|
||||||
|
|
||||||
if (OpCode == OpCodes.Ldarg)
|
|
||||||
return new MsilInstruction(OpCodes.Starg).InlineValue(
|
|
||||||
((MsilOperandInline<ParameterInfo>)Operand).Value);
|
|
||||||
if (OpCode == OpCodes.Ldarg_S)
|
|
||||||
return new MsilInstruction(OpCodes.Starg_S).InlineValue(
|
|
||||||
((MsilOperandInline<ParameterInfo>)Operand).Value);
|
|
||||||
// TODO Ldarg_0 etc
|
|
||||||
|
|
||||||
if (OpCode == OpCodes.Starg)
|
|
||||||
return new MsilInstruction(OpCodes.Ldarg).InlineValue(
|
|
||||||
((MsilOperandInline<ParameterInfo>)Operand).Value);
|
|
||||||
if (OpCode == OpCodes.Starg_S)
|
|
||||||
return new MsilInstruction(OpCodes.Ldarg_S).InlineValue(
|
|
||||||
((MsilOperandInline<ParameterInfo>)Operand).Value);
|
|
||||||
|
|
||||||
throw new ArgumentException($"Can't invert the instruction {this}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Estimates the stack delta for this instruction.
|
/// Estimates the stack delta for this instruction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
202
Torch/Managers/PatchManager/MSIL/MsilInstructionExtensions.cs
Normal file
202
Torch/Managers/PatchManager/MSIL/MsilInstructionExtensions.cs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.Managers.PatchManager.MSIL
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Various methods to make composing MSIL easier
|
||||||
|
/// </summary>
|
||||||
|
public static class MsilInstructionExtensions
|
||||||
|
{
|
||||||
|
#region Local Utils
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction a local load-by-value instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsLocalLoad(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
return me.OpCode == OpCodes.Ldloc || me.OpCode == OpCodes.Ldloc_S || me.OpCode == OpCodes.Ldloc_0 ||
|
||||||
|
me.OpCode == OpCodes.Ldloc_1 || me.OpCode == OpCodes.Ldloc_2 || me.OpCode == OpCodes.Ldloc_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction a local load-by-reference instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsLocalLoadByRef(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
return me.OpCode == OpCodes.Ldloca || me.OpCode == OpCodes.Ldloca_S;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction a local store instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsLocalStore(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
return me.OpCode == OpCodes.Stloc || me.OpCode == OpCodes.Stloc_S || me.OpCode == OpCodes.Stloc_0 ||
|
||||||
|
me.OpCode == OpCodes.Stloc_1 || me.OpCode == OpCodes.Stloc_2 || me.OpCode == OpCodes.Stloc_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For a local referencing opcode, get the local it is referencing.
|
||||||
|
/// </summary>
|
||||||
|
public static MsilLocal GetReferencedLocal(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
if (me.Operand is MsilOperandInline.MsilOperandLocal mol)
|
||||||
|
return mol.Value;
|
||||||
|
if (me.OpCode == OpCodes.Stloc_0 || me.OpCode == OpCodes.Ldloc_0)
|
||||||
|
return new MsilLocal(0);
|
||||||
|
if (me.OpCode == OpCodes.Stloc_1 || me.OpCode == OpCodes.Ldloc_1)
|
||||||
|
return new MsilLocal(1);
|
||||||
|
if (me.OpCode == OpCodes.Stloc_2 || me.OpCode == OpCodes.Ldloc_2)
|
||||||
|
return new MsilLocal(2);
|
||||||
|
if (me.OpCode == OpCodes.Stloc_3 || me.OpCode == OpCodes.Ldloc_3)
|
||||||
|
return new MsilLocal(3);
|
||||||
|
throw new ArgumentException($"Can't get referenced local in instruction {me}");
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction representing a load-by-value from the given local.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="local">Local to load</param>
|
||||||
|
/// <returns>Loading instruction</returns>
|
||||||
|
public static MsilInstruction AsValueLoad(this MsilLocal local)
|
||||||
|
{
|
||||||
|
switch (local.Index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return new MsilInstruction(OpCodes.Ldloc_0);
|
||||||
|
case 1:
|
||||||
|
return new MsilInstruction(OpCodes.Ldloc_1);
|
||||||
|
case 2:
|
||||||
|
return new MsilInstruction(OpCodes.Ldloc_2);
|
||||||
|
case 3:
|
||||||
|
return new MsilInstruction(OpCodes.Ldloc_3);
|
||||||
|
default:
|
||||||
|
return new MsilInstruction(local.Index < 0xFF ? OpCodes.Ldloc_S : OpCodes.Ldloc).InlineValue(local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction representing a store-by-value to the given local.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="local">Local to write to</param>
|
||||||
|
/// <returns>Loading instruction</returns>
|
||||||
|
public static MsilInstruction AsValueStore(this MsilLocal local)
|
||||||
|
{
|
||||||
|
switch (local.Index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return new MsilInstruction(OpCodes.Stloc_0);
|
||||||
|
case 1:
|
||||||
|
return new MsilInstruction(OpCodes.Stloc_1);
|
||||||
|
case 2:
|
||||||
|
return new MsilInstruction(OpCodes.Stloc_2);
|
||||||
|
case 3:
|
||||||
|
return new MsilInstruction(OpCodes.Stloc_3);
|
||||||
|
default:
|
||||||
|
return new MsilInstruction(local.Index < 0xFF ? OpCodes.Stloc_S : OpCodes.Stloc).InlineValue(local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction representing a load-by-reference from the given local.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="local">Local to load</param>
|
||||||
|
/// <returns>Loading instruction</returns>
|
||||||
|
public static MsilInstruction AsReferenceLoad(this MsilLocal local)
|
||||||
|
{
|
||||||
|
return new MsilInstruction(local.Index < 0xFF ? OpCodes.Ldloca_S : OpCodes.Ldloca).InlineValue(local);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Argument Utils
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction an argument load-by-value instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsArgumentLoad(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
return me.OpCode == OpCodes.Ldarg || me.OpCode == OpCodes.Ldarg_S || me.OpCode == OpCodes.Ldarg_0 ||
|
||||||
|
me.OpCode == OpCodes.Ldarg_1 || me.OpCode == OpCodes.Ldarg_2 || me.OpCode == OpCodes.Ldarg_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction an argument load-by-reference instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsArgumentLoadByRef(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
return me.OpCode == OpCodes.Ldarga || me.OpCode == OpCodes.Ldarga_S;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction an argument store instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsArgumentStore(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
return me.OpCode == OpCodes.Starg || me.OpCode == OpCodes.Starg_S;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For an argument referencing opcode, get the index of the local it is referencing.
|
||||||
|
/// </summary>
|
||||||
|
public static MsilArgument GetReferencedArgument(this MsilInstruction me)
|
||||||
|
{
|
||||||
|
if (me.Operand is MsilOperandInline.MsilOperandArgument mol)
|
||||||
|
return mol.Value;
|
||||||
|
if (me.OpCode == OpCodes.Ldarg_0)
|
||||||
|
return new MsilArgument(0);
|
||||||
|
if (me.OpCode == OpCodes.Ldarg_1)
|
||||||
|
return new MsilArgument(1);
|
||||||
|
if (me.OpCode == OpCodes.Ldarg_2)
|
||||||
|
return new MsilArgument(2);
|
||||||
|
if (me.OpCode == OpCodes.Ldarg_3)
|
||||||
|
return new MsilArgument(3);
|
||||||
|
throw new ArgumentException($"Can't get referenced argument in instruction {me}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction representing a load-by-value from the given argument.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">argument to load</param>
|
||||||
|
/// <returns>Load instruction</returns>
|
||||||
|
public static MsilInstruction AsValueLoad(this MsilArgument argument)
|
||||||
|
{
|
||||||
|
switch (argument.Position)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return new MsilInstruction(OpCodes.Ldarg_0);
|
||||||
|
case 1:
|
||||||
|
return new MsilInstruction(OpCodes.Ldarg_1);
|
||||||
|
case 2:
|
||||||
|
return new MsilInstruction(OpCodes.Ldarg_2);
|
||||||
|
case 3:
|
||||||
|
return new MsilInstruction(OpCodes.Ldarg_3);
|
||||||
|
default:
|
||||||
|
return new MsilInstruction(argument.Position < 0xFF ? OpCodes.Ldarg_S : OpCodes.Ldarg).InlineValue(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction representing a store-by-value to the given argument.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">argument to write to</param>
|
||||||
|
/// <returns>Store instruction</returns>
|
||||||
|
public static MsilInstruction AsValueStore(this MsilArgument argument)
|
||||||
|
{
|
||||||
|
return new MsilInstruction(argument.Position < 0xFF ? OpCodes.Starg_S : OpCodes.Starg).InlineValue(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction representing a load-by-reference from the given argument.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">argument to load</param>
|
||||||
|
/// <returns>Reference load instruction</returns>
|
||||||
|
public static MsilInstruction AsReferenceLoad(this MsilArgument argument)
|
||||||
|
{
|
||||||
|
return new MsilInstruction(argument.Position < 0xFF ? OpCodes.Ldarga_S : OpCodes.Ldarga).InlineValue(argument);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
56
Torch/Managers/PatchManager/MSIL/MsilLocal.cs
Normal file
56
Torch/Managers/PatchManager/MSIL/MsilLocal.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.Managers.PatchManager.MSIL
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents metadata about a method's local
|
||||||
|
/// </summary>
|
||||||
|
public class MsilLocal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The index of this local.
|
||||||
|
/// </summary>
|
||||||
|
public int Index { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of this local, or null if unknown.
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of this local, or null if unknown.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
internal MsilLocal(LocalBuilder local)
|
||||||
|
{
|
||||||
|
Index = local.LocalIndex;
|
||||||
|
Type = local.LocalType;
|
||||||
|
Name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal MsilLocal(LocalVariableInfo local)
|
||||||
|
{
|
||||||
|
Index = local.LocalIndex;
|
||||||
|
Type = local.LocalType;
|
||||||
|
Name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an empty local reference with the given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The local's index</param>
|
||||||
|
public MsilLocal(int index)
|
||||||
|
{
|
||||||
|
Index = index;
|
||||||
|
Type = null;
|
||||||
|
Name = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -209,11 +209,11 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inline parameter reference
|
/// Inline argument reference
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MsilOperandParameter : MsilOperandInline<ParameterInfo>
|
public class MsilOperandArgument : MsilOperandInline<MsilArgument>
|
||||||
{
|
{
|
||||||
internal MsilOperandParameter(MsilInstruction instruction) : base(instruction)
|
internal MsilOperandArgument(MsilInstruction instruction) : base(instruction)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,20 +225,19 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
: reader.ReadUInt16();
|
: reader.ReadUInt16();
|
||||||
if (paramID == 0 && !context.Method.IsStatic)
|
if (paramID == 0 && !context.Method.IsStatic)
|
||||||
throw new ArgumentException("Haven't figured out how to ldarg with the \"this\" argument");
|
throw new ArgumentException("Haven't figured out how to ldarg with the \"this\" argument");
|
||||||
Value = context.Method.GetParameters()[paramID - (context.Method.IsStatic ? 0 : 1)];
|
Value = new MsilArgument(context.Method.GetParameters()[paramID - (context.Method.IsStatic ? 0 : 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
var methodInfo = Value.Member as MethodBase;
|
generator.Emit(Instruction.OpCode, Value.Position);
|
||||||
generator.Emit(Instruction.OpCode, Value.Position + (methodInfo != null && methodInfo.IsStatic ? 0 : 1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inline local variable reference
|
/// Inline local variable reference
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MsilOperandLocal : MsilOperandInline<LocalVariableInfo>
|
public class MsilOperandLocal : MsilOperandInline<MsilLocal>
|
||||||
{
|
{
|
||||||
internal MsilOperandLocal(MsilInstruction instruction) : base(instruction)
|
internal MsilOperandLocal(MsilInstruction instruction) : base(instruction)
|
||||||
{
|
{
|
||||||
@@ -247,15 +246,15 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value =
|
Value =
|
||||||
context.Method.GetMethodBody().LocalVariables[
|
new MsilLocal(context.Method.GetMethodBody().LocalVariables[
|
||||||
Instruction.OpCode.OperandType == OperandType.ShortInlineVar
|
Instruction.OpCode.OperandType == OperandType.ShortInlineVar
|
||||||
? reader.ReadByte()
|
? reader.ReadByte()
|
||||||
: reader.ReadUInt16()];
|
: reader.ReadUInt16()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value.LocalIndex);
|
generator.Emit(Instruction.OpCode, Value.Index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
{
|
{
|
||||||
public static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
public static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
internal static void Transpile(MethodBase baseMethod, IEnumerable<MethodInfo> transpilers, LoggingIlGenerator output, Label? retLabel)
|
internal static void Transpile(MethodBase baseMethod, Func<Type, MsilLocal> localCreator, IEnumerable<MethodInfo> transpilers, LoggingIlGenerator output, Label? retLabel)
|
||||||
{
|
{
|
||||||
var context = new MethodContext(baseMethod);
|
var context = new MethodContext(baseMethod);
|
||||||
context.Read();
|
context.Read();
|
||||||
@@ -20,8 +20,23 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
// _log.Trace(context.ToHumanMsil);
|
// _log.Trace(context.ToHumanMsil);
|
||||||
|
|
||||||
var methodContent = (IEnumerable<MsilInstruction>)context.Instructions;
|
var methodContent = (IEnumerable<MsilInstruction>)context.Instructions;
|
||||||
foreach (var transpiler in transpilers)
|
foreach (MethodInfo transpiler in transpilers)
|
||||||
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, new object[] { methodContent });
|
{
|
||||||
|
var paramList = new List<object>();
|
||||||
|
foreach (var parameter in transpiler.GetParameters())
|
||||||
|
{
|
||||||
|
if (parameter.Name.Equals("__methodBody"))
|
||||||
|
paramList.Add(baseMethod.GetMethodBody());
|
||||||
|
else if (parameter.Name.Equals("__localCreator"))
|
||||||
|
paramList.Add(localCreator);
|
||||||
|
else if (parameter.ParameterType == typeof(IEnumerable<MsilInstruction>))
|
||||||
|
paramList.Add(methodContent);
|
||||||
|
else
|
||||||
|
throw new ArgumentException(
|
||||||
|
$"Bad transpiler parameter type {parameter.ParameterType.FullName} {parameter.Name}");
|
||||||
|
}
|
||||||
|
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, paramList.ToArray());
|
||||||
|
}
|
||||||
methodContent = FixBranchAndReturn(methodContent, retLabel);
|
methodContent = FixBranchAndReturn(methodContent, retLabel);
|
||||||
foreach (var k in methodContent)
|
foreach (var k in methodContent)
|
||||||
k.Emit(output);
|
k.Emit(output);
|
||||||
|
@@ -165,7 +165,10 @@
|
|||||||
<Compile Include="Managers\PatchManager\EmitExtensions.cs" />
|
<Compile Include="Managers\PatchManager\EmitExtensions.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\ITokenResolver.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\ITokenResolver.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\MsilInstruction.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilInstruction.cs" />
|
||||||
|
<Compile Include="Managers\PatchManager\MSIL\MsilInstructionExtensions.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\MsilLabel.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilLabel.cs" />
|
||||||
|
<Compile Include="Managers\PatchManager\MSIL\MsilArgument.cs" />
|
||||||
|
<Compile Include="Managers\PatchManager\MSIL\MsilLocal.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperand.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilOperand.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperandBrTarget.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilOperandBrTarget.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperandInline.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilOperandInline.cs" />
|
||||||
|
@@ -74,6 +74,16 @@ namespace Torch.Utils
|
|||||||
/// Expected parameters of this method, or null if any parameters are accepted.
|
/// Expected parameters of this method, or null if any parameters are accepted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Type[] Parameters { get; set; } = null;
|
public Type[] Parameters { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assembly qualified names of <see cref="Parameters"/>
|
||||||
|
/// </summary>
|
||||||
|
public string[] ParameterNames
|
||||||
|
{
|
||||||
|
get => Parameters.Select(x => x.AssemblyQualifiedName).ToArray();
|
||||||
|
set => Parameters = value?.Select(x => x == null ? null : Type.GetType(x)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Expected return type of this method, or null if any return type is accepted.
|
/// Expected return type of this method, or null if any return type is accepted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Reference in New Issue
Block a user