Skip to content

Commit 62bae54

Browse files
Merge pull request #50 from CedaryCat/default
Relinker: handle vars/params & generics; fix by-ref hook/delegate emission
2 parents a2c0c70 + fb7030d commit 62bae54

4 files changed

Lines changed: 81 additions & 43 deletions

File tree

ModFramework/Emitters/HookEmitter.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ static string GetUniqueName(MethodDefinition method)
9191
name += "_" + string.Join("_", method.Parameters.Select(y =>
9292
{
9393
var name = y.ParameterType.Name;
94-
if (y.ParameterType.IsByReference)
95-
name = $"{y.ParameterType.GetElementType().Name}ByRef";
94+
if (y.ParameterType is ByReferenceType byref)
95+
name = $"{byref.ElementType.Name}ByRef";
9696
return name;
9797
}));
9898
}
@@ -133,7 +133,7 @@ static TypeDefinition CreateHookEventArgs(TypeDefinition hookType, MethodDefinit
133133
// for each parameter in the method, create a field
134134
foreach (var param in hookDefinition.Parameters)
135135
{
136-
var paramType = param.ParameterType.IsByReference ? param.ParameterType.GetElementType() : param.ParameterType;
136+
var paramType = param.ParameterType is ByReferenceType byref ? byref.ElementType : param.ParameterType;
137137
FieldDefinition paramField = new(param.Name, FieldAttributes.Public, paramType);
138138
hookEvent.Fields.Add(paramField);
139139
}
@@ -254,7 +254,7 @@ public static TypeDefinition GetOrCreateOriginalMethodDelegate(MonoModder modder
254254
};
255255

256256
foreach (var param in originalDefinition.Parameters)
257-
invoke.Parameters.Add(new(param.Name, ParameterAttributes.None, param.ParameterType));
257+
invoke.Parameters.Add(param.ClonePreservingInOut());
258258

259259
delegateType.Methods.Add(invoke);
260260

@@ -266,7 +266,7 @@ public static TypeDefinition GetOrCreateOriginalMethodDelegate(MonoModder modder
266266
IsRuntime = true
267267
};
268268
foreach (var param in originalDefinition.Parameters)
269-
beginInvoke.Parameters.Add(new(param.Name, ParameterAttributes.None, param.ParameterType));
269+
beginInvoke.Parameters.Add(param.ClonePreservingInOut());
270270
beginInvoke.Parameters.Add(new("callback", ParameterAttributes.None, iAsyncCallback));
271271
beginInvoke.Parameters.Add(new("object", ParameterAttributes.None, delegateType.Module.TypeSystem.Object));
272272
delegateType.Methods.Add(beginInvoke);
@@ -495,7 +495,7 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
495495
// if any out parameters, initialise them with default values
496496
foreach (var param in methodDefinition.Parameters.Where(x => x.IsOut))
497497
{
498-
var type = param.ParameterType.GetElementType();
498+
var type = ((ByReferenceType)param.ParameterType).ElementType;
499499
il.Emit(OpCodes.Ldarg_S, param);
500500
var defaultValue = CreateDefaultValueInstruction(type);
501501
il.Append(defaultValue);
@@ -510,14 +510,15 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
510510
il.Emit(OpCodes.Ldftn, original);
511511
il.Emit(OpCodes.Newobj, originalMethodField.FieldType.Resolve().Methods.Single(x => x.Name == ".ctor"));
512512

513-
for (int i = 0; i < methodDefinition.Parameters.Count; i++)
513+
foreach (var param in methodDefinition.Parameters)
514514
{
515-
var isByRef = methodDefinition.Parameters[i].ParameterType.IsByReference;
516-
var opCode = isByRef ? OpCodes.Ldarg_S : OpCodes.Ldarg;
517-
il.Emit(opCode, methodDefinition.Parameters[i]);
518-
if (isByRef)
519-
il.Append(CreateLoadIndirectInstruction(methodDefinition.Parameters[i].ParameterType.GetElementType()));
515+
il.Emit(OpCodes.Ldarg_S, param);
516+
if (param.ParameterType is ByReferenceType byRefType)
517+
{
518+
il.Append(CreateLoadIndirectInstruction(byRefType.ElementType));
519+
}
520520
}
521+
521522
il.Emit(OpCodes.Call, eventInvoke);
522523

523524
// store the event args in a local variable
@@ -530,7 +531,7 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
530531
il.Emit(OpCodes.Ldarg_S, param);
531532
il.Emit(OpCodes.Ldloc, eventArgsVariable);
532533
il.Emit(OpCodes.Ldfld, field);
533-
il.Append(CreateStoreIndirectFunction(field.FieldType.GetElementType()));
534+
il.Append(CreateStoreIndirectFunction(field.FieldType));
534535
}
535536

536537
// use ContinueExecutionName to determine whether to continue or not

ModFramework/Extensions/Replacement.Extensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,10 @@ public static PropertyDefinition Clone(this PropertyDefinition property)
4343

4444
return prop;
4545
}
46+
47+
public static ParameterDefinition ClonePreservingInOut(this ParameterDefinition p)
48+
{
49+
var attrs = p.Attributes & (ParameterAttributes.In | ParameterAttributes.Out);
50+
return new ParameterDefinition(p.Name, attrs, p.ParameterType);
51+
}
4652
}

ModFramework/Relinker/ArrayToCollectionRelinker.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ public override void Relink(PropertyDefinition property)
9898
property.PropertyType = ICollectionGen;
9999
}
100100

101+
public override void Relink(MethodDefinition method, VariableDefinition variable)
102+
{
103+
if (variable.VariableType is ArrayType arrayType && arrayType.ElementType.FullName == this.Type.FullName)
104+
variable.VariableType = ICollectionGen;
105+
}
106+
107+
public override void Relink(MethodDefinition method, ParameterDefinition parameter)
108+
{
109+
if (parameter.ParameterType is ArrayType arrayType && arrayType.ElementType.FullName == this.Type.FullName)
110+
parameter.ParameterType = ICollectionGen;
111+
}
112+
101113
public override void Relink(MethodBody body, Instruction instr)
102114
{
103115
if (body.Method.ReturnType is ArrayType arrayType && arrayType.ElementType.FullName == this.Type.FullName)

ModFramework/Relinker/TypeRelinker.cs

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,14 @@ bool CheckType<TRef>(TRef type, Action<TRef>? update = null)
101101
}
102102
else
103103
{
104-
// TODO determine if this is needed anymore. causes recursion issues but i dont see evidence its needed anymore
105-
//if (type.HasGenericParameters)
106-
// for (int i = 0; i < type.GenericParameters.Count; i++)
107-
// {
108-
// changed |= CheckType(
109-
// type.GenericParameters[i],
110-
// nr => type.GenericParameters[i] = nr
111-
// );
112-
// }
104+
foreach (var gpm in type.GenericParameters)
105+
{
106+
foreach (var ct in gpm.Constraints)
107+
{
108+
FixAttributes(ct.CustomAttributes);
109+
changed |= CheckType(ct.ConstraintType, ntype => ct.ConstraintType = ntype);
110+
}
111+
}
113112

114113
changed |= RelinkType(ref type);
115114
}
@@ -125,34 +124,49 @@ bool CheckType<TRef>(TRef type, Action<TRef>? update = null)
125124
return changed;
126125
}
127126

128-
public abstract bool RelinkType<TRef>(ref TRef typeReference) where TRef : TypeReference;
129-
130-
public void Relink(Instruction instr)
127+
private void CheckMethodRef(MethodReference mref)
131128
{
132-
if (instr.Operand is MethodReference mref)
129+
if (mref is GenericInstanceMethod gim)
133130
{
134-
if (mref is GenericInstanceMethod gim)
131+
CheckType(gim.ElementMethod.DeclaringType, nt => gim.ElementMethod.DeclaringType = nt);
132+
133+
for (var x = 0; x < gim.GenericArguments.Count; x++)
135134
{
136-
CheckType(gim.ElementMethod.DeclaringType, nt => gim.ElementMethod.DeclaringType = nt);
135+
CheckType(gim.GenericArguments[x], nt => gim.GenericArguments[x] = nt);
136+
137+
if (gim.GenericArguments[x].DeclaringType is not null)
138+
CheckType(gim.GenericArguments[x].DeclaringType, nt =>
139+
{
140+
if (gim.GenericArguments[x] is GenericParameter gp)
141+
{
142+
gim.GenericArguments[x] = nt.GenericParameters[gp.Position];
143+
}
144+
else
145+
{
146+
gim.GenericArguments[x].DeclaringType = nt;
147+
}
148+
});
149+
}
150+
}
151+
else
152+
CheckType(mref.DeclaringType, nt => mref.DeclaringType = nt);
137153

138-
for (var x = 0; x < gim.GenericArguments.Count; x++)
139-
{
140-
CheckType(gim.GenericArguments[x], nt => gim.GenericArguments[x] = nt);
154+
CheckType(mref.ReturnType, nt => mref.ReturnType = nt);
141155

142-
if (gim.GenericArguments[x].DeclaringType is not null)
143-
CheckType(gim.GenericArguments[x].DeclaringType, nt => gim.GenericArguments[x].DeclaringType = nt);
144-
}
145-
}
146-
else
147-
CheckType(mref.DeclaringType, nt => mref.DeclaringType = nt);
156+
foreach (var prm in mref.Parameters)
157+
{
158+
CheckType(prm.ParameterType, nt => prm.ParameterType = nt);
159+
FixAttributes(prm.CustomAttributes);
160+
}
161+
}
148162

149-
CheckType(mref.ReturnType, nt => mref.ReturnType = nt);
163+
public abstract bool RelinkType<TRef>(ref TRef typeReference) where TRef : TypeReference;
150164

151-
foreach (var prm in mref.Parameters)
152-
{
153-
CheckType(prm.ParameterType, nt => prm.ParameterType = nt);
154-
FixAttributes(prm.CustomAttributes);
155-
}
165+
public void Relink(Instruction instr)
166+
{
167+
if (instr.Operand is MethodReference mref)
168+
{
169+
CheckMethodRef(mref);
156170
}
157171
else if (instr.Operand is FieldReference fref)
158172
{
@@ -298,6 +312,11 @@ public override void Relink(MethodDefinition method)
298312
FixAttributes(prm.CustomAttributes);
299313
}
300314

315+
foreach (var ovrd in method.Overrides)
316+
{
317+
CheckMethodRef(ovrd);
318+
}
319+
301320
FixAttributes(method.CustomAttributes);
302321

303322
CheckType(method.MethodReturnType.ReturnType, nt => method.MethodReturnType.ReturnType = nt);

0 commit comments

Comments
 (0)