Patcher correctly translates catch clauses

This commit is contained in:
Westin Miller
2017-11-11 03:50:25 -08:00
parent 11bc7cb60c
commit c07a01a427
3 changed files with 37 additions and 34 deletions

View File

@@ -12,19 +12,9 @@ namespace Torch.Managers.PatchManager.MSIL
/// </summary> /// </summary>
public enum MsilTryCatchOperationType public enum MsilTryCatchOperationType
{ {
// TryCatchBlockIL:
// var exBlock = ILGenerator.BeginExceptionBlock();
// try{
// ILGenerator.BeginCatchBlock(typeof(Exception));
// } catch(Exception e) {
// ILGenerator.BeginCatchBlock(null);
// } catch {
// ILGenerator.BeginFinallyBlock();
// }finally {
// ILGenerator.EndExceptionBlock();
// }
BeginExceptionBlock, BeginExceptionBlock,
BeginCatchBlock, BeginClauseBlock,
BeginFaultBlock,
BeginFinallyBlock, BeginFinallyBlock,
EndExceptionBlock EndExceptionBlock
} }
@@ -46,9 +36,11 @@ namespace Torch.Managers.PatchManager.MSIL
public MsilTryCatchOperation(MsilTryCatchOperationType op, Type caughtType = null) public MsilTryCatchOperation(MsilTryCatchOperationType op, Type caughtType = null)
{ {
Type = op; Type = op;
if (caughtType != null && op != MsilTryCatchOperationType.BeginCatchBlock) if (caughtType != null && op != MsilTryCatchOperationType.BeginClauseBlock)
throw new ArgumentException($"Can't use caught type with operation type {op}", nameof(caughtType)); throw new ArgumentException($"Can't use caught type with operation type {op}", nameof(caughtType));
CatchType = caughtType; CatchType = caughtType;
} }
public override string ToString() => $"{Type} -> {CatchType}";
} }
} }

View File

@@ -43,10 +43,8 @@ namespace Torch.Managers.PatchManager.Transpile
} }
#pragma warning disable 649 #pragma warning disable 649
[ReflectedMethod(Name = "BakeByteArray")] [ReflectedMethod(Name = "BakeByteArray")] private static Func<ILGenerator, byte[]> _ilGeneratorBakeByteArray;
private static Func<ILGenerator, byte[]> _ilGeneratorBakeByteArray;
#pragma warning restore 649 #pragma warning restore 649
public MethodContext(DynamicMethod method) public MethodContext(DynamicMethod method)
@@ -72,11 +70,11 @@ 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 opcodeOffset = (int)memory.Position; var opcodeOffset = (int) memory.Position;
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());
} }
if (!OpCodeLookup.TryGetValue(instructionValue, out OpCode opcode)) if (!OpCodeLookup.TryGetValue(instructionValue, out OpCode opcode))
{ {
@@ -86,7 +84,8 @@ namespace Torch.Managers.PatchManager.Transpile
continue; 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)
{ {
Offset = opcodeOffset Offset = opcodeOffset
@@ -105,16 +104,24 @@ namespace Torch.Managers.PatchManager.Transpile
var beginInstruction = FindInstruction(clause.TryOffset); var beginInstruction = FindInstruction(clause.TryOffset);
var catchInstruction = FindInstruction(clause.HandlerOffset); var catchInstruction = FindInstruction(clause.HandlerOffset);
var finalInstruction = FindInstruction(clause.HandlerOffset + clause.HandlerLength); var finalInstruction = FindInstruction(clause.HandlerOffset + clause.HandlerLength);
beginInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.BeginExceptionBlock); beginInstruction.TryCatchOperation =
if ((clause.Flags & ExceptionHandlingClauseOptions.Clause) != 0) new MsilTryCatchOperation(MsilTryCatchOperationType.BeginExceptionBlock);
catchInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.BeginCatchBlock, clause.CatchType); if ((clause.Flags & ExceptionHandlingClauseOptions.Fault) != 0)
catchInstruction.TryCatchOperation =
new MsilTryCatchOperation(MsilTryCatchOperationType.BeginFaultBlock);
else if ((clause.Flags & ExceptionHandlingClauseOptions.Finally) != 0) else if ((clause.Flags & ExceptionHandlingClauseOptions.Finally) != 0)
catchInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.BeginFinallyBlock); catchInstruction.TryCatchOperation =
finalInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.EndExceptionBlock); new MsilTryCatchOperation(MsilTryCatchOperationType.BeginFinallyBlock);
else
catchInstruction.TryCatchOperation =
new MsilTryCatchOperation(MsilTryCatchOperationType.BeginClauseBlock, clause.CatchType);
finalInstruction.TryCatchOperation =
new MsilTryCatchOperation(MsilTryCatchOperationType.EndExceptionBlock);
} }
} }
private MsilInstruction FindInstruction(int offset) public MsilInstruction FindInstruction(int offset)
{ {
int min = 0, max = _instructions.Count; int min = 0, max = _instructions.Count;
while (min != max) while (min != max)
@@ -153,14 +160,14 @@ namespace Torch.Managers.PatchManager.Transpile
Prefixes = new HashSet<short>(); Prefixes = new HashSet<short>();
foreach (FieldInfo field in typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public)) foreach (FieldInfo field in typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public))
{ {
var opcode = (OpCode)field.GetValue(null); var opcode = (OpCode) field.GetValue(null);
if (opcode.OpCodeType != OpCodeType.Nternal) if (opcode.OpCodeType != OpCodeType.Nternal)
OpCodeLookup.Add(opcode.Value, opcode); OpCodeLookup.Add(opcode.Value, opcode);
if ((ushort)opcode.Value > 0xFF) if ((ushort) opcode.Value > 0xFF)
{ {
Prefixes.Add((short)((ushort)opcode.Value >> 8)); Prefixes.Add((short) ((ushort) opcode.Value >> 8));
} }
} }
} }
} }
} }

View File

@@ -60,9 +60,12 @@ namespace Torch.Managers.PatchManager.Transpile
case MsilTryCatchOperationType.BeginExceptionBlock: case MsilTryCatchOperationType.BeginExceptionBlock:
target.BeginExceptionBlock(); target.BeginExceptionBlock();
break; break;
case MsilTryCatchOperationType.BeginCatchBlock: case MsilTryCatchOperationType.BeginClauseBlock:
target.BeginCatchBlock(il.TryCatchOperation.CatchType); target.BeginCatchBlock(il.TryCatchOperation.CatchType);
break; break;
case MsilTryCatchOperationType.BeginFaultBlock:
target.BeginFaultBlock();
break;
case MsilTryCatchOperationType.BeginFinallyBlock: case MsilTryCatchOperationType.BeginFinallyBlock:
target.BeginFinallyBlock(); target.BeginFinallyBlock();
break; break;
@@ -80,11 +83,12 @@ namespace Torch.Managers.PatchManager.Transpile
// Leave opcodes emitted by these: // Leave opcodes emitted by these:
if (il.OpCode == OpCodes.Endfilter && ilNext?.TryCatchOperation?.Type == if (il.OpCode == OpCodes.Endfilter && ilNext?.TryCatchOperation?.Type ==
MsilTryCatchOperationType.BeginCatchBlock) MsilTryCatchOperationType.BeginClauseBlock)
continue; continue;
if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) && if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) &&
(ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock || (ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock ||
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginCatchBlock || ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginClauseBlock ||
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFaultBlock ||
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFinallyBlock)) ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFinallyBlock))
continue; continue;
if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S || il.OpCode == OpCodes.Endfinally) && if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S || il.OpCode == OpCodes.Endfinally) &&
@@ -175,7 +179,7 @@ namespace Torch.Managers.PatchManager.Transpile
continue; continue;
} }
} }
if (k.OpCode == OpCodes.Br || k.OpCode == OpCodes.Br_S) if (k.OpCode == OpCodes.Br || k.OpCode == OpCodes.Br_S || k.OpCode == OpCodes.Leave || k.OpCode == OpCodes.Leave_S)
unreachable = true; unreachable = true;
} }
foreach (var k in data) foreach (var k in data)