Skip to content

Commit a9fe08d

Browse files
committed
Fixing and synchronizing dumper
1 parent ef84f6e commit a9fe08d

File tree

1 file changed

+48
-9
lines changed

1 file changed

+48
-9
lines changed

Harmony/Internal/Util/CecilEmitter.cs

+48-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using HarmonyLib.Tools;
22
using Mono.Cecil;
33
using Mono.Cecil.Cil;
4+
using Mono.Collections.Generic;
45
using MonoMod.Cil;
56
using MonoMod.Utils;
67
using System;
@@ -19,7 +20,7 @@ namespace HarmonyLib.Internal.Util;
1920
/// <summary>
2021
/// Basic safe DLL emitter for dynamically generated <see cref="MethodDefinition"/>s.
2122
/// </summary>
22-
/// <remarks>Based on https://github.com/MonoMod/MonoMod.Common/blob/master/Utils/DMDGenerators/DMDCecilGenerator.cs</remarks>
23+
/// <remarks>Based on https://github.com/MonoMod/MonoMod/blob/reorganize/src/MonoMod.Utils/DMDGenerators/DMDCecilGenerator.cs</remarks>
2324
internal static class CecilEmitter
2425
{
2526
private static readonly ConstructorInfo UnverifiableCodeAttributeConstructor =
@@ -49,26 +50,43 @@ public static void Dump(MethodDefinition md, IEnumerable<string> dumpPaths, Meth
4950

5051
MethodDefinition clone = null;
5152

53+
/* see below
5254
var isVolatile = new TypeReference("System.Runtime.CompilerServices", "IsVolatile", module,
5355
module.TypeSystem.CoreLibrary);
56+
*/
5457

55-
Relinker relinker = (mtp, _) => mtp == md ? clone : module.ImportReference(mtp);
58+
Relinker relinker = (mtp, _) =>
59+
{
60+
if (mtp == md)
61+
return clone!;
62+
if (mtp is MethodReference mr)
63+
{
64+
if (mr.FullName == md.FullName
65+
&& mr.DeclaringType.FullName == md.DeclaringType.FullName
66+
&& mr.DeclaringType.Scope.Name == md.DeclaringType.Scope.Name)
67+
return clone!;
68+
}
69+
return module.ImportReference(mtp);
70+
};
5671

5772
clone =
5873
new MethodDefinition(original?.Name ?? "_" + md.Name.Replace(".", "_"), md.Attributes, module.TypeSystem.Void)
5974
{
6075
MethodReturnType = md.MethodReturnType,
61-
Attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
76+
Attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Static,
6277
ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed,
6378
DeclaringType = td,
64-
HasThis = false
79+
HasThis = false,
80+
NoInlining = true
6581
};
82+
6683
td.Methods.Add(clone);
6784

6885
foreach (var param in md.Parameters)
6986
clone.Parameters.Add(param.Clone().Relink(relinker, clone));
7087

7188
clone.ReturnType = md.ReturnType.Relink(relinker, clone);
89+
7290
var body = clone.Body = md.Body.Clone(clone);
7391

7492
foreach (var variable in clone.Body.Variables)
@@ -83,15 +101,25 @@ public static void Dump(MethodDefinition md, IEnumerable<string> dumpPaths, Meth
83101
operand = operand switch
84102
{
85103
ParameterDefinition param => clone.Parameters[param.Index],
86-
ILLabel label => label.Target,
104+
ILLabel label => LabelFix(label, body.Instructions, md.Body.Instructions),
87105
IMetadataTokenProvider mtp => mtp.Relink(relinker, clone),
88106
_ => operand
89107
};
90108

91-
if (instr.Previous?.OpCode == OpCodes.Volatile &&
92-
operand is FieldReference fref &&
93-
(fref.FieldType as RequiredModifierType)?.ModifierType != isVolatile)
94-
fref.FieldType = new RequiredModifierType(isVolatile, fref.FieldType);
109+
// System.Reflection doesn't contain any volatility info.
110+
// System.Reflection.Emit presumably does something similar to this.
111+
// Mono.Cecil thus isn't aware of the volatility as part of the imported field reference.
112+
// The modifier is still necessary though.
113+
// This is done here instead of the copier as Harmony and other users can't track modreqs
114+
115+
// This isn't actually a valid transformation though. A ldfld or stfld can have the volatile
116+
// prefix, without having modreq(IsVolatile) on the field. Adding the modreq() causes the runtime
117+
// to not be able to find the field.
118+
/*if (instr.Previous?.OpCode == OpCodes.Volatile &&
119+
operand is FieldReference fref &&
120+
(fref.FieldType as RequiredModifierType)?.ModifierType != tr_IsVolatile) {
121+
fref.FieldType = new RequiredModifierType(tr_IsVolatile, fref.FieldType);
122+
}*/
95123

96124
instr.Operand = operand;
97125
}
@@ -129,4 +157,15 @@ private static string SanitizeTypeName(string typeName)
129157
.Replace("<", "{")
130158
.Replace(">", "}");
131159
}
160+
161+
private static Instruction LabelFix(ILLabel label, Collection<Instruction> clone, Collection<Instruction> original)
162+
{
163+
var target = label.Target;
164+
if (!clone.Contains(target))
165+
{
166+
var idx = original.IndexOf(label.Target);
167+
if (idx != -1) return clone[idx];
168+
}
169+
return target;
170+
}
132171
}

0 commit comments

Comments
 (0)