Normal logging for patch manager
Fix: RE treating constructors as normal methods
This commit is contained in:
@@ -112,8 +112,13 @@ namespace Torch.Managers.PatchManager
|
|||||||
|
|
||||||
var specialVariables = new Dictionary<string, LocalBuilder>();
|
var specialVariables = new Dictionary<string, LocalBuilder>();
|
||||||
|
|
||||||
|
Label? labelAfterOriginalContent = Suffixes.Count > 0 ? target.DefineLabel() : (Label?)null;
|
||||||
|
Label? labelAfterOriginalReturn = Prefixes.Any(x => x.ReturnType == typeof(bool)) ? target.DefineLabel() : (Label?)null;
|
||||||
|
|
||||||
|
|
||||||
var returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
|
var returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
|
||||||
var resultVariable = returnType != typeof(void) && Prefixes.Concat(Suffixes).SelectMany(x => x.GetParameters()).Any(x => x.Name == RESULT_PARAMETER)
|
var resultVariable = returnType != typeof(void) && (labelAfterOriginalReturn.HasValue || // If we jump past main content we need local to store return val
|
||||||
|
Prefixes.Concat(Suffixes).SelectMany(x => x.GetParameters()).Any(x => x.Name == RESULT_PARAMETER))
|
||||||
? target.DeclareLocal(returnType)
|
? target.DeclareLocal(returnType)
|
||||||
: null;
|
: null;
|
||||||
resultVariable?.SetToDefault(target);
|
resultVariable?.SetToDefault(target);
|
||||||
@@ -121,39 +126,54 @@ namespace Torch.Managers.PatchManager
|
|||||||
if (resultVariable != null)
|
if (resultVariable != null)
|
||||||
specialVariables.Add(RESULT_PARAMETER, resultVariable);
|
specialVariables.Add(RESULT_PARAMETER, resultVariable);
|
||||||
|
|
||||||
var labelAfterOriginalContent = target.DefineLabel();
|
target.EmitComment("Prefixes Begin");
|
||||||
var labelAfterOriginalReturn = target.DefineLabel();
|
|
||||||
|
|
||||||
foreach (var prefix in Prefixes)
|
foreach (var prefix in Prefixes)
|
||||||
{
|
{
|
||||||
EmitMonkeyCall(target, prefix, specialVariables);
|
EmitMonkeyCall(target, prefix, specialVariables);
|
||||||
if (prefix.ReturnType == typeof(bool))
|
if (prefix.ReturnType == typeof(bool))
|
||||||
target.Emit(OpCodes.Brfalse, labelAfterOriginalReturn);
|
{
|
||||||
else if (prefix.ReturnType != typeof(void))
|
Debug.Assert(labelAfterOriginalReturn.HasValue);
|
||||||
throw new Exception($"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
|
target.Emit(OpCodes.Brfalse, labelAfterOriginalReturn.Value);
|
||||||
}
|
}
|
||||||
|
else if (prefix.ReturnType != typeof(void))
|
||||||
|
throw new Exception(
|
||||||
|
$"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
|
||||||
|
}
|
||||||
|
target.EmitComment("Prefixes End");
|
||||||
|
|
||||||
|
target.EmitComment("Original Begin");
|
||||||
MethodTranspiler.Transpile(_method, Transpilers, target, labelAfterOriginalContent);
|
MethodTranspiler.Transpile(_method, Transpilers, target, labelAfterOriginalContent);
|
||||||
target.MarkLabel(labelAfterOriginalContent);
|
target.EmitComment("Original End");
|
||||||
|
if (labelAfterOriginalContent.HasValue)
|
||||||
|
{
|
||||||
|
target.MarkLabel(labelAfterOriginalContent.Value);
|
||||||
if (resultVariable != null)
|
if (resultVariable != null)
|
||||||
target.Emit(OpCodes.Stloc, resultVariable);
|
target.Emit(OpCodes.Stloc, resultVariable);
|
||||||
target.MarkLabel(labelAfterOriginalReturn);
|
}
|
||||||
|
if (labelAfterOriginalReturn.HasValue)
|
||||||
|
target.MarkLabel(labelAfterOriginalReturn.Value);
|
||||||
|
|
||||||
|
target.EmitComment("Suffixes Begin");
|
||||||
foreach (var suffix in Suffixes)
|
foreach (var suffix in Suffixes)
|
||||||
{
|
{
|
||||||
EmitMonkeyCall(target, suffix, specialVariables);
|
EmitMonkeyCall(target, 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 (labelAfterOriginalContent.HasValue || labelAfterOriginalReturn.HasValue)
|
||||||
|
{
|
||||||
if (resultVariable != null)
|
if (resultVariable != null)
|
||||||
target.Emit(OpCodes.Ldloc, resultVariable);
|
target.Emit(OpCodes.Ldloc, resultVariable);
|
||||||
target.Emit(OpCodes.Ret);
|
target.Emit(OpCodes.Ret);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void EmitMonkeyCall(LoggingIlGenerator target, MethodInfo patch,
|
private void EmitMonkeyCall(LoggingIlGenerator target, MethodInfo patch,
|
||||||
IReadOnlyDictionary<string, LocalBuilder> specialVariables)
|
IReadOnlyDictionary<string, LocalBuilder> 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)
|
||||||
|
@@ -40,7 +40,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
Operand = new MsilOperandInline.MsilOperandInt64(this);
|
Operand = new MsilOperandInline.MsilOperandInt64(this);
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineMethod:
|
case OperandType.InlineMethod:
|
||||||
Operand = new MsilOperandInline.MsilOperandReflected<MethodInfo>(this);
|
Operand = new MsilOperandInline.MsilOperandReflected<MethodBase>(this);
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineR:
|
case OperandType.InlineR:
|
||||||
Operand = new MsilOperandInline.MsilOperandDouble(this);
|
Operand = new MsilOperandInline.MsilOperandDouble(this);
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
@@ -257,23 +258,28 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
|
|
||||||
internal override void Read(MethodContext context, BinaryReader reader)
|
internal override void Read(MethodContext context, BinaryReader reader)
|
||||||
{
|
{
|
||||||
|
object value = null;
|
||||||
switch (Instruction.OpCode.OperandType)
|
switch (Instruction.OpCode.OperandType)
|
||||||
{
|
{
|
||||||
case OperandType.InlineTok:
|
case OperandType.InlineTok:
|
||||||
Value = context.TokenResolver.ResolveMember(reader.ReadInt32()) as TY;
|
value = context.TokenResolver.ResolveMember(reader.ReadInt32());
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineType:
|
case OperandType.InlineType:
|
||||||
Value = context.TokenResolver.ResolveType(reader.ReadInt32()) as TY;
|
value = context.TokenResolver.ResolveType(reader.ReadInt32());
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineMethod:
|
case OperandType.InlineMethod:
|
||||||
Value = context.TokenResolver.ResolveMethod(reader.ReadInt32()) as TY;
|
value = context.TokenResolver.ResolveMethod(reader.ReadInt32());
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineField:
|
case OperandType.InlineField:
|
||||||
Value = context.TokenResolver.ResolveField(reader.ReadInt32()) as TY;
|
value = context.TokenResolver.ResolveField(reader.ReadInt32());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException("Reflected operand only applies to inline reflected types");
|
throw new ArgumentException("Reflected operand only applies to inline reflected types");
|
||||||
}
|
}
|
||||||
|
if (value is TY vty)
|
||||||
|
Value = vty;
|
||||||
|
else
|
||||||
|
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)
|
||||||
|
@@ -90,7 +90,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
public void RemoveAll()
|
public void RemoveAll()
|
||||||
{
|
{
|
||||||
foreach (var k in _backingList)
|
foreach (var k in _backingList)
|
||||||
_backingSet.Remove(k);
|
_backingSet?.Remove(k);
|
||||||
_backingList.Clear();
|
_backingList.Clear();
|
||||||
_sortDirty = true;
|
_sortDirty = true;
|
||||||
Interlocked.Exchange(ref _hasChanges, 1);
|
Interlocked.Exchange(ref _hasChanges, 1);
|
||||||
|
@@ -1,19 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Torch.Utils;
|
||||||
|
|
||||||
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
||||||
#pragma warning disable 162 // unreachable code
|
#pragma warning disable 162 // unreachable code
|
||||||
namespace Torch.Managers.PatchManager.Transpile
|
namespace Torch.Managers.PatchManager.Transpile
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An ILGenerator that can log emit calls when <see cref="LoggingIlGenerator._logging"/> is enabled.
|
/// An ILGenerator that can log emit calls when the TRACE level is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LoggingIlGenerator
|
public class LoggingIlGenerator
|
||||||
{
|
{
|
||||||
private const bool _logging = false;
|
private const int _opcodePadding = -10;
|
||||||
|
|
||||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -34,8 +37,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
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);
|
||||||
if (_logging)
|
_log.Trace($"DclLoc\t{res.LocalIndex}\t=> {res.LocalType} {res.IsPinned}");
|
||||||
_log.Trace($"DeclareLocal {res.LocalType} {res.IsPinned} => {res.LocalIndex}");
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,123 +45,111 @@ 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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding}");
|
||||||
_log.Trace($"Emit {op}");
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} L:{arg.LocalIndex} {arg.LocalType}");
|
||||||
_log.Trace($"Emit {op} L:{arg.LocalIndex} {arg.LocalType}");
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {arg}");
|
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FieldInfo _labelID =
|
|
||||||
typeof(Label).GetField("m_label", BindingFlags.Instance | BindingFlags.NonPublic);
|
#pragma warning disable 649
|
||||||
|
[ReflectedGetter(Name="m_label")]
|
||||||
|
private static Func<Label, int> _labelID;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
/// <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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding}\tL:{_labelID.Invoke(arg)}");
|
||||||
_log.Trace($"Emit {op} L:{_labelID.GetValue(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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding}\t{string.Join(", ", arg.Select(x => "L:" + _labelID.Invoke(x)))}");
|
||||||
_log.Trace($"Emit {op} {string.Join(", ", arg.Select(x => "L:" + _labelID.GetValue(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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {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)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"Emit\t{op,_opcodePadding} {arg}");
|
||||||
_log.Trace($"Emit {op} {arg}");
|
|
||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.MarkLabel(Label)"/>
|
/// <inheritdoc cref="ILGenerator.MarkLabel(Label)"/>
|
||||||
public void MarkLabel(Label label)
|
public void MarkLabel(Label label)
|
||||||
{
|
{
|
||||||
if (_logging)
|
_log.Trace($"MkLbl\tL:{_labelID.Invoke(label)}");
|
||||||
_log.Trace($"MarkLabel L:{_labelID.GetValue(label)}");
|
|
||||||
Backing.MarkLabel(label);
|
Backing.MarkLabel(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +158,16 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
{
|
{
|
||||||
return Backing.DefineLabel();
|
return Backing.DefineLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Emits a comment to the log.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comment">Comment</param>
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
public void EmitComment(string comment)
|
||||||
|
{
|
||||||
|
_log.Trace($"// {comment}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore 162
|
#pragma warning restore 162
|
||||||
}
|
}
|
||||||
|
@@ -52,11 +52,17 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
using (var reader = new BinaryReader(memory))
|
using (var reader = new BinaryReader(memory))
|
||||||
while (memory.Length > memory.Position)
|
while (memory.Length > memory.Position)
|
||||||
{
|
{
|
||||||
|
var count = 1;
|
||||||
var instructionValue = (short)memory.ReadByte();
|
var instructionValue = (short)memory.ReadByte();
|
||||||
if (Prefixes.Contains(instructionValue))
|
if (Prefixes.Contains(instructionValue))
|
||||||
instructionValue = (short)((instructionValue << 8) | memory.ReadByte());
|
{
|
||||||
|
instructionValue = (short) ((instructionValue << 8) | memory.ReadByte());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
if (!OpCodeLookup.TryGetValue(instructionValue, out OpCode opcode))
|
if (!OpCodeLookup.TryGetValue(instructionValue, out OpCode opcode))
|
||||||
throw new Exception($"Unknown opcode {instructionValue:X}");
|
throw new Exception($"Unknown opcode {instructionValue:X}");
|
||||||
|
if (opcode.Size != count)
|
||||||
|
throw new Exception($"Opcode said it was {opcode.Size} but we read {count}");
|
||||||
var instruction = new MsilInstruction(opcode)
|
var instruction = new MsilInstruction(opcode)
|
||||||
{
|
{
|
||||||
Offset = (int) memory.Position
|
Offset = (int) memory.Position
|
||||||
@@ -85,7 +91,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
|
|
||||||
public string ToHumanMsil()
|
public string ToHumanMsil()
|
||||||
{
|
{
|
||||||
return string.Join("\n", _instructions.Select(x => x.Offset + "\t" + x));
|
return string.Join("\n", _instructions.Select(x => $"IL_{x.Offset:X4}: {x}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Dictionary<short, OpCode> OpCodeLookup;
|
private static readonly Dictionary<short, OpCode> OpCodeLookup;
|
||||||
|
@@ -2,16 +2,22 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using NLog;
|
||||||
using Torch.Managers.PatchManager.MSIL;
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
|
|
||||||
namespace Torch.Managers.PatchManager.Transpile
|
namespace Torch.Managers.PatchManager.Transpile
|
||||||
{
|
{
|
||||||
internal class MethodTranspiler
|
internal class MethodTranspiler
|
||||||
{
|
{
|
||||||
|
private 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, IEnumerable<MethodInfo> transpilers, LoggingIlGenerator output, Label? retLabel)
|
||||||
{
|
{
|
||||||
var context = new MethodContext(baseMethod);
|
var context = new MethodContext(baseMethod);
|
||||||
context.Read();
|
context.Read();
|
||||||
|
_log.Trace("Input Method:");
|
||||||
|
_log.Trace(context.ToHumanMsil);
|
||||||
|
|
||||||
var methodContent = (IEnumerable<MsilInstruction>) context.Instructions;
|
var methodContent = (IEnumerable<MsilInstruction>) context.Instructions;
|
||||||
foreach (var transpiler in transpilers)
|
foreach (var transpiler in transpilers)
|
||||||
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, new object[] { methodContent });
|
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, new object[] { methodContent });
|
||||||
@@ -48,7 +54,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
{
|
{
|
||||||
var opcode = (OpCode)field.GetValue(null);
|
var opcode = (OpCode)field.GetValue(null);
|
||||||
if (opcode.OperandType == OperandType.ShortInlineBrTarget &&
|
if (opcode.OperandType == OperandType.ShortInlineBrTarget &&
|
||||||
opcode.Name.EndsWith("_S", StringComparison.OrdinalIgnoreCase))
|
opcode.Name.EndsWith(".s", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var other = (OpCode?) typeof(OpCodes).GetField(field.Name.Substring(0, field.Name.Length - 2),
|
var other = (OpCode?) typeof(OpCodes).GetField(field.Name.Substring(0, field.Name.Length - 2),
|
||||||
BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
|
BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
|
||||||
|
Reference in New Issue
Block a user