Skip to content

Commit

Permalink
Added support for constructor patching
Browse files Browse the repository at this point in the history
Improved opcode debugging
Better variable initialization
Removed prefix jump if not necessary
  • Loading branch information
pardeike committed Feb 21, 2017
1 parent 19e8bd5 commit 837f303
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 82 deletions.
6 changes: 6 additions & 0 deletions Harmony/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public HarmonyPatch(Type type, string methodName, Type[] parameter = null)
info.methodName = methodName;
info.parameter = parameter;
}

public HarmonyPatch(Type type, Type[] parameter = null)
{
info.originalType = type;
info.parameter = parameter;
}
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
Expand Down
1 change: 1 addition & 0 deletions Harmony/Harmony.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<Compile Include="HarmonyProcessor.cs" />
<Compile Include="HarmonySharedState.cs" />
<Compile Include="CodeProcessor.cs" />
<Compile Include="ILCopying\Emitter.cs" />
<Compile Include="Tools\AccessCache.cs" />
<Compile Include="Tools\AccessTools.cs" />
<Compile Include="Attributes.cs" />
Expand Down
179 changes: 179 additions & 0 deletions Harmony/ILCopying/Emitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

namespace Harmony.ILCopying
{
public static class Emitter
{
public static string CodePos(ILGenerator il)
{
var offset = Traverse.Create(il).Field("code_len").GetValue<int>();
return "L_" + offset.ToString("x4") + ": ";
}

public static string FormatArgument(object argument)
{
if (argument == null) return "NULL";
var type = argument.GetType();

if (type == typeof(string))
return "\"" + argument + "\"";
if (type == typeof(Label))
return "Label #" + ((Label)argument).GetHashCode();
if (type == typeof(Label[]))
return "Labels #" + string.Join(" ", ((Label[])argument).Select(l => "#" + l.GetHashCode()).ToArray());
if (type == typeof(LocalBuilder))
return ((LocalBuilder)argument).LocalIndex + " (" + ((LocalBuilder)argument).LocalType + ")";

return "" + argument;
}

public static void MarkLabel(ILGenerator il, Label label)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + FormatArgument(label));
il.MarkLabel(label);
}

public static void Emit(ILGenerator il, OpCode opcode)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode);
il.Emit(opcode);
}

public static void Emit(ILGenerator il, OpCode opcode, LocalBuilder local)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(local));
il.Emit(opcode, local);
}

public static void Emit(ILGenerator il, OpCode opcode, FieldInfo field)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(field));
il.Emit(opcode, field);
}

public static void Emit(ILGenerator il, OpCode opcode, Label[] labels)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(labels));
il.Emit(opcode, labels);
}

public static void Emit(ILGenerator il, OpCode opcode, Label label)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(label));
il.Emit(opcode, label);
}

public static void Emit(ILGenerator il, OpCode opcode, string str)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + FormatArgument(str));
il.Emit(opcode, str);
}

public static void Emit(ILGenerator il, OpCode opcode, float arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void Emit(ILGenerator il, OpCode opcode, byte arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void Emit(ILGenerator il, OpCode opcode, sbyte arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void Emit(ILGenerator il, OpCode opcode, double arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void Emit(ILGenerator il, OpCode opcode, int arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void Emit(ILGenerator il, OpCode opcode, MethodInfo meth)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(meth));
il.Emit(opcode, meth);
}

public static void Emit(ILGenerator il, OpCode opcode, short arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void Emit(ILGenerator il, OpCode opcode, SignatureHelper signature)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(signature));
il.Emit(opcode, signature);
}

public static void Emit(ILGenerator il, OpCode opcode, ConstructorInfo con)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(con));
il.Emit(opcode, con);
}

public static void Emit(ILGenerator il, OpCode opcode, Type cls)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(cls));
il.Emit(opcode, cls);
}

public static void Emit(ILGenerator il, OpCode opcode, long arg)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + opcode + " " + FormatArgument(arg));
il.Emit(opcode, arg);
}

public static void EmitCall(ILGenerator il, OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + "Call " + opcode + " " + methodInfo + " " + optionalParameterTypes);
il.EmitCall(opcode, methodInfo, optionalParameterTypes);
}

public static void EmitCalli(ILGenerator il, OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + "Calli " + opcode + " " + unmanagedCallConv + " " + returnType + " " + parameterTypes);
il.EmitCalli(opcode, unmanagedCallConv, returnType, parameterTypes);
}

public static void EmitCalli(ILGenerator il, OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + "Calli " + opcode + " " + callingConvention + " " + returnType + " " + parameterTypes + " " + optionalParameterTypes);
il.EmitCalli(opcode, callingConvention, returnType, parameterTypes, optionalParameterTypes);
}

public static void EmitWriteLine(ILGenerator il, string value)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + "WriteLine " + FormatArgument(value));
il.EmitWriteLine(value);
}

public static void EmitWriteLine(ILGenerator il, LocalBuilder localBuilder)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + "WriteLine " + FormatArgument(localBuilder));
il.EmitWriteLine(localBuilder);
}

public static void EmitWriteLine(ILGenerator il, FieldInfo fld)
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(CodePos(il) + "WriteLine " + FormatArgument(fld));
il.EmitWriteLine(fld);
}

}
}
10 changes: 6 additions & 4 deletions Harmony/ILCopying/MethodCopier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,23 +206,25 @@ public void FinalizeILCodes(List<ICodeProcessor> processors)


// pass3 - mark labels and emit codes
if (MethodCopier.DEBUG_OPCODES) FileLog.Log("### " + method);
codeInstructions.ForEach(codeInstruction =>
{
foreach (var label in codeInstruction.labels)
generator.MarkLabel(label);
{
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(Emitter.CodePos(generator) + Emitter.FormatArgument(label));
Emitter.MarkLabel(generator, label);
}
var code = codeInstruction.opcode;
var operand = codeInstruction.operand;
if (MethodCopier.DEBUG_OPCODES) FileLog.Log("# " + code + " " + operand);
if (code.OperandType == OperandType.InlineNone)
generator.Emit(code);
Emitter.Emit(generator, code);
else
{
if (operand == null) throw new Exception("Wrong null argument: " + codeInstruction);
var emitMethod = EmitMethodForType(operand.GetType());
if (emitMethod == null) throw new Exception("Unknown Emit argument type " + operand.GetType() + " in " + codeInstruction);
if (MethodCopier.DEBUG_OPCODES) FileLog.Log(Emitter.CodePos(generator) + code + " " + Emitter.FormatArgument(operand));
emitMethod.Invoke(generator, new object[] { code, operand });
}
});
Expand Down
Loading

0 comments on commit 837f303

Please sign in to comment.