From 44de2049687327f429933fb8ee1457e3c23279f6 Mon Sep 17 00:00:00 2001 From: kohanis Date: Wed, 24 Jul 2024 05:32:02 +0300 Subject: [PATCH] Fixing and synchronizing dumper --- Harmony/Internal/Util/CecilEmitter.cs | 45 +++++++++++++++++++++------ 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/Harmony/Internal/Util/CecilEmitter.cs b/Harmony/Internal/Util/CecilEmitter.cs index e328752f..7e887786 100644 --- a/Harmony/Internal/Util/CecilEmitter.cs +++ b/Harmony/Internal/Util/CecilEmitter.cs @@ -19,7 +19,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 +49,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 +100,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 => body.Instructions[md.Body.Instructions.IndexOf(label.Target)], 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; }