Skip to content

Commit

Permalink
fixes __runOriginal logic
Browse files Browse the repository at this point in the history
  • Loading branch information
pardeike committed Mar 15, 2022
1 parent 22226a7 commit 6006140
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 29 deletions.
23 changes: 13 additions & 10 deletions Harmony/Internal/MethodPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,16 @@ internal MethodInfo CreateReplacement(out Dictionary<int, CodeInstruction> final

Label? skipOriginalLabel = null;
LocalBuilder runOriginalVariable = null;
if (prefixes.Any(fix => PrefixAffectsOriginal(fix)))
var prefixAffectsOriginal = prefixes.Any(fix => PrefixAffectsOriginal(fix));
var anyFixHasRunOriginalVar = fixes.Any(fix => fix.GetParameters().Any(p => p.Name == RUN_ORIGINAL_VAR));
if (prefixAffectsOriginal || anyFixHasRunOriginalVar)
{
runOriginalVariable = DeclareLocalVariable(typeof(bool));
emitter.Emit(OpCodes.Ldc_I4_1);
emitter.Emit(OpCodes.Stloc, runOriginalVariable);

skipOriginalLabel = il.DefineLabel();
if (prefixAffectsOriginal)
skipOriginalLabel = il.DefineLabel();
}

fixes.ForEach(fix =>
Expand Down Expand Up @@ -151,12 +154,12 @@ internal MethodInfo CreateReplacement(out Dictionary<int, CodeInstruction> final
if (skipOriginalLabel.HasValue)
emitter.MarkLabel(skipOriginalLabel.Value);

_ = AddPostfixes(privateVars, false);
_ = AddPostfixes(privateVars, runOriginalVariable, false);

if (resultVariable is object && hasReturnCode)
emitter.Emit(OpCodes.Ldloc, resultVariable);

var needsToStorePassthroughResult = AddPostfixes(privateVars, true);
var needsToStorePassthroughResult = AddPostfixes(privateVars, runOriginalVariable, true);

var hasFinalizers = finalizers.Any();
if (hasFinalizers)
Expand All @@ -167,7 +170,7 @@ internal MethodInfo CreateReplacement(out Dictionary<int, CodeInstruction> final
emitter.Emit(OpCodes.Ldloc, resultVariable);
}

_ = AddFinalizers(privateVars, false);
_ = AddFinalizers(privateVars, runOriginalVariable, false);
emitter.Emit(OpCodes.Ldc_I4_1);
emitter.Emit(OpCodes.Stloc, finalizedVariable);
var noExceptionLabel1 = il.DefineLabel();
Expand All @@ -185,7 +188,7 @@ internal MethodInfo CreateReplacement(out Dictionary<int, CodeInstruction> final
var endFinalizerLabel = il.DefineLabel();
emitter.Emit(OpCodes.Brtrue, endFinalizerLabel);

var rethrowPossible = AddFinalizers(privateVars, true);
var rethrowPossible = AddFinalizers(privateVars, runOriginalVariable, true);

emitter.MarkLabel(endFinalizerLabel);

Expand Down Expand Up @@ -771,7 +774,7 @@ void AddPrefixes(Dictionary<string, LocalBuilder> variables, LocalBuilder runOri
});
}

bool AddPostfixes(Dictionary<string, LocalBuilder> variables, bool passthroughPatches)
bool AddPostfixes(Dictionary<string, LocalBuilder> variables, LocalBuilder runOriginalVariable, bool passthroughPatches)
{
var result = false;
postfixes
Expand All @@ -782,7 +785,7 @@ bool AddPostfixes(Dictionary<string, LocalBuilder> variables, bool passthroughPa
throw new Exception("Methods without body cannot have postfixes. Use a transpiler instead.");
var tmpBoxVars = new List<KeyValuePair<LocalBuilder, Type>>();
EmitCallParameter(fix, variables, null, true, out var tmpObjectVar, tmpBoxVars);
EmitCallParameter(fix, variables, runOriginalVariable, true, out var tmpObjectVar, tmpBoxVars);
emitter.Emit(OpCodes.Call, fix);
if (fix.GetParameters().Any(p => p.Name == ARGS_ARRAY_VAR))
RestoreArgumentArray(variables);
Expand Down Expand Up @@ -818,7 +821,7 @@ bool AddPostfixes(Dictionary<string, LocalBuilder> variables, bool passthroughPa
return result;
}

bool AddFinalizers(Dictionary<string, LocalBuilder> variables, bool catchExceptions)
bool AddFinalizers(Dictionary<string, LocalBuilder> variables, LocalBuilder runOriginalVariable, bool catchExceptions)
{
var rethrowPossible = true;
finalizers
Expand All @@ -831,7 +834,7 @@ bool AddFinalizers(Dictionary<string, LocalBuilder> variables, bool catchExcepti
emitter.MarkBlockBefore(new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock), out var label);
var tmpBoxVars = new List<KeyValuePair<LocalBuilder, Type>>();
EmitCallParameter(fix, variables, null, false, out var tmpObjectVar, tmpBoxVars);
EmitCallParameter(fix, variables, runOriginalVariable, false, out var tmpObjectVar, tmpBoxVars);
emitter.Emit(OpCodes.Call, fix);
if (fix.GetParameters().Any(p => p.Name == ARGS_ARRAY_VAR))
RestoreArgumentArray(variables);
Expand Down
76 changes: 73 additions & 3 deletions HarmonyTests/Patching/Assets/PatchClasses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1117,10 +1117,13 @@ public static void Postfix(ref object __result)
}
}

[HarmonyPatch(typeof(Class22), nameof(Class22.Method22))]
public class Class22
{
public static bool? bool1 = null;
public static bool? bool2 = null;
public static bool? bool1;
public static bool? bool2;
public static bool? bool3;
public static bool? bool4;

[MethodImpl(MethodImplOptions.NoInlining)]
public static void Method22()
Expand All @@ -1134,13 +1137,80 @@ public static void Method22()
}
}

[HarmonyPrefix]
public static bool Prefix1(bool __runOriginal)
{
bool1 = __runOriginal;
return true;
}

[HarmonyPrefix]
public static bool Prefix2(bool __runOriginal)
{
bool2 = __runOriginal;
return false;
}

public static void Prefix2(bool __runOriginal)
[HarmonyPrefix]
public static void Prefix3(bool __runOriginal)
{
bool3 = __runOriginal;
}

[HarmonyPostfix]
public static void Postfix(bool __runOriginal)
{
bool4 = __runOriginal;
}
}

[HarmonyPatch(typeof(Class23), nameof(Class23.Method23))]
public class Class23
{
public static bool? bool1;

[MethodImpl(MethodImplOptions.NoInlining)]
public static void Method23()
{
try
{
}
catch
{
throw;
}
}

public static void Postfix(bool __runOriginal)
{
bool1 = __runOriginal;
}
}

[HarmonyPatch(typeof(Class24), nameof(Class24.Method24))]
public class Class24
{
public static bool? bool1;
public static bool? bool2;

[MethodImpl(MethodImplOptions.NoInlining)]
public static void Method24()
{
try
{
}
catch
{
throw;
}
}

public static void Prefix(bool __runOriginal)
{
bool1 = __runOriginal;
}

public static void Postfix(bool __runOriginal)
{
bool2 = __runOriginal;
}
Expand Down
70 changes: 54 additions & 16 deletions HarmonyTests/Patching/StaticPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,27 +409,65 @@ public void Test_Class22()
var instance = new Harmony("test");
Assert.NotNull(instance, "instance");

var original = SymbolExtensions.GetMethodInfo(() => Class22.Method22());
Assert.NotNull(original, "original");
var prefix1 = SymbolExtensions.GetMethodInfo(() => Class22.Prefix1(false));
Assert.NotNull(original, "prefix1");
var prefix2 = SymbolExtensions.GetMethodInfo(() => Class22.Prefix2(false));
Assert.NotNull(original, "prefix2");

var patched1 = instance.Patch(original, new HarmonyMethod(prefix1));
Assert.NotNull(patched1, "patched1");

var patched2 = instance.Patch(original, new HarmonyMethod(prefix2));
Assert.NotNull(patched2, "patched2");
var processor = new PatchClassProcessor(instance, typeof(Class22));
Assert.NotNull(processor, "processor");
_ = processor.Patch();

Class22.bool1 = null;
Class22.bool2 = null;
Class22.bool3 = null;
Class22.bool4 = null;
Class22.Method22();

Assert.NotNull(Class22.bool1, "Class22.bool1");
Assert.NotNull(Class22.bool2, "Class22.bool2");
Assert.IsTrue(Class22.bool1.Value, "Class22.bool1.Value");
Assert.IsFalse(Class22.bool2.Value, "Class22.bool2.Value");
Assert.NotNull(Class22.bool1, "bool1");
Assert.IsTrue(Class22.bool1.Value, "bool1.Value");

Assert.NotNull(Class22.bool2, "bool2");
Assert.IsTrue(Class22.bool2.Value, "bool2.Value");

Assert.NotNull(Class22.bool3, "bool3");
Assert.IsFalse(Class22.bool3.Value, "bool3.Value");

Assert.NotNull(Class22.bool4, "bool3");
Assert.IsFalse(Class22.bool4.Value, "bool4.Value");
}

[Test]
public void Test_Class23()
{
var instance = new Harmony("test");
Assert.NotNull(instance, "instance");

var processor = new PatchClassProcessor(instance, typeof(Class23));
Assert.NotNull(processor, "processor");
_ = processor.Patch();

Class23.bool1 = null;
Class23.Method23();

Assert.NotNull(Class23.bool1, "bool1");
Assert.IsTrue(Class23.bool1.Value, "bool1.Value");
}

[Test]
public void Test_Class24()
{
var instance = new Harmony("test");
Assert.NotNull(instance, "instance");

var processor = new PatchClassProcessor(instance, typeof(Class24));
Assert.NotNull(processor, "processor");
_ = processor.Patch();

Class24.bool1 = null;
Class24.bool2 = null;
Class24.Method24();

Assert.NotNull(Class24.bool1, "bool1");
Assert.IsTrue(Class24.bool1.Value, "bool1.Value");

Assert.NotNull(Class24.bool2, "bool2");
Assert.IsTrue(Class24.bool2.Value, "bool2.Value");
}
}
}

0 comments on commit 6006140

Please sign in to comment.