Skip to content

Commit

Permalink
Fixing and synchronizing dumper
Browse files Browse the repository at this point in the history
  • Loading branch information
kohanis committed Jul 24, 2024
1 parent ef84f6e commit 44de204
Showing 1 changed file with 36 additions and 9 deletions.
45 changes: 36 additions & 9 deletions Harmony/Internal/Util/CecilEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace HarmonyLib.Internal.Util;
/// <summary>
/// Basic safe DLL emitter for dynamically generated <see cref="MethodDefinition"/>s.
/// </summary>
/// <remarks>Based on https://github.com/MonoMod/MonoMod.Common/blob/master/Utils/DMDGenerators/DMDCecilGenerator.cs</remarks>
/// <remarks>Based on https://github.com/MonoMod/MonoMod/blob/reorganize/src/MonoMod.Utils/DMDGenerators/DMDCecilGenerator.cs</remarks>
internal static class CecilEmitter
{
private static readonly ConstructorInfo UnverifiableCodeAttributeConstructor =
Expand Down Expand Up @@ -49,26 +49,43 @@ public static void Dump(MethodDefinition md, IEnumerable<string> 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)
Expand All @@ -83,15 +100,25 @@ public static void Dump(MethodDefinition md, IEnumerable<string> 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;
}
Expand Down

0 comments on commit 44de204

Please sign in to comment.