diff --git a/Harmony/Internal/Util/CecilEmitter.cs b/Harmony/Internal/Util/CecilEmitter.cs
index e328752f..520c770c 100644
--- a/Harmony/Internal/Util/CecilEmitter.cs
+++ b/Harmony/Internal/Util/CecilEmitter.cs
@@ -1,6 +1,7 @@
using HarmonyLib.Tools;
using Mono.Cecil;
using Mono.Cecil.Cil;
+using Mono.Collections.Generic;
using MonoMod.Cil;
using MonoMod.Utils;
using System;
@@ -19,7 +20,7 @@ namespace HarmonyLib.Internal.Util;
///
/// Basic safe DLL emitter for dynamically generated s.
///
-/// Based on https://github.com/MonoMod/MonoMod.Common/blob/master/Utils/DMDGenerators/DMDCecilGenerator.cs
+/// Based on https://github.com/MonoMod/MonoMod/blob/reorganize/src/MonoMod.Utils/DMDGenerators/DMDCecilGenerator.cs
internal static class CecilEmitter
{
private static readonly ConstructorInfo UnverifiableCodeAttributeConstructor =
@@ -49,26 +50,43 @@ public static void Dump(MethodDefinition md, IEnumerable dumpPaths, Meth
MethodDefinition clone = null;
+ /* see below
var isVolatile = new TypeReference("System.Runtime.CompilerServices", "IsVolatile", module,
module.TypeSystem.CoreLibrary);
+ */
- Relinker relinker = (mtp, _) => mtp == md ? clone : module.ImportReference(mtp);
+ Relinker relinker = (mtp, _) =>
+ {
+ if (mtp == md)
+ return clone!;
+ if (mtp is MethodReference mr)
+ {
+ if (mr.FullName == md.FullName
+ && mr.DeclaringType.FullName == md.DeclaringType.FullName
+ && mr.DeclaringType.Scope.Name == md.DeclaringType.Scope.Name)
+ return clone!;
+ }
+ return module.ImportReference(mtp);
+ };
clone =
new MethodDefinition(original?.Name ?? "_" + md.Name.Replace(".", "_"), md.Attributes, module.TypeSystem.Void)
{
MethodReturnType = md.MethodReturnType,
- Attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
+ Attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static,
ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed,
DeclaringType = td,
- HasThis = false
+ HasThis = false,
+ NoInlining = true
};
+
td.Methods.Add(clone);
foreach (var param in md.Parameters)
clone.Parameters.Add(param.Clone().Relink(relinker, clone));
clone.ReturnType = md.ReturnType.Relink(relinker, clone);
+
var body = clone.Body = md.Body.Clone(clone);
foreach (var variable in clone.Body.Variables)
@@ -83,15 +101,25 @@ public static void Dump(MethodDefinition md, IEnumerable dumpPaths, Meth
operand = operand switch
{
ParameterDefinition param => clone.Parameters[param.Index],
- ILLabel label => label.Target,
+ ILLabel label => LabelFix(label, body.Instructions, md.Body.Instructions),
IMetadataTokenProvider mtp => mtp.Relink(relinker, clone),
_ => operand
};
- if (instr.Previous?.OpCode == OpCodes.Volatile &&
- operand is FieldReference fref &&
- (fref.FieldType as RequiredModifierType)?.ModifierType != isVolatile)
- fref.FieldType = new RequiredModifierType(isVolatile, fref.FieldType);
+ // System.Reflection doesn't contain any volatility info.
+ // System.Reflection.Emit presumably does something similar to this.
+ // Mono.Cecil thus isn't aware of the volatility as part of the imported field reference.
+ // The modifier is still necessary though.
+ // This is done here instead of the copier as Harmony and other users can't track modreqs
+
+ // This isn't actually a valid transformation though. A ldfld or stfld can have the volatile
+ // prefix, without having modreq(IsVolatile) on the field. Adding the modreq() causes the runtime
+ // to not be able to find the field.
+ /*if (instr.Previous?.OpCode == OpCodes.Volatile &&
+ operand is FieldReference fref &&
+ (fref.FieldType as RequiredModifierType)?.ModifierType != tr_IsVolatile) {
+ fref.FieldType = new RequiredModifierType(tr_IsVolatile, fref.FieldType);
+ }*/
instr.Operand = operand;
}
@@ -129,4 +157,15 @@ private static string SanitizeTypeName(string typeName)
.Replace("<", "{")
.Replace(">", "}");
}
+
+ private static Instruction LabelFix(ILLabel label, Collection clone, Collection original)
+ {
+ var target = label.Target;
+ if (!clone.Contains(target))
+ {
+ var idx = original.IndexOf(label.Target);
+ if (idx != -1) return clone[idx];
+ }
+ return target;
+ }
}