Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve corlib type resolution during unstripping #171

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Il2CppInterop.Generator/Contexts/RewriteGlobalContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class RewriteGlobalContext : IDisposable

private readonly Dictionary<string, AssemblyRewriteContext> myAssemblies = new();
private readonly Dictionary<AssemblyDefinition, AssemblyRewriteContext> myAssembliesByOld = new();
private readonly Dictionary<AssemblyDefinition, AssemblyRewriteContext> myAssembliesByNew = new();
internal readonly Dictionary<TypeDefinition, string> PreviousRenamedTypes = new();
internal readonly Dictionary<TypeDefinition, string> RenamedTypes = new();

Expand Down Expand Up @@ -65,6 +66,7 @@ internal void AddAssemblyContext(string assemblyName, AssemblyRewriteContext con
myAssemblies[assemblyName] = context;
if (context.OriginalAssembly != null)
myAssembliesByOld[context.OriginalAssembly] = context;
myAssembliesByNew[context.NewAssembly] = context;
}

public AssemblyRewriteContext GetNewAssemblyForOriginal(AssemblyDefinition oldAssembly)
Expand Down Expand Up @@ -120,9 +122,14 @@ public AssemblyRewriteContext GetAssemblyByName(string name)
return null;
}

public AssemblyRewriteContext GetContextForNewAssembly(AssemblyDefinition assembly)
{
return myAssembliesByNew[assembly];
}

public TypeRewriteContext GetContextForNewType(TypeDefinition type)
{
return GetAssemblyByName(type.Module!.Assembly!.Name!).GetContextForNewType(type);
return GetContextForNewAssembly(type.Module!.Assembly!).GetContextForNewType(type);
}

public MethodDefinition? CreateParamsMethod(MethodDefinition originalMethod, MethodDefinition newMethod,
Expand Down
14 changes: 12 additions & 2 deletions Il2CppInterop.Generator/Extensions/AsmResolverExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@ namespace Il2CppInterop.Generator.Extensions;

internal static class AsmResolverExtensions
{
/// <summary>
/// Boolean, Char, or numeric type
/// </summary>
public static bool IsPrimitive(this TypeSignature type)
{
//https://github.com/jbevain/cecil/blob/8e1ae7b4ea67ccc38cb8db3ded6802643109ffd7/Mono.Cecil/TypeReference.cs#L286
return type is CorLibTypeSignature { ElementType: >= ElementType.Boolean and <= ElementType.R8 or ElementType.I or ElementType.U };
return (type as CorLibTypeSignature)?.ElementType.IsPrimitive() ?? false;
}

/// <summary>
/// Boolean, Char, or numeric type
/// </summary>
public static bool IsPrimitive(this ElementType elementType)
{
return elementType is >= ElementType.Boolean and <= ElementType.R8 or ElementType.I or ElementType.U;
}

public static TypeSignature GetElementType(this TypeSignature type) => type switch
Expand Down
13 changes: 6 additions & 7 deletions Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,14 @@ private static PropertyDefinition GetOrCreateProperty(MethodDefinition unityMeth
}

internal static TypeSignature? ResolveTypeInNewAssemblies(RewriteGlobalContext context, TypeSignature? unityType,
RuntimeAssemblyReferences imports)
RuntimeAssemblyReferences imports, bool useSystemCorlibPrimitives = true)
{
var resolved = ResolveTypeInNewAssembliesRaw(context, unityType, imports);
var resolved = ResolveTypeInNewAssembliesRaw(context, unityType, imports, useSystemCorlibPrimitives);
return resolved != null ? imports.Module.DefaultImporter.ImportTypeSignature(resolved) : null;
}

internal static TypeSignature? ResolveTypeInNewAssembliesRaw(RewriteGlobalContext context, TypeSignature? unityType,
RuntimeAssemblyReferences imports)
RuntimeAssemblyReferences imports, bool useSystemCorlibPrimitives = true)
{
if (unityType is null)
return null;
Expand Down Expand Up @@ -264,10 +264,9 @@ private static PropertyDefinition GetOrCreateProperty(MethodDefinition unityMeth
var targetAssemblyName = unityType.Scope!.Name!;
if (targetAssemblyName.EndsWith(".dll"))
targetAssemblyName = targetAssemblyName.Substring(0, targetAssemblyName.Length - 4);
if ((targetAssemblyName == "mscorlib" || targetAssemblyName == "netstandard") &&
(unityType.IsValueType || unityType.FullName == "System.String" ||
unityType.FullName == "System.Void") && unityType.FullName != "System.RuntimeTypeHandle")
return imports.Module.ImportCorlibReference(unityType.FullName);

if (useSystemCorlibPrimitives && (unityType.IsPrimitive() || unityType.ElementType is ElementType.String or ElementType.Void))
return imports.Module.CorLibTypeFactory.FromElementType(unityType.ElementType);

if (targetAssemblyName == "UnityEngine")
foreach (var assemblyRewriteContext in context.Assemblies)
Expand Down
12 changes: 10 additions & 2 deletions Il2CppInterop.Generator/Utils/UnstripTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,13 @@ public static bool TranslateMethod(MethodDefinition original, MethodDefinition t
}
else if (bodyInstruction.OpCode.OperandType == CilOperandType.InlineField)
{
// This code doesn't handle fields in the corlib types well.
// Static fields are fine, but references to instance fields can't be redirected.

var fieldArg = (IFieldDescriptor)bodyInstruction.Operand;
var useSystemCorlibType = fieldArg.Signature?.HasThis ?? true;
var fieldDeclarer =
Pass80UnstripMethods.ResolveTypeInNewAssembliesRaw(globalContext, fieldArg.DeclaringType!.ToTypeSignature(), imports);
Pass80UnstripMethods.ResolveTypeInNewAssembliesRaw(globalContext, fieldArg.DeclaringType!.ToTypeSignature(), imports, useSystemCorlibType);
if (fieldDeclarer == null)
return false;
var fieldDeclarerDefinition = fieldDeclarer.Resolve();
Expand Down Expand Up @@ -157,9 +161,13 @@ public static bool TranslateMethod(MethodDefinition original, MethodDefinition t
}
else if (bodyInstruction.OpCode.OperandType == CilOperandType.InlineMethod)
{
// This code doesn't handle methods in the corlib types well.
// Static methods are fine, but references to instance methods can't be redirected.

var methodArg = (IMethodDescriptor)bodyInstruction.Operand;
var useSystemCorlibType = methodArg.Signature?.HasThis ?? true;
var methodDeclarer =
Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArg.DeclaringType?.ToTypeSignature(), imports);
Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArg.DeclaringType?.ToTypeSignature(), imports, useSystemCorlibType);
if (methodDeclarer == null)
return false;

Expand Down
Loading