1
1
using HarmonyLib . Tools ;
2
2
using Mono . Cecil ;
3
3
using Mono . Cecil . Cil ;
4
+ using Mono . Collections . Generic ;
4
5
using MonoMod . Cil ;
5
6
using MonoMod . Utils ;
6
7
using System ;
@@ -19,7 +20,7 @@ namespace HarmonyLib.Internal.Util;
19
20
/// <summary>
20
21
/// Basic safe DLL emitter for dynamically generated <see cref="MethodDefinition"/>s.
21
22
/// </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>
23
24
internal static class CecilEmitter
24
25
{
25
26
private static readonly ConstructorInfo UnverifiableCodeAttributeConstructor =
@@ -49,26 +50,43 @@ public static void Dump(MethodDefinition md, IEnumerable<string> dumpPaths, Meth
49
50
50
51
MethodDefinition clone = null ;
51
52
53
+ /* see below
52
54
var isVolatile = new TypeReference("System.Runtime.CompilerServices", "IsVolatile", module,
53
55
module.TypeSystem.CoreLibrary);
56
+ */
54
57
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
+ } ;
56
71
57
72
clone =
58
73
new MethodDefinition ( original ? . Name ?? "_" + md . Name . Replace ( "." , "_" ) , md . Attributes , module . TypeSystem . Void )
59
74
{
60
75
MethodReturnType = md . MethodReturnType ,
61
- Attributes = MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Static ,
76
+ Attributes = MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . Public | MethodAttributes . Static ,
62
77
ImplAttributes = MethodImplAttributes . IL | MethodImplAttributes . Managed ,
63
78
DeclaringType = td ,
64
- HasThis = false
79
+ HasThis = false ,
80
+ NoInlining = true
65
81
} ;
82
+
66
83
td . Methods . Add ( clone ) ;
67
84
68
85
foreach ( var param in md . Parameters )
69
86
clone . Parameters . Add ( param . Clone ( ) . Relink ( relinker , clone ) ) ;
70
87
71
88
clone . ReturnType = md . ReturnType . Relink ( relinker , clone ) ;
89
+
72
90
var body = clone . Body = md . Body . Clone ( clone ) ;
73
91
74
92
foreach ( var variable in clone . Body . Variables )
@@ -83,15 +101,25 @@ public static void Dump(MethodDefinition md, IEnumerable<string> dumpPaths, Meth
83
101
operand = operand switch
84
102
{
85
103
ParameterDefinition param => clone . Parameters [ param . Index ] ,
86
- ILLabel label => label . Target ,
104
+ ILLabel label => LabelFix ( label , body . Instructions , md . Body . Instructions ) ,
87
105
IMetadataTokenProvider mtp => mtp . Relink ( relinker , clone ) ,
88
106
_ => operand
89
107
} ;
90
108
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
+ }*/
95
123
96
124
instr . Operand = operand ;
97
125
}
@@ -129,4 +157,15 @@ private static string SanitizeTypeName(string typeName)
129
157
. Replace ( "<" , "{" )
130
158
. Replace ( ">" , "}" ) ;
131
159
}
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
+ }
132
171
}
0 commit comments