Skip to content

Commit

Permalink
Improve Generics Unstripping
Browse files Browse the repository at this point in the history
Improve Ldtoken handling during unstripping

Formatting
  • Loading branch information
ds5678 committed Sep 14, 2024
1 parent 2f73813 commit 5355d46
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 50 deletions.
5 changes: 4 additions & 1 deletion Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,12 @@ private static PropertyDefinition GetOrCreateProperty(MethodDefinition unityMeth
internal static TypeSignature? ResolveTypeInNewAssembliesRaw(RewriteGlobalContext context, TypeSignature? unityType,
RuntimeAssemblyReferences imports)
{
if (unityType is null or GenericParameterSignature)
if (unityType is null)
return null;

if (unityType is GenericParameterSignature genericParameterSignature)
return new GenericParameterSignature(imports.Module, genericParameterSignature.ParameterType, genericParameterSignature.Index);

if (unityType is ByReferenceTypeSignature)
{
var resolvedElementType = ResolveTypeInNewAssemblies(context, unityType.GetElementType(), imports);
Expand Down
88 changes: 39 additions & 49 deletions Il2CppInterop.Generator/Utils/UnstripTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Cil;
using Il2CppInterop.Generator.Contexts;
using Il2CppInterop.Generator.Extensions;
using Il2CppInterop.Generator.Passes;

namespace Il2CppInterop.Generator.Utils;
Expand Down Expand Up @@ -160,7 +159,7 @@ public static bool TranslateMethod(MethodDefinition original, MethodDefinition t
var methodDeclarer =
Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArg.DeclaringType?.ToTypeSignature(), imports);
if (methodDeclarer == null)
return false; // todo: generic methods
return false;

var newReturnType =
Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArg.Signature?.ReturnType, imports);
Expand All @@ -180,36 +179,40 @@ public static bool TranslateMethod(MethodDefinition original, MethodDefinition t
newMethodSignature.ParameterTypes.Add(newParamType);
}

var newMethod = new MemberReference(methodDeclarer.ToTypeDefOrRef(), methodArg.Name, newMethodSignature);
var memberReference = new MemberReference(methodDeclarer.ToTypeDefOrRef(), methodArg.Name, newMethodSignature);

var newInstruction = targetBuilder.Add(bodyInstruction.OpCode, imports.Module.DefaultImporter.ImportMethod(newMethod));
instructionMap.Add(bodyInstruction, newInstruction);
}
else if (bodyInstruction.OpCode.OperandType == CilOperandType.InlineType)
{
var targetType = ((ITypeDefOrRef)bodyInstruction.Operand).ToTypeSignature();
if (targetType is GenericParameterSignature genericParam)
IMethodDescriptor newMethod;
if (methodArg is MethodSpecification genericMethod)
{
if (genericParam.ParameterType is GenericParameterType.Type)
if (genericMethod.Signature is null)
return false;

TypeSignature[] typeArguments = new TypeSignature[genericMethod.Signature.TypeArguments.Count];
for (var i = 0; i < genericMethod.Signature.TypeArguments.Count; i++)
{
var newTypeOwner =
Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, original.DeclaringType?.ToTypeSignature(), imports)?.Resolve();
if (newTypeOwner == null)
var newTypeArgument = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, genericMethod.Signature.TypeArguments[i], imports);
if (newTypeArgument == null)
return false;
targetType = newTypeOwner.GenericParameters.Single(it => it.Name == targetType.Name).ToTypeSignature();
}
else
{
targetType = target.GenericParameters.Single(it => it.Name == targetType.Name).ToTypeSignature();

typeArguments[i] = newTypeArgument;
}

newMethod = memberReference.MakeGenericInstanceMethod(typeArguments);
}
else
{
targetType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, targetType, imports);
if (targetType == null)
return false;
newMethod = memberReference;
}

var newInstruction = targetBuilder.Add(bodyInstruction.OpCode, imports.Module.DefaultImporter.ImportMethod(newMethod));
instructionMap.Add(bodyInstruction, newInstruction);
}
else if (bodyInstruction.OpCode.OperandType == CilOperandType.InlineType)
{
var targetType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, ((ITypeDefOrRef)bodyInstruction.Operand).ToTypeSignature(), imports);
if (targetType == null)
return false;

if (bodyInstruction.OpCode == OpCodes.Castclass && !targetType.IsValueType)
{
var newInstruction = targetBuilder.Add(OpCodes.Call,
Expand Down Expand Up @@ -256,36 +259,23 @@ public static bool TranslateMethod(MethodDefinition original, MethodDefinition t
}
else if (bodyInstruction.OpCode.OperandType == CilOperandType.InlineTok)
{
var targetTok = (bodyInstruction.Operand as ITypeDefOrRef)?.ToTypeSignature();
if (targetTok == null)
return false;
if (targetTok is GenericParameterSignature genericParam)
switch (bodyInstruction.Operand)
{
if (genericParam.ParameterType is GenericParameterType.Type)
{
var newTypeOwner =
Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, original.DeclaringType?.ToTypeSignature(), imports)?.Resolve();
if (newTypeOwner == null)
return false;
var name = original.DeclaringType!.GenericParameters[genericParam.Index].Name;
targetTok = newTypeOwner.GenericParameters.Single(it => it.Name == name).ToTypeSignature();
}
else
{
var name = original.GenericParameters[genericParam.Index].Name;
targetTok = target.GenericParameters.Single(it => it.Name == name).ToTypeSignature();
}
}
else
{
targetTok = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, targetTok, imports);
if (targetTok == null)
case ITypeDefOrRef typeDefOrRef:
{
var targetTok = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, typeDefOrRef.ToTypeSignature(), imports);
if (targetTok == null)
return false;

var newInstruction = targetBuilder.Add(OpCodes.Call,
imports.Module.DefaultImporter.ImportMethod(imports.Il2CppSystemRuntimeTypeHandleGetRuntimeTypeHandle.Value.MakeGenericInstanceMethod(targetTok)));
instructionMap.Add(bodyInstruction, newInstruction);
}
break;
default:
// Ldtoken is also used for members, which is not implemented.
return false;
}

var newInstruction = targetBuilder.Add(OpCodes.Call,
imports.Module.DefaultImporter.ImportMethod(imports.Il2CppSystemRuntimeTypeHandleGetRuntimeTypeHandle.Value.MakeGenericInstanceMethod(targetTok)));
instructionMap.Add(bodyInstruction, newInstruction);
}
else if (bodyInstruction.OpCode.OperandType is CilOperandType.InlineSwitch && bodyInstruction.Operand is IReadOnlyList<ICilLabel> labels)
{
Expand Down

0 comments on commit 5355d46

Please sign in to comment.