Post transpilers (happen after prefix and suffix)
More debugging options More robust inline writing and reading
This commit is contained in:
@@ -29,20 +29,21 @@ namespace Torch.Managers.PatchManager
|
|||||||
|
|
||||||
internal bool HasChanged()
|
internal bool HasChanged()
|
||||||
{
|
{
|
||||||
return Prefixes.HasChanges() || Suffixes.HasChanges() || Transpilers.HasChanges();
|
return Prefixes.HasChanges() || Suffixes.HasChanges() || Transpilers.HasChanges() || PostTranspilers.HasChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Commit()
|
internal void Commit()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!Prefixes.HasChanges(true) && !Suffixes.HasChanges(true) && !Transpilers.HasChanges(true))
|
// non-greedy so they are all reset
|
||||||
|
if (!Prefixes.HasChanges(true) & !Suffixes.HasChanges(true) & !Transpilers.HasChanges(true) & !PostTranspilers.HasChanges(true))
|
||||||
return;
|
return;
|
||||||
Revert();
|
Revert();
|
||||||
|
|
||||||
if (Prefixes.Count == 0 && Suffixes.Count == 0 && Transpilers.Count == 0)
|
if (Prefixes.Count == 0 && Suffixes.Count == 0 && Transpilers.Count == 0 && PostTranspilers.Count == 0)
|
||||||
return;
|
return;
|
||||||
_log.Debug(
|
_log.Log(PrintMsil ? LogLevel.Info : LogLevel.Debug,
|
||||||
$"Begin patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
|
$"Begin patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
|
||||||
var patch = ComposePatchedMethod();
|
var patch = ComposePatchedMethod();
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
var newAddress = AssemblyMemory.GetMethodBodyStart(patch);
|
var newAddress = AssemblyMemory.GetMethodBodyStart(patch);
|
||||||
_revertData = AssemblyMemory.WriteJump(_revertAddress, newAddress);
|
_revertData = AssemblyMemory.WriteJump(_revertAddress, newAddress);
|
||||||
_pinnedPatch = GCHandle.Alloc(patch);
|
_pinnedPatch = GCHandle.Alloc(patch);
|
||||||
_log.Debug(
|
_log.Log(PrintMsil ? LogLevel.Info : LogLevel.Debug,
|
||||||
$"Done patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
|
$"Done patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
@@ -110,100 +111,119 @@ namespace Torch.Managers.PatchManager
|
|||||||
public DynamicMethod ComposePatchedMethod()
|
public DynamicMethod ComposePatchedMethod()
|
||||||
{
|
{
|
||||||
DynamicMethod method = AllocatePatchMethod();
|
DynamicMethod method = AllocatePatchMethod();
|
||||||
var generator = new LoggingIlGenerator(method.GetILGenerator());
|
var generator = new LoggingIlGenerator(method.GetILGenerator(), PrintMsil ? LogLevel.Info : LogLevel.Trace);
|
||||||
EmitPatched(generator);
|
List<MsilInstruction> il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();
|
||||||
|
if (PrintMsil)
|
||||||
|
{
|
||||||
|
lock (_log)
|
||||||
|
{
|
||||||
|
MethodTranspiler.IntegrityAnalysis(LogLevel.Info, il);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MethodTranspiler.EmitMethod(il, generator);
|
||||||
|
|
||||||
// Force it to compile
|
try
|
||||||
RuntimeMethodHandle handle = _getMethodHandle.Invoke(method);
|
{
|
||||||
object runtimeMethodInfo = _getMethodInfo.Invoke(handle);
|
// Force it to compile
|
||||||
_compileDynamicMethod.Invoke(runtimeMethodInfo);
|
RuntimeMethodHandle handle = _getMethodHandle.Invoke(method);
|
||||||
|
object runtimeMethodInfo = _getMethodInfo.Invoke(handle);
|
||||||
|
_compileDynamicMethod.Invoke(runtimeMethodInfo);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
lock (_log)
|
||||||
|
{
|
||||||
|
var ctx = new MethodContext(method);
|
||||||
|
ctx.Read();
|
||||||
|
MethodTranspiler.IntegrityAnalysis(LogLevel.Warn, ctx.Instructions);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Emit
|
#region Emit
|
||||||
private void EmitPatched(LoggingIlGenerator target)
|
private IEnumerable<MsilInstruction> EmitPatched(Func<Type, bool, MsilLocal> declareLocal)
|
||||||
{
|
{
|
||||||
var originalLocalVariables = _method.GetMethodBody().LocalVariables
|
var methodBody = _method.GetMethodBody();
|
||||||
.Select(x =>
|
Debug.Assert(methodBody != null, "Method body is null");
|
||||||
{
|
foreach (var localVar in methodBody.LocalVariables)
|
||||||
Debug.Assert(x.LocalType != null);
|
{
|
||||||
return target.DeclareLocal(x.LocalType, x.IsPinned);
|
Debug.Assert(localVar.LocalType != null);
|
||||||
}).ToArray();
|
declareLocal(localVar.LocalType, localVar.IsPinned);
|
||||||
|
}
|
||||||
|
var instructions = new List<MsilInstruction>();
|
||||||
|
var specialVariables = new Dictionary<string, MsilLocal>();
|
||||||
|
|
||||||
var specialVariables = new Dictionary<string, LocalBuilder>();
|
var labelAfterOriginalContent = new MsilLabel();
|
||||||
|
var labelSkipMethodContent = new MsilLabel();
|
||||||
Label labelAfterOriginalContent = target.DefineLabel();
|
|
||||||
Label labelSkipMethodContent = target.DefineLabel();
|
|
||||||
|
|
||||||
|
|
||||||
Type returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
|
Type returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
|
||||||
LocalBuilder resultVariable = null;
|
MsilLocal resultVariable = null;
|
||||||
if (returnType != typeof(void))
|
if (returnType != typeof(void))
|
||||||
{
|
{
|
||||||
if (Prefixes.Concat(Suffixes).SelectMany(x => x.GetParameters()).Any(x => x.Name == RESULT_PARAMETER))
|
if (Prefixes.Concat(Suffixes).SelectMany(x => x.GetParameters()).Any(x => x.Name == RESULT_PARAMETER)
|
||||||
resultVariable = target.DeclareLocal(returnType);
|
|| Prefixes.Any(x => x.ReturnType == typeof(bool)))
|
||||||
else if (Prefixes.Any(x => x.ReturnType == typeof(bool)))
|
resultVariable = declareLocal(returnType, false);
|
||||||
resultVariable = target.DeclareLocal(returnType);
|
|
||||||
}
|
}
|
||||||
resultVariable?.SetToDefault(target);
|
if (resultVariable != null)
|
||||||
LocalBuilder prefixSkippedVariable = null;
|
instructions.AddRange(resultVariable.SetToDefault());
|
||||||
|
MsilLocal prefixSkippedVariable = null;
|
||||||
if (Prefixes.Count > 0 && Suffixes.Any(x => x.GetParameters()
|
if (Prefixes.Count > 0 && Suffixes.Any(x => x.GetParameters()
|
||||||
.Any(y => y.Name.Equals(PREFIX_SKIPPED_PARAMETER))))
|
.Any(y => y.Name.Equals(PREFIX_SKIPPED_PARAMETER))))
|
||||||
{
|
{
|
||||||
prefixSkippedVariable = target.DeclareLocal(typeof(bool));
|
prefixSkippedVariable = declareLocal(typeof(bool), false);
|
||||||
specialVariables.Add(PREFIX_SKIPPED_PARAMETER, prefixSkippedVariable);
|
specialVariables.Add(PREFIX_SKIPPED_PARAMETER, prefixSkippedVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultVariable != null)
|
if (resultVariable != null)
|
||||||
specialVariables.Add(RESULT_PARAMETER, resultVariable);
|
specialVariables.Add(RESULT_PARAMETER, resultVariable);
|
||||||
|
|
||||||
target.EmitComment("Prefixes Begin");
|
|
||||||
foreach (MethodInfo prefix in Prefixes)
|
foreach (MethodInfo prefix in Prefixes)
|
||||||
{
|
{
|
||||||
EmitMonkeyCall(target, prefix, specialVariables);
|
instructions.AddRange(EmitMonkeyCall(prefix, specialVariables));
|
||||||
if (prefix.ReturnType == typeof(bool))
|
if (prefix.ReturnType == typeof(bool))
|
||||||
target.Emit(OpCodes.Brfalse, labelSkipMethodContent);
|
instructions.Add(new MsilInstruction(OpCodes.Brfalse).InlineTarget(labelSkipMethodContent));
|
||||||
else if (prefix.ReturnType != typeof(void))
|
else if (prefix.ReturnType != typeof(void))
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
$"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
|
$"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
|
||||||
}
|
}
|
||||||
target.EmitComment("Prefixes End");
|
instructions.AddRange(MethodTranspiler.Transpile(_method, (x) => declareLocal(x, false), Transpilers, labelAfterOriginalContent));
|
||||||
|
|
||||||
target.EmitComment("Original Begin");
|
instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(labelAfterOriginalContent));
|
||||||
MethodTranspiler.Transpile(_method, (type) => new MsilLocal(target.DeclareLocal(type)), Transpilers, target, labelAfterOriginalContent, PrintMsil);
|
|
||||||
target.EmitComment("Original End");
|
|
||||||
|
|
||||||
target.MarkLabel(labelAfterOriginalContent);
|
|
||||||
if (resultVariable != null)
|
if (resultVariable != null)
|
||||||
target.Emit(OpCodes.Stloc, resultVariable);
|
instructions.Add(new MsilInstruction(OpCodes.Stloc).InlineValue(resultVariable));
|
||||||
Label notSkip = target.DefineLabel();
|
var notSkip = new MsilLabel();
|
||||||
target.Emit(OpCodes.Br, notSkip);
|
instructions.Add(new MsilInstruction(OpCodes.Br).InlineTarget(notSkip));
|
||||||
target.MarkLabel(labelSkipMethodContent);
|
instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(labelSkipMethodContent));
|
||||||
if (prefixSkippedVariable != null)
|
if (prefixSkippedVariable != null)
|
||||||
{
|
{
|
||||||
target.Emit(OpCodes.Ldc_I4_1);
|
instructions.Add(new MsilInstruction(OpCodes.Ldc_I4_1));
|
||||||
target.Emit(OpCodes.Stloc, prefixSkippedVariable);
|
instructions.Add(new MsilInstruction(OpCodes.Stloc).InlineValue(prefixSkippedVariable));
|
||||||
}
|
}
|
||||||
target.MarkLabel(notSkip);
|
instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(notSkip));
|
||||||
|
|
||||||
target.EmitComment("Suffixes Begin");
|
|
||||||
foreach (MethodInfo suffix in Suffixes)
|
foreach (MethodInfo suffix in Suffixes)
|
||||||
{
|
{
|
||||||
EmitMonkeyCall(target, suffix, specialVariables);
|
instructions.AddRange(EmitMonkeyCall(suffix, specialVariables));
|
||||||
if (suffix.ReturnType != typeof(void))
|
if (suffix.ReturnType != typeof(void))
|
||||||
throw new Exception($"Suffixes must return void. {suffix.DeclaringType?.FullName}.{suffix.Name} returns {suffix.ReturnType}");
|
throw new Exception($"Suffixes must return void. {suffix.DeclaringType?.FullName}.{suffix.Name} returns {suffix.ReturnType}");
|
||||||
}
|
}
|
||||||
target.EmitComment("Suffixes End");
|
|
||||||
if (resultVariable != null)
|
if (resultVariable != null)
|
||||||
target.Emit(OpCodes.Ldloc, resultVariable);
|
instructions.Add(new MsilInstruction(OpCodes.Ldloc).InlineValue(resultVariable));
|
||||||
target.Emit(OpCodes.Ret);
|
instructions.Add(new MsilInstruction(OpCodes.Ret));
|
||||||
|
|
||||||
|
var result = MethodTranspiler.Transpile(_method, instructions, (x) => declareLocal(x, false), PostTranspilers, null).ToList();
|
||||||
|
if (result.Last().OpCode != OpCodes.Ret)
|
||||||
|
result.Add(new MsilInstruction(OpCodes.Ret));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitMonkeyCall(LoggingIlGenerator target, MethodInfo patch,
|
private IEnumerable<MsilInstruction> EmitMonkeyCall(MethodInfo patch,
|
||||||
IReadOnlyDictionary<string, LocalBuilder> specialVariables)
|
IReadOnlyDictionary<string, MsilLocal> specialVariables)
|
||||||
{
|
{
|
||||||
target.EmitComment($"Call {patch.DeclaringType?.FullName}#{patch.Name}");
|
|
||||||
foreach (var param in patch.GetParameters())
|
foreach (var param in patch.GetParameters())
|
||||||
{
|
{
|
||||||
switch (param.Name)
|
switch (param.Name)
|
||||||
@@ -211,25 +231,26 @@ namespace Torch.Managers.PatchManager
|
|||||||
case INSTANCE_PARAMETER:
|
case INSTANCE_PARAMETER:
|
||||||
if (_method.IsStatic)
|
if (_method.IsStatic)
|
||||||
throw new Exception("Can't use an instance parameter for a static method");
|
throw new Exception("Can't use an instance parameter for a static method");
|
||||||
target.Emit(OpCodes.Ldarg_0);
|
yield return new MsilInstruction(OpCodes.Ldarg_0);
|
||||||
break;
|
break;
|
||||||
case PREFIX_SKIPPED_PARAMETER:
|
case PREFIX_SKIPPED_PARAMETER:
|
||||||
if (param.ParameterType != typeof(bool))
|
if (param.ParameterType != typeof(bool))
|
||||||
throw new Exception($"Prefix skipped parameter {param.ParameterType} must be of type bool");
|
throw new Exception($"Prefix skipped parameter {param.ParameterType} must be of type bool");
|
||||||
if (param.ParameterType.IsByRef || param.IsOut)
|
if (param.ParameterType.IsByRef || param.IsOut)
|
||||||
throw new Exception($"Prefix skipped parameter {param.ParameterType} can't be a reference type");
|
throw new Exception($"Prefix skipped parameter {param.ParameterType} can't be a reference type");
|
||||||
if (specialVariables.TryGetValue(PREFIX_SKIPPED_PARAMETER, out LocalBuilder prefixSkip))
|
if (specialVariables.TryGetValue(PREFIX_SKIPPED_PARAMETER, out MsilLocal prefixSkip))
|
||||||
target.Emit(OpCodes.Ldloc, prefixSkip);
|
yield return new MsilInstruction(OpCodes.Ldloc).InlineValue(prefixSkip);
|
||||||
else
|
else
|
||||||
target.Emit(OpCodes.Ldc_I4_0);
|
yield return new MsilInstruction(OpCodes.Ldc_I4_0);
|
||||||
break;
|
break;
|
||||||
case RESULT_PARAMETER:
|
case RESULT_PARAMETER:
|
||||||
Type retType = param.ParameterType.IsByRef
|
Type retType = param.ParameterType.IsByRef
|
||||||
? param.ParameterType.GetElementType()
|
? param.ParameterType.GetElementType()
|
||||||
: param.ParameterType;
|
: param.ParameterType;
|
||||||
if (retType == null || !retType.IsAssignableFrom(specialVariables[RESULT_PARAMETER].LocalType))
|
if (retType == null || !retType.IsAssignableFrom(specialVariables[RESULT_PARAMETER].Type))
|
||||||
throw new Exception($"Return type {specialVariables[RESULT_PARAMETER].LocalType} can't be assigned to result parameter type {retType}");
|
throw new Exception($"Return type {specialVariables[RESULT_PARAMETER].Type} can't be assigned to result parameter type {retType}");
|
||||||
target.Emit(param.ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc, specialVariables[RESULT_PARAMETER]);
|
yield return new MsilInstruction(param.ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc)
|
||||||
|
.InlineValue(specialVariables[RESULT_PARAMETER]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ParameterInfo declParam = _method.GetParameters().FirstOrDefault(x => x.Name == param.Name);
|
ParameterInfo declParam = _method.GetParameters().FirstOrDefault(x => x.Name == param.Name);
|
||||||
@@ -240,18 +261,18 @@ namespace Torch.Managers.PatchManager
|
|||||||
bool patchByRef = param.IsOut || param.ParameterType.IsByRef;
|
bool patchByRef = param.IsOut || param.ParameterType.IsByRef;
|
||||||
bool declByRef = declParam.IsOut || declParam.ParameterType.IsByRef;
|
bool declByRef = declParam.IsOut || declParam.ParameterType.IsByRef;
|
||||||
if (patchByRef == declByRef)
|
if (patchByRef == declByRef)
|
||||||
target.Emit(OpCodes.Ldarg, paramIdx);
|
yield return new MsilInstruction(OpCodes.Ldarg).InlineValue(new MsilArgument(paramIdx));
|
||||||
else if (patchByRef)
|
else if (patchByRef)
|
||||||
target.Emit(OpCodes.Ldarga, paramIdx);
|
yield return new MsilInstruction(OpCodes.Ldarga).InlineValue(new MsilArgument(paramIdx));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
target.Emit(OpCodes.Ldarg, paramIdx);
|
yield return new MsilInstruction(OpCodes.Ldarg).InlineValue(new MsilArgument(paramIdx));
|
||||||
target.EmitDereference(declParam.ParameterType);
|
yield return EmitExtensions.EmitDereference(declParam.ParameterType);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target.Emit(OpCodes.Call, patch);
|
yield return new MsilInstruction(OpCodes.Call).InlineValue(patch);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
using Torch.Managers.PatchManager.Transpile;
|
using Torch.Managers.PatchManager.Transpile;
|
||||||
|
|
||||||
namespace Torch.Managers.PatchManager
|
namespace Torch.Managers.PatchManager
|
||||||
@@ -11,65 +13,64 @@ namespace Torch.Managers.PatchManager
|
|||||||
/// Sets the given local to its default value in the given IL generator.
|
/// Sets the given local to its default value in the given IL generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="local">Local to set to default</param>
|
/// <param name="local">Local to set to default</param>
|
||||||
/// <param name="target">The IL generator</param>
|
/// <returns>Instructions</returns>
|
||||||
public static void SetToDefault(this LocalBuilder local, LoggingIlGenerator target)
|
public static IEnumerable<MsilInstruction> SetToDefault(this MsilLocal local)
|
||||||
{
|
{
|
||||||
Debug.Assert(local.LocalType != null);
|
Debug.Assert(local.Type != null);
|
||||||
if (local.LocalType.IsEnum || local.LocalType.IsPrimitive)
|
if (local.Type.IsEnum || local.Type.IsPrimitive)
|
||||||
{
|
{
|
||||||
if (local.LocalType == typeof(float))
|
if (local.Type == typeof(float))
|
||||||
target.Emit(OpCodes.Ldc_R4, 0f);
|
yield return new MsilInstruction(OpCodes.Ldc_R4).InlineValue(0f);
|
||||||
else if (local.LocalType == typeof(double))
|
else if (local.Type == typeof(double))
|
||||||
target.Emit(OpCodes.Ldc_R8, 0d);
|
yield return new MsilInstruction(OpCodes.Ldc_R8).InlineValue(0d);
|
||||||
else if (local.LocalType == typeof(long) || local.LocalType == typeof(ulong))
|
else if (local.Type == typeof(long) || local.Type == typeof(ulong))
|
||||||
target.Emit(OpCodes.Ldc_I8, 0L);
|
yield return new MsilInstruction(OpCodes.Ldc_I8).InlineValue(0L);
|
||||||
else
|
else
|
||||||
target.Emit(OpCodes.Ldc_I4, 0);
|
yield return new MsilInstruction(OpCodes.Ldc_I4).InlineValue(0);
|
||||||
target.Emit(OpCodes.Stloc, local);
|
yield return new MsilInstruction(OpCodes.Stloc).InlineValue(local);
|
||||||
}
|
}
|
||||||
else if (local.LocalType.IsValueType) // struct
|
else if (local.Type.IsValueType) // struct
|
||||||
{
|
{
|
||||||
target.Emit(OpCodes.Ldloca, local);
|
yield return new MsilInstruction(OpCodes.Ldloca).InlineValue(local);
|
||||||
target.Emit(OpCodes.Initobj, local.LocalType);
|
yield return new MsilInstruction(OpCodes.Initobj).InlineValue(local.Type);
|
||||||
}
|
}
|
||||||
else // class
|
else // class
|
||||||
{
|
{
|
||||||
target.Emit(OpCodes.Ldnull);
|
yield return new MsilInstruction(OpCodes.Ldnull);
|
||||||
target.Emit(OpCodes.Stloc, local);
|
yield return new MsilInstruction(OpCodes.Stloc).InlineValue(local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Emits a dereference for the given type.
|
/// Emits a dereference for the given type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">IL Generator to emit on</param>
|
|
||||||
/// <param name="type">Type to dereference</param>
|
/// <param name="type">Type to dereference</param>
|
||||||
public static void EmitDereference(this LoggingIlGenerator target, Type type)
|
/// <returns>Derference instruction</returns>
|
||||||
|
public static MsilInstruction EmitDereference(Type type)
|
||||||
{
|
{
|
||||||
if (type.IsByRef)
|
if (type.IsByRef)
|
||||||
type = type.GetElementType();
|
type = type.GetElementType();
|
||||||
Debug.Assert(type != null);
|
Debug.Assert(type != null);
|
||||||
|
|
||||||
if (type == typeof(float))
|
if (type == typeof(float))
|
||||||
target.Emit(OpCodes.Ldind_R4);
|
return new MsilInstruction(OpCodes.Ldind_R4);
|
||||||
else if (type == typeof(double))
|
if (type == typeof(double))
|
||||||
target.Emit(OpCodes.Ldind_R8);
|
return new MsilInstruction(OpCodes.Ldind_R8);
|
||||||
else if (type == typeof(byte))
|
if (type == typeof(byte))
|
||||||
target.Emit(OpCodes.Ldind_U1);
|
return new MsilInstruction(OpCodes.Ldind_U1);
|
||||||
else if (type == typeof(ushort) || type == typeof(char))
|
if (type == typeof(ushort) || type == typeof(char))
|
||||||
target.Emit(OpCodes.Ldind_U2);
|
return new MsilInstruction(OpCodes.Ldind_U2);
|
||||||
else if (type == typeof(uint))
|
if (type == typeof(uint))
|
||||||
target.Emit(OpCodes.Ldind_U4);
|
return new MsilInstruction(OpCodes.Ldind_U4);
|
||||||
else if (type == typeof(sbyte))
|
if (type == typeof(sbyte))
|
||||||
target.Emit(OpCodes.Ldind_I1);
|
return new MsilInstruction(OpCodes.Ldind_I1);
|
||||||
else if (type == typeof(short))
|
if (type == typeof(short))
|
||||||
target.Emit(OpCodes.Ldind_I2);
|
return new MsilInstruction(OpCodes.Ldind_I2);
|
||||||
else if (type == typeof(int) || type.IsEnum)
|
if (type == typeof(int) || type.IsEnum)
|
||||||
target.Emit(OpCodes.Ldind_I4);
|
return new MsilInstruction(OpCodes.Ldind_I4);
|
||||||
else if (type == typeof(long) || type == typeof(ulong))
|
if (type == typeof(long) || type == typeof(ulong))
|
||||||
target.Emit(OpCodes.Ldind_I8);
|
return new MsilInstruction(OpCodes.Ldind_I8);
|
||||||
else
|
return new MsilInstruction(OpCodes.Ldind_Ref);
|
||||||
target.Emit(OpCodes.Ldind_Ref);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
{
|
{
|
||||||
internal static readonly NullTokenResolver Instance = new NullTokenResolver();
|
internal static readonly NullTokenResolver Instance = new NullTokenResolver();
|
||||||
|
|
||||||
private NullTokenResolver()
|
internal NullTokenResolver()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
case OperandType.InlineField:
|
case OperandType.InlineField:
|
||||||
Operand = new MsilOperandInline.MsilOperandReflected<FieldInfo>(this);
|
Operand = new MsilOperandInline.MsilOperandReflected<FieldInfo>(this);
|
||||||
break;
|
break;
|
||||||
|
case OperandType.ShortInlineI:
|
||||||
case OperandType.InlineI:
|
case OperandType.InlineI:
|
||||||
Operand = new MsilOperandInline.MsilOperandInt32(this);
|
Operand = new MsilOperandInline.MsilOperandInt32(this);
|
||||||
break;
|
break;
|
||||||
@@ -63,16 +64,11 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
break;
|
break;
|
||||||
case OperandType.ShortInlineVar:
|
case OperandType.ShortInlineVar:
|
||||||
case OperandType.InlineVar:
|
case OperandType.InlineVar:
|
||||||
if (OpCode.Name.IndexOf("loc", StringComparison.OrdinalIgnoreCase) != -1)
|
if (OpCode.IsLocalStore() || OpCode.IsLocalLoad() || OpCode.IsLocalLoadByRef())
|
||||||
Operand = new MsilOperandInline.MsilOperandLocal(this);
|
Operand = new MsilOperandInline.MsilOperandLocal(this);
|
||||||
else
|
else
|
||||||
Operand = new MsilOperandInline.MsilOperandArgument(this);
|
Operand = new MsilOperandInline.MsilOperandArgument(this);
|
||||||
break;
|
break;
|
||||||
case OperandType.ShortInlineI:
|
|
||||||
Operand = OpCode == OpCodes.Ldc_I4_S
|
|
||||||
? (MsilOperand)new MsilOperandInline.MsilOperandInt8(this)
|
|
||||||
: new MsilOperandInline.MsilOperandUInt8(this);
|
|
||||||
break;
|
|
||||||
case OperandType.ShortInlineR:
|
case OperandType.ShortInlineR:
|
||||||
Operand = new MsilOperandInline.MsilOperandSingle(this);
|
Operand = new MsilOperandInline.MsilOperandSingle(this);
|
||||||
break;
|
break;
|
||||||
@@ -206,6 +202,8 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
Operand is MsilOperandInline<MethodBase> inline)
|
Operand is MsilOperandInline<MethodBase> inline)
|
||||||
{
|
{
|
||||||
MethodBase op = inline.Value;
|
MethodBase op = inline.Value;
|
||||||
|
if (op == null)
|
||||||
|
return num;
|
||||||
if (op is MethodInfo mi && mi.ReturnType != typeof(void))
|
if (op is MethodInfo mi && mi.ReturnType != typeof(void))
|
||||||
num++;
|
num++;
|
||||||
num -= op.GetParameters().Length;
|
num -= op.GetParameters().Length;
|
||||||
|
@@ -19,8 +19,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsLocalLoad(this MsilInstruction me)
|
public static bool IsLocalLoad(this MsilInstruction me)
|
||||||
{
|
{
|
||||||
return me.OpCode == OpCodes.Ldloc || me.OpCode == OpCodes.Ldloc_S || me.OpCode == OpCodes.Ldloc_0 ||
|
return me.OpCode.IsLocalLoad();
|
||||||
me.OpCode == OpCodes.Ldloc_1 || me.OpCode == OpCodes.Ldloc_2 || me.OpCode == OpCodes.Ldloc_3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -28,7 +27,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsLocalLoadByRef(this MsilInstruction me)
|
public static bool IsLocalLoadByRef(this MsilInstruction me)
|
||||||
{
|
{
|
||||||
return me.OpCode == OpCodes.Ldloca || me.OpCode == OpCodes.Ldloca_S;
|
return me.OpCode.IsLocalLoadByRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,8 +35,33 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsLocalStore(this MsilInstruction me)
|
public static bool IsLocalStore(this MsilInstruction me)
|
||||||
{
|
{
|
||||||
return me.OpCode == OpCodes.Stloc || me.OpCode == OpCodes.Stloc_S || me.OpCode == OpCodes.Stloc_0 ||
|
return me.OpCode.IsLocalStore();
|
||||||
me.OpCode == OpCodes.Stloc_1 || me.OpCode == OpCodes.Stloc_2 || me.OpCode == OpCodes.Stloc_3;
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction a local load-by-value instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsLocalLoad(this OpCode opcode)
|
||||||
|
{
|
||||||
|
return opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S || opcode == OpCodes.Ldloc_0 ||
|
||||||
|
opcode == OpCodes.Ldloc_1 || opcode == OpCodes.Ldloc_2 || opcode == OpCodes.Ldloc_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction a local load-by-reference instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsLocalLoadByRef(this OpCode opcode)
|
||||||
|
{
|
||||||
|
return opcode == OpCodes.Ldloca || opcode == OpCodes.Ldloca_S;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this instruction a local store instruction.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsLocalStore(this OpCode opcode)
|
||||||
|
{
|
||||||
|
return opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S || opcode == OpCodes.Stloc_0 ||
|
||||||
|
opcode == OpCodes.Stloc_1 || opcode == OpCodes.Stloc_2 || opcode == OpCodes.Stloc_3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
@@ -21,15 +21,40 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
int val = Instruction.OpCode.OperandType == OperandType.InlineBrTarget
|
|
||||||
? reader.ReadInt32()
|
long offset;
|
||||||
: reader.ReadSByte();
|
|
||||||
Target = context.LabelAt((int)reader.BaseStream.Position + val);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineBrTarget:
|
||||||
|
offset = reader.ReadSByte();
|
||||||
|
break;
|
||||||
|
case OperandType.InlineBrTarget:
|
||||||
|
offset = reader.ReadInt32();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Target = context.LabelAt((int)(reader.BaseStream.Position + offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Target.LabelFor(generator));
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineBrTarget:
|
||||||
|
case OperandType.InlineBrTarget:
|
||||||
|
generator.Emit(Instruction.OpCode, Target.LabelFor(generator));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void CopyTo(MsilOperand operand)
|
internal override void CopyTo(MsilOperand operand)
|
||||||
|
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using Torch.Managers.PatchManager.Transpile;
|
using Torch.Managers.PatchManager.Transpile;
|
||||||
|
using Torch.Utils;
|
||||||
|
|
||||||
namespace Torch.Managers.PatchManager.MSIL
|
namespace Torch.Managers.PatchManager.MSIL
|
||||||
{
|
{
|
||||||
@@ -44,47 +45,6 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class MsilOperandInline
|
public static class MsilOperandInline
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Inline unsigned byte
|
|
||||||
/// </summary>
|
|
||||||
public class MsilOperandUInt8 : MsilOperandInline<byte>
|
|
||||||
{
|
|
||||||
internal MsilOperandUInt8(MsilInstruction instruction) : base(instruction)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
|
||||||
{
|
|
||||||
Value = reader.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
|
||||||
{
|
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Inline signed byte
|
|
||||||
/// </summary>
|
|
||||||
public class MsilOperandInt8 : MsilOperandInline<sbyte>
|
|
||||||
{
|
|
||||||
internal MsilOperandInt8(MsilInstruction instruction) : base(instruction)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
|
||||||
{
|
|
||||||
Value =
|
|
||||||
(sbyte)reader.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
|
||||||
{
|
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inline integer
|
/// Inline integer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,12 +56,36 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value = reader.ReadInt32();
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineI:
|
||||||
|
Value = reader.ReadByte();
|
||||||
|
return;
|
||||||
|
case OperandType.InlineI:
|
||||||
|
Value = reader.ReadInt32();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineI:
|
||||||
|
generator.Emit(Instruction.OpCode, (byte)Value);
|
||||||
|
return;
|
||||||
|
case OperandType.InlineI:
|
||||||
|
generator.Emit(Instruction.OpCode, Value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,12 +100,30 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value = reader.ReadSingle();
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineR:
|
||||||
|
Value = reader.ReadSingle();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineR:
|
||||||
|
generator.Emit(Instruction.OpCode, Value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,12 +138,30 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value = reader.ReadDouble();
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineR:
|
||||||
|
Value = reader.ReadDouble();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineR:
|
||||||
|
generator.Emit(Instruction.OpCode, Value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,12 +176,30 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value = reader.ReadInt64();
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineI8:
|
||||||
|
Value = reader.ReadInt64();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineI8:
|
||||||
|
generator.Emit(Instruction.OpCode, Value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,13 +214,30 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value =
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
context.TokenResolver.ResolveString(reader.ReadInt32());
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineString:
|
||||||
|
Value = context.TokenResolver.ResolveString(reader.ReadInt32());
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineString:
|
||||||
|
generator.Emit(Instruction.OpCode, Value);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,14 +252,28 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
byte[] sig = context.TokenResolver
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
.ResolveSignature(reader.ReadInt32());
|
switch (Instruction.OpCode.OperandType)
|
||||||
throw new ArgumentException("Can't figure out how to convert this.");
|
{
|
||||||
|
case OperandType.InlineSig:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineSig:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,18 +288,45 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
int paramID =
|
int id;
|
||||||
Instruction.OpCode.OperandType == OperandType.ShortInlineVar
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
? reader.ReadByte()
|
switch (Instruction.OpCode.OperandType)
|
||||||
: reader.ReadUInt16();
|
{
|
||||||
if (paramID == 0 && !context.Method.IsStatic)
|
case OperandType.ShortInlineVar:
|
||||||
|
id = reader.ReadByte();
|
||||||
|
break;
|
||||||
|
case OperandType.InlineVar:
|
||||||
|
id = reader.ReadUInt16();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 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 = new MsilArgument(context.Method.GetParameters()[paramID - (context.Method.IsStatic ? 0 : 1)]);
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||||
|
if (context.Method == null)
|
||||||
|
Value = new MsilArgument(id);
|
||||||
|
else
|
||||||
|
Value = new MsilArgument(context.Method.GetParameters()[id - (context.Method.IsStatic ? 0 : 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value.Position);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineVar:
|
||||||
|
generator.Emit(Instruction.OpCode, (byte) Value.Position);
|
||||||
|
break;
|
||||||
|
case OperandType.InlineVar:
|
||||||
|
generator.Emit(Instruction.OpCode, (short)Value.Position);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,16 +341,42 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
Value =
|
int id;
|
||||||
new MsilLocal(context.Method.GetMethodBody().LocalVariables[
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
Instruction.OpCode.OperandType == OperandType.ShortInlineVar
|
switch (Instruction.OpCode.OperandType)
|
||||||
? reader.ReadByte()
|
{
|
||||||
: reader.ReadUInt16()]);
|
case OperandType.ShortInlineVar:
|
||||||
|
id = reader.ReadByte();
|
||||||
|
break;
|
||||||
|
case OperandType.InlineVar:
|
||||||
|
id = reader.ReadUInt16();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||||
|
if (context.MethodBody == null)
|
||||||
|
Value = new MsilLocal(id);
|
||||||
|
else
|
||||||
|
Value = new MsilLocal(context.MethodBody.LocalVariables[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
generator.Emit(Instruction.OpCode, Value.Index);
|
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.ShortInlineVar:
|
||||||
|
generator.Emit(Instruction.OpCode, (byte)Value.Index);
|
||||||
|
break;
|
||||||
|
case OperandType.InlineVar:
|
||||||
|
generator.Emit(Instruction.OpCode, (short)Value.Index);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,16 +408,40 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
value = context.TokenResolver.ResolveField(reader.ReadInt32());
|
value = context.TokenResolver.ResolveField(reader.ReadInt32());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException("Reflected operand only applies to inline reflected types");
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
}
|
}
|
||||||
if (value is TY vty)
|
if (value is TY vty)
|
||||||
Value = vty;
|
Value = vty;
|
||||||
|
else if (value == null)
|
||||||
|
Value = null;
|
||||||
else
|
else
|
||||||
throw new Exception($"Expected type {typeof(TY).Name} from operand {Instruction.OpCode.OperandType}, got {value.GetType()?.Name ?? "null"}");
|
throw new Exception($"Expected type {typeof(TY).Name} from operand {Instruction.OpCode.OperandType}, got {value.GetType()?.Name ?? "null"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Emit(LoggingIlGenerator generator)
|
internal override void Emit(LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
switch (Instruction.OpCode.OperandType)
|
||||||
|
{
|
||||||
|
case OperandType.InlineTok:
|
||||||
|
Debug.Assert(Value is MethodBase || Value is Type || Value is FieldInfo,
|
||||||
|
$"Value {Value?.GetType()} doesn't match operand type");
|
||||||
|
break;
|
||||||
|
case OperandType.InlineType:
|
||||||
|
Debug.Assert(Value is Type, $"Value {Value?.GetType()} doesn't match operand type");
|
||||||
|
break;
|
||||||
|
case OperandType.InlineMethod:
|
||||||
|
Debug.Assert(Value is MethodBase, $"Value {Value?.GetType()} doesn't match operand type");
|
||||||
|
break;
|
||||||
|
case OperandType.InlineField:
|
||||||
|
Debug.Assert(Value is FieldInfo, $"Value {Value?.GetType()} doesn't match operand type");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidBranchException(
|
||||||
|
$"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
|
||||||
|
}
|
||||||
|
|
||||||
if (Value is ConstructorInfo)
|
if (Value is ConstructorInfo)
|
||||||
generator.Emit(Instruction.OpCode, Value as ConstructorInfo);
|
generator.Emit(Instruction.OpCode, Value as ConstructorInfo);
|
||||||
else if (Value is FieldInfo)
|
else if (Value is FieldInfo)
|
||||||
|
@@ -156,12 +156,17 @@ namespace Torch.Managers.PatchManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MethodRewriteSet Transpilers { get; }
|
public MethodRewriteSet Transpilers { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Methods capable of accepting one <see cref="IEnumerable{MsilInstruction}"/> and returing another, modified.
|
||||||
|
/// Runs after prefixes, suffixes, and normal transpilers are applied.
|
||||||
|
/// </summary>
|
||||||
|
public MethodRewriteSet PostTranspilers { get; }
|
||||||
|
/// <summary>
|
||||||
/// Methods run after the original method has run.
|
/// Methods run after the original method has run.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MethodRewriteSet Suffixes { get; }
|
public MethodRewriteSet Suffixes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should the resulting MSIL of this patch operation be printed.
|
/// Should the resulting MSIL of the transpile operation be printed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PrintMsil
|
public bool PrintMsil
|
||||||
{
|
{
|
||||||
@@ -174,8 +179,8 @@ namespace Torch.Managers.PatchManager
|
|||||||
_printMsilBacking = value;
|
_printMsilBacking = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _printMsilBacking;
|
private bool _printMsilBacking;
|
||||||
|
|
||||||
private readonly MethodRewritePattern _parent;
|
private readonly MethodRewritePattern _parent;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -186,6 +191,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
{
|
{
|
||||||
Prefixes = new MethodRewriteSet(parentPattern?.Prefixes);
|
Prefixes = new MethodRewriteSet(parentPattern?.Prefixes);
|
||||||
Transpilers = new MethodRewriteSet(parentPattern?.Transpilers);
|
Transpilers = new MethodRewriteSet(parentPattern?.Transpilers);
|
||||||
|
PostTranspilers = new MethodRewriteSet(parentPattern?.PostTranspilers);
|
||||||
Suffixes = new MethodRewriteSet(parentPattern?.Suffixes);
|
Suffixes = new MethodRewriteSet(parentPattern?.Suffixes);
|
||||||
_parent = parentPattern;
|
_parent = parentPattern;
|
||||||
}
|
}
|
||||||
|
@@ -177,7 +177,9 @@ namespace Torch.Managers.PatchManager
|
|||||||
_finishedPatchCount = 0;
|
_finishedPatchCount = 0;
|
||||||
_dirtyPatchCount = _rewritePatterns.Values.Sum(x => x.HasChanged() ? 1 : 0);
|
_dirtyPatchCount = _rewritePatterns.Values.Sum(x => x.HasChanged() ? 1 : 0);
|
||||||
#if true
|
#if true
|
||||||
ParallelTasks.Parallel.ForEach(_rewritePatterns.Values, DoCommit);
|
ParallelTasks.Parallel.ForEach(_rewritePatterns.Values.Where(x => !x.PrintMsil), DoCommit);
|
||||||
|
foreach (DecoratedMethod m in _rewritePatterns.Values.Where(x => x.PrintMsil))
|
||||||
|
DoCommit(m);
|
||||||
#else
|
#else
|
||||||
foreach (DecoratedMethod m in _rewritePatterns.Values)
|
foreach (DecoratedMethod m in _rewritePatterns.Values)
|
||||||
DoCommit(m);
|
DoCommit(m);
|
||||||
|
@@ -24,20 +24,23 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ILGenerator Backing { get; }
|
public ILGenerator Backing { get; }
|
||||||
|
|
||||||
|
private readonly LogLevel _level;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new logging IL generator backed by the given generator.
|
/// Creates a new logging IL generator backed by the given generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="backing">Backing generator</param>
|
/// <param name="backing">Backing generator</param>
|
||||||
public LoggingIlGenerator(ILGenerator backing)
|
public LoggingIlGenerator(ILGenerator backing, LogLevel level)
|
||||||
{
|
{
|
||||||
Backing = backing;
|
Backing = backing;
|
||||||
|
_level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.DeclareLocal(Type, bool)"/>
|
/// <inheritdoc cref="ILGenerator.DeclareLocal(Type, bool)"/>
|
||||||
public LocalBuilder DeclareLocal(Type localType, bool isPinned = false)
|
public LocalBuilder DeclareLocal(Type localType, bool isPinned = false)
|
||||||
{
|
{
|
||||||
LocalBuilder res = Backing.DeclareLocal(localType, isPinned);
|
LocalBuilder res = Backing.DeclareLocal(localType, isPinned);
|
||||||
_log?.Trace($"DclLoc\t{res.LocalIndex}\t=> {res.LocalType} {res.IsPinned}");
|
_log?.Log(_level, $"DclLoc\t{res.LocalIndex}\t=> {res.LocalType} {res.IsPinned}");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,70 +48,84 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode)"/>
|
||||||
public void Emit(OpCode op)
|
public void Emit(OpCode op)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding}");
|
||||||
Backing.Emit(op);
|
Backing.Emit(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, LocalBuilder)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, LocalBuilder)"/>
|
||||||
public void Emit(OpCode op, LocalBuilder arg)
|
public void Emit(OpCode op, LocalBuilder arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} Local:{arg.LocalIndex}/{arg.LocalType}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} Local:{arg.LocalIndex}/{arg.LocalType}");
|
||||||
|
Backing.Emit(op, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, byte)"/>
|
||||||
|
public void Emit(OpCode op, byte arg)
|
||||||
|
{
|
||||||
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
|
Backing.Emit(op, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, int)"/>
|
||||||
|
public void Emit(OpCode op, short arg)
|
||||||
|
{
|
||||||
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, int)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, int)"/>
|
||||||
public void Emit(OpCode op, int arg)
|
public void Emit(OpCode op, int arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, long)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, long)"/>
|
||||||
public void Emit(OpCode op, long arg)
|
public void Emit(OpCode op, long arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, float)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, float)"/>
|
||||||
public void Emit(OpCode op, float arg)
|
public void Emit(OpCode op, float arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, double)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, double)"/>
|
||||||
public void Emit(OpCode op, double arg)
|
public void Emit(OpCode op, double arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, string)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, string)"/>
|
||||||
public void Emit(OpCode op, string arg)
|
public void Emit(OpCode op, string arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, Type)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, Type)"/>
|
||||||
public void Emit(OpCode op, Type arg)
|
public void Emit(OpCode op, Type arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, FieldInfo)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, FieldInfo)"/>
|
||||||
public void Emit(OpCode op, FieldInfo arg)
|
public void Emit(OpCode op, FieldInfo arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, MethodInfo)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, MethodInfo)"/>
|
||||||
public void Emit(OpCode op, MethodInfo arg)
|
public void Emit(OpCode op, MethodInfo arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,28 +138,28 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, Label)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, Label)"/>
|
||||||
public void Emit(OpCode op, Label arg)
|
public void Emit(OpCode op, Label arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding}\tL:{_labelID.Invoke(arg)}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding}\tL:{_labelID.Invoke(arg)}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, Label[])"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, Label[])"/>
|
||||||
public void Emit(OpCode op, Label[] arg)
|
public void Emit(OpCode op, Label[] arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding}\t{string.Join(", ", arg.Select(x => "L:" + _labelID.Invoke(x)))}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding}\t{string.Join(", ", arg.Select(x => "L:" + _labelID.Invoke(x)))}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, SignatureHelper)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, SignatureHelper)"/>
|
||||||
public void Emit(OpCode op, SignatureHelper arg)
|
public void Emit(OpCode op, SignatureHelper arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.Emit(OpCode, ConstructorInfo)"/>
|
/// <inheritdoc cref="ILGenerator.Emit(OpCode, ConstructorInfo)"/>
|
||||||
public void Emit(OpCode op, ConstructorInfo arg)
|
public void Emit(OpCode op, ConstructorInfo arg)
|
||||||
{
|
{
|
||||||
_log?.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
_log?.Log(_level, $"Emit\t{op,_opcodePadding} {arg}");
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,42 +168,42 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
/// <inheritdoc cref="ILGenerator.BeginExceptionBlock"/>
|
/// <inheritdoc cref="ILGenerator.BeginExceptionBlock"/>
|
||||||
public Label BeginExceptionBlock()
|
public Label BeginExceptionBlock()
|
||||||
{
|
{
|
||||||
_log?.Trace($"BeginExceptionBlock");
|
_log?.Log(_level, $"BeginExceptionBlock");
|
||||||
return Backing.BeginExceptionBlock();
|
return Backing.BeginExceptionBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.BeginCatchBlock"/>
|
/// <inheritdoc cref="ILGenerator.BeginCatchBlock"/>
|
||||||
public void BeginCatchBlock(Type caught)
|
public void BeginCatchBlock(Type caught)
|
||||||
{
|
{
|
||||||
_log?.Trace($"BeginCatchBlock {caught}");
|
_log?.Log(_level, $"BeginCatchBlock {caught}");
|
||||||
Backing.BeginCatchBlock(caught);
|
Backing.BeginCatchBlock(caught);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.BeginExceptFilterBlock"/>
|
/// <inheritdoc cref="ILGenerator.BeginExceptFilterBlock"/>
|
||||||
public void BeginExceptFilterBlock()
|
public void BeginExceptFilterBlock()
|
||||||
{
|
{
|
||||||
_log?.Trace($"BeginExceptFilterBlock");
|
_log?.Log(_level, $"BeginExceptFilterBlock");
|
||||||
Backing.BeginExceptFilterBlock();
|
Backing.BeginExceptFilterBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.BeginFaultBlock"/>
|
/// <inheritdoc cref="ILGenerator.BeginFaultBlock"/>
|
||||||
public void BeginFaultBlock()
|
public void BeginFaultBlock()
|
||||||
{
|
{
|
||||||
_log?.Trace($"BeginFaultBlock");
|
_log?.Log(_level, $"BeginFaultBlock");
|
||||||
Backing.BeginFaultBlock();
|
Backing.BeginFaultBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.BeginFinallyBlock"/>
|
/// <inheritdoc cref="ILGenerator.BeginFinallyBlock"/>
|
||||||
public void BeginFinallyBlock()
|
public void BeginFinallyBlock()
|
||||||
{
|
{
|
||||||
_log?.Trace($"BeginFinallyBlock");
|
_log?.Log(_level, $"BeginFinallyBlock");
|
||||||
Backing.BeginFinallyBlock();
|
Backing.BeginFinallyBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.EndExceptionBlock"/>
|
/// <inheritdoc cref="ILGenerator.EndExceptionBlock"/>
|
||||||
public void EndExceptionBlock()
|
public void EndExceptionBlock()
|
||||||
{
|
{
|
||||||
_log?.Trace($"EndExceptionBlock");
|
_log?.Log(_level, $"EndExceptionBlock");
|
||||||
Backing.EndExceptionBlock();
|
Backing.EndExceptionBlock();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -194,7 +211,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
/// <inheritdoc cref="ILGenerator.MarkLabel(Label)"/>
|
/// <inheritdoc cref="ILGenerator.MarkLabel(Label)"/>
|
||||||
public void MarkLabel(Label label)
|
public void MarkLabel(Label label)
|
||||||
{
|
{
|
||||||
_log?.Trace($"MkLbl\tL:{_labelID.Invoke(label)}");
|
_log?.Log(_level, $"MkLbl\tL:{_labelID.Invoke(label)}");
|
||||||
Backing.MarkLabel(label);
|
Backing.MarkLabel(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +228,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
public void EmitComment(string comment)
|
public void EmitComment(string comment)
|
||||||
{
|
{
|
||||||
_log?.Trace($"// {comment}");
|
_log?.Log(_level, $"// {comment}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore 162
|
#pragma warning restore 162
|
||||||
|
@@ -42,6 +42,21 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
TokenResolver = new NormalTokenResolver(method);
|
TokenResolver = new NormalTokenResolver(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[ReflectedMethod(Name = "BakeByteArray")]
|
||||||
|
private static Func<ILGenerator, byte[]> _ilGeneratorBakeByteArray;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public MethodContext(DynamicMethod method)
|
||||||
|
{
|
||||||
|
Method = null;
|
||||||
|
MethodBody = null;
|
||||||
|
_msilBytes = _ilGeneratorBakeByteArray(method.GetILGenerator());
|
||||||
|
TokenResolver = new DynamicMethodTokenResolver(method);
|
||||||
|
}
|
||||||
|
|
||||||
public void Read()
|
public void Read()
|
||||||
{
|
{
|
||||||
ReadInstructions();
|
ReadInstructions();
|
||||||
@@ -64,7 +79,12 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
instructionValue = (short)((instructionValue << 8) | memory.ReadByte());
|
instructionValue = (short)((instructionValue << 8) | memory.ReadByte());
|
||||||
}
|
}
|
||||||
if (!OpCodeLookup.TryGetValue(instructionValue, out OpCode opcode))
|
if (!OpCodeLookup.TryGetValue(instructionValue, out OpCode opcode))
|
||||||
throw new Exception($"Unknown opcode {instructionValue:X}");
|
{
|
||||||
|
var msg = $"Unknown opcode {instructionValue:X}";
|
||||||
|
_log.Error(msg);
|
||||||
|
Debug.Assert(false, msg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (opcode.Size != memory.Position - opcodeOffset)
|
if (opcode.Size != memory.Position - opcodeOffset)
|
||||||
throw new Exception($"Opcode said it was {opcode.Size} but we read {memory.Position - opcodeOffset}");
|
throw new Exception($"Opcode said it was {opcode.Size} but we read {memory.Position - opcodeOffset}");
|
||||||
var instruction = new MsilInstruction(opcode)
|
var instruction = new MsilInstruction(opcode)
|
||||||
@@ -78,6 +98,8 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
|
|
||||||
private void ResolveCatchClauses()
|
private void ResolveCatchClauses()
|
||||||
{
|
{
|
||||||
|
if (MethodBody == null)
|
||||||
|
return;
|
||||||
foreach (ExceptionHandlingClause clause in MethodBody.ExceptionHandlingClauses)
|
foreach (ExceptionHandlingClause clause in MethodBody.ExceptionHandlingClauses)
|
||||||
{
|
{
|
||||||
var beginInstruction = FindInstruction(clause.TryOffset);
|
var beginInstruction = FindInstruction(clause.TryOffset);
|
||||||
@@ -111,7 +133,8 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
foreach (var label in Labels)
|
foreach (var label in Labels)
|
||||||
{
|
{
|
||||||
MsilInstruction target = FindInstruction(label.Key);
|
MsilInstruction target = FindInstruction(label.Key);
|
||||||
target.Labels?.Add(label.Value);
|
Debug.Assert(target != null, $"No label for offset {label.Key}");
|
||||||
|
target?.Labels?.Add(label.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,15 +14,19 @@ 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, Func<Type, MsilLocal> localCreator,
|
internal static IEnumerable<MsilInstruction> Transpile(MethodBase baseMethod, Func<Type, MsilLocal> localCreator,
|
||||||
IEnumerable<MethodInfo> transpilers, LoggingIlGenerator output, Label? retLabel,
|
IEnumerable<MethodInfo> transpilers, MsilLabel retLabel)
|
||||||
bool logMsil)
|
|
||||||
{
|
{
|
||||||
var context = new MethodContext(baseMethod);
|
var context = new MethodContext(baseMethod);
|
||||||
context.Read();
|
context.Read();
|
||||||
// IntegrityAnalysis(LogLevel.Trace, context.Instructions);
|
// IntegrityAnalysis(LogLevel.Trace, context.Instructions);
|
||||||
|
return Transpile(baseMethod, context.Instructions, localCreator, transpilers, retLabel);
|
||||||
|
}
|
||||||
|
|
||||||
var methodContent = (IEnumerable<MsilInstruction>)context.Instructions;
|
internal static IEnumerable<MsilInstruction> Transpile(MethodBase baseMethod, IEnumerable<MsilInstruction> methodContent,
|
||||||
|
Func<Type, MsilLocal> localCreator,
|
||||||
|
IEnumerable<MethodInfo> transpilers, MsilLabel retLabel)
|
||||||
|
{
|
||||||
foreach (MethodInfo transpiler in transpilers)
|
foreach (MethodInfo transpiler in transpilers)
|
||||||
{
|
{
|
||||||
var paramList = new List<object>();
|
var paramList = new List<object>();
|
||||||
@@ -42,13 +46,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
}
|
}
|
||||||
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, paramList.ToArray());
|
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, paramList.ToArray());
|
||||||
}
|
}
|
||||||
methodContent = FixBranchAndReturn(methodContent, retLabel);
|
return FixBranchAndReturn(methodContent, retLabel);
|
||||||
var list = methodContent.ToList();
|
|
||||||
if (logMsil)
|
|
||||||
{
|
|
||||||
IntegrityAnalysis(LogLevel.Info, list);
|
|
||||||
}
|
|
||||||
EmitMethod(list, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void EmitMethod(IReadOnlyList<MsilInstruction> instructions, LoggingIlGenerator target)
|
internal static void EmitMethod(IReadOnlyList<MsilInstruction> instructions, LoggingIlGenerator target)
|
||||||
@@ -89,7 +87,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginCatchBlock ||
|
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginCatchBlock ||
|
||||||
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFinallyBlock))
|
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFinallyBlock))
|
||||||
continue;
|
continue;
|
||||||
if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) &&
|
if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S || il.OpCode == OpCodes.Endfinally) &&
|
||||||
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock)
|
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -105,7 +103,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="level">default logging level</param>
|
/// <param name="level">default logging level</param>
|
||||||
/// <param name="instructions">instructions</param>
|
/// <param name="instructions">instructions</param>
|
||||||
private static void IntegrityAnalysis(LogLevel level, IReadOnlyList<MsilInstruction> instructions)
|
public static void IntegrityAnalysis(LogLevel level, IReadOnlyList<MsilInstruction> instructions)
|
||||||
{
|
{
|
||||||
var targets = new Dictionary<MsilLabel, int>();
|
var targets = new Dictionary<MsilLabel, int>();
|
||||||
for (var i = 0; i < instructions.Count; i++)
|
for (var i = 0; i < instructions.Count; i++)
|
||||||
@@ -192,13 +190,13 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<MsilInstruction> FixBranchAndReturn(IEnumerable<MsilInstruction> insn, Label? retTarget)
|
private static IEnumerable<MsilInstruction> FixBranchAndReturn(IEnumerable<MsilInstruction> insn, MsilLabel retTarget)
|
||||||
{
|
{
|
||||||
foreach (MsilInstruction i in insn)
|
foreach (MsilInstruction i in insn)
|
||||||
{
|
{
|
||||||
if (retTarget.HasValue && i.OpCode == OpCodes.Ret)
|
if (retTarget != null && i.OpCode == OpCodes.Ret)
|
||||||
{
|
{
|
||||||
var j = i.CopyWith(OpCodes.Br).InlineTarget(new MsilLabel(retTarget.Value));
|
var j = i.CopyWith(OpCodes.Br).InlineTarget(retTarget);
|
||||||
_log.Trace($"Replacing {i} with {j}");
|
_log.Trace($"Replacing {i} with {j}");
|
||||||
yield return j;
|
yield return j;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user