Skip to content

Commit f18354d

Browse files
committed
Don't unstrip types that interact with generics
1 parent 661a632 commit f18354d

5 files changed

Lines changed: 189 additions & 22 deletions

File tree

Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ public override void Process(ApplicationAnalysisContext appContext, Action<int,
6161
}
6262
}
6363

64-
var invokeMethod = type.GetMethodByName("Invoke");
64+
var invokeMethod = type.TryGetMethodByName("Invoke");
65+
if (invokeMethod is null)
66+
{
67+
// The delegate does not have an Invoke method.
68+
// This can happen if the delegate is unstripped, but a parameter type could not unstripped.
69+
continue;
70+
}
6571

6672
TypeAnalysisContext managedDelegateType;
6773

Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public List<Instruction> GetOrCreateStaticConstructorInstructions()
139139
return instructions;
140140
}
141141

142-
public MethodAnalysisContext GetMethodByName(string name)
142+
public MethodAnalysisContext? TryGetMethodByName(string name)
143143
{
144144
for (var i = type.Methods.Count - 1; i >= 0; i--)
145145
{
@@ -149,7 +149,12 @@ public MethodAnalysisContext GetMethodByName(string name)
149149
return method;
150150
}
151151
}
152-
throw new Exception($"Method {name} not found in type {type.Name}");
152+
return null;
153+
}
154+
155+
public MethodAnalysisContext GetMethodByName(string name)
156+
{
157+
return type.TryGetMethodByName(name) ?? throw new Exception($"Method {name} not found in type {type.Name}");
153158
}
154159

155160
public FieldAnalysisContext GetFieldByName(string? name)

Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action<int,
4444

4545
Logger.InfoNewline($"Injecting new mscorlib...", nameof(MscorlibAssemblyInjectionProcessingLayer));
4646

47-
InjectAssemblies(appContext, [mscorlib], false);
47+
InjectAssemblies(appContext, [mscorlib], false, true);
4848

4949
// Need to reset the system types context to use the new corlib
5050
appContext.SystemTypes = new SystemTypesContext(appContext);

Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs

Lines changed: 173 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public abstract class UnstripBaseProcessingLayer : Cpp2IlProcessingLayer
1414
public const string AssembliesKey = "unstrip-assemblies";
1515
public const string DirectoryKey = "unstrip-directory";
1616

17-
protected static void InjectAssemblies(ApplicationAnalysisContext appContext, IReadOnlyList<AssemblyDefinition> assemblyList, bool storeMethodBodies)
17+
protected static void InjectAssemblies(ApplicationAnalysisContext appContext, IReadOnlyList<AssemblyDefinition> assemblyList, bool storeMethodBodies, bool allowGenericTypes)
1818
{
1919
// Inject assemblies
2020
var assemblyDictionary = new Dictionary<ModuleDefinition, AssemblyAnalysisContext>(assemblyList.Count);
@@ -50,33 +50,162 @@ protected static void InjectAssemblies(ApplicationAnalysisContext appContext, IR
5050
// Inject types
5151
var injectedTypes = new List<(TypeDefinition, InjectedTypeAnalysisContext)>();
5252
var existingTypes = new List<(TypeDefinition, TypeAnalysisContext)>();
53-
foreach ((var module, var assemblyContext) in assemblyDictionary)
53+
if (allowGenericTypes)
5454
{
55-
foreach (var type in module.TopLevelTypes)
55+
foreach ((var module, var assemblyContext) in assemblyDictionary)
5656
{
57-
var typeContext = assemblyContext.GetTypeByFullName(type.FullName);
58-
if (typeContext is null)
57+
foreach (var type in module.TopLevelTypes)
5958
{
60-
typeContext = assemblyContext.InjectType((string?)type.Namespace ?? "", (string?)type.Name ?? "", null, (System.Reflection.TypeAttributes)type.Attributes);
61-
foreach (var genericParameter in type.GenericParameters)
59+
var typeContext = assemblyContext.GetTypeByFullName(type.FullName);
60+
if (typeContext is null)
6261
{
63-
var genericParameterContext = new GenericParameterTypeAnalysisContext(
64-
genericParameter.Name!,
65-
genericParameter.Number,
66-
Il2CppTypeEnum.IL2CPP_TYPE_VAR,
67-
(System.Reflection.GenericParameterAttributes)genericParameter.Attributes,
68-
typeContext);
69-
typeContext.GenericParameters.Add(genericParameterContext);
62+
typeContext = assemblyContext.InjectType((string?)type.Namespace ?? "", (string?)type.Name ?? "", null, (System.Reflection.TypeAttributes)type.Attributes);
63+
foreach (var genericParameter in type.GenericParameters)
64+
{
65+
var genericParameterContext = new GenericParameterTypeAnalysisContext(
66+
genericParameter.Name!,
67+
genericParameter.Number,
68+
Il2CppTypeEnum.IL2CPP_TYPE_VAR,
69+
(System.Reflection.GenericParameterAttributes)genericParameter.Attributes,
70+
typeContext);
71+
typeContext.GenericParameters.Add(genericParameterContext);
72+
}
73+
injectedTypes.Add((type, (InjectedTypeAnalysisContext)typeContext));
74+
typeContext.IsUnstripped = true;
7075
}
71-
injectedTypes.Add((type, (InjectedTypeAnalysisContext)typeContext));
76+
else
77+
{
78+
existingTypes.Add((type, typeContext));
79+
}
80+
InjectNestedTypes(type, typeContext, injectedTypes, existingTypes);
81+
}
82+
}
83+
}
84+
else
85+
{
86+
var nonExistingTypes = new Queue<TypeDefinition>();
87+
var existingTypesDictionary = new Dictionary<TypeDefinition, TypeAnalysisContext>(runtimeContext.SignatureComparer);
88+
foreach ((var module, var assemblyContext) in assemblyDictionary)
89+
{
90+
foreach (var type in module.TopLevelTypes)
91+
{
92+
var typeContext = assemblyContext.GetTypeByFullName(type.FullName);
93+
if (typeContext is null)
94+
{
95+
nonExistingTypes.Enqueue(type);
96+
AddNestedTypes(type, nonExistingTypes);
97+
}
98+
else
99+
{
100+
existingTypesDictionary.Add(type, typeContext);
101+
AddNestedTypes(type, typeContext, nonExistingTypes, existingTypesDictionary);
102+
}
103+
}
104+
}
105+
106+
var invalidTypes = new HashSet<TypeDefinition>(runtimeContext.SignatureComparer);
107+
var injectedTypesDictionary = new Dictionary<TypeDefinition, TypeAnalysisContext>(runtimeContext.SignatureComparer);
108+
while (nonExistingTypes.TryDequeue(out var nonExistingType))
109+
{
110+
if (nonExistingType.GenericParameters.Count > 0)
111+
{
112+
invalidTypes.Add(nonExistingType);
113+
continue;
114+
}
115+
116+
var baseType = nonExistingType.BaseType;
117+
if (baseType is not null)
118+
{
119+
var baseTypeResolved = baseType.TryResolve(runtimeContext);
120+
if (baseTypeResolved is null)
121+
{
122+
invalidTypes.Add(nonExistingType);
123+
continue;
124+
}
125+
126+
if (baseTypeResolved.GenericParameters.Count > 0)
127+
{
128+
invalidTypes.Add(nonExistingType);
129+
continue;
130+
}
131+
132+
if (invalidTypes.Contains(baseTypeResolved))
133+
{
134+
invalidTypes.Add(nonExistingType);
135+
continue;
136+
}
137+
138+
if (!existingTypesDictionary.ContainsKey(baseTypeResolved) && !injectedTypesDictionary.ContainsKey(baseTypeResolved))
139+
{
140+
nonExistingTypes.Enqueue(nonExistingType);
141+
continue;
142+
}
143+
}
144+
145+
var shouldSkipToNextType = false;
146+
foreach (var interfaceType in nonExistingType.Interfaces.Select(i => i.Interface))
147+
{
148+
var interfaceTypeResolved = interfaceType?.TryResolve(runtimeContext);
149+
if (interfaceTypeResolved is null)
150+
{
151+
invalidTypes.Add(nonExistingType);
152+
shouldSkipToNextType = true;
153+
break;
154+
}
155+
if (interfaceTypeResolved.GenericParameters.Count > 0)
156+
{
157+
invalidTypes.Add(nonExistingType);
158+
shouldSkipToNextType = true;
159+
break;
160+
}
161+
if (invalidTypes.Contains(interfaceTypeResolved))
162+
{
163+
invalidTypes.Add(nonExistingType);
164+
shouldSkipToNextType = true;
165+
break;
166+
}
167+
if (!existingTypesDictionary.ContainsKey(interfaceTypeResolved) && !injectedTypesDictionary.ContainsKey(interfaceTypeResolved))
168+
{
169+
nonExistingTypes.Enqueue(nonExistingType);
170+
shouldSkipToNextType = true;
171+
break;
172+
}
173+
}
174+
if (shouldSkipToNextType)
175+
{
176+
continue;
177+
}
178+
179+
if (nonExistingType.DeclaringType is null)
180+
{
181+
var typeContext = assemblyDictionary[nonExistingType.DeclaringModule!].InjectType((string?)nonExistingType.Namespace ?? "", (string?)nonExistingType.Name ?? "", null, (System.Reflection.TypeAttributes)nonExistingType.Attributes);
182+
injectedTypesDictionary.Add(nonExistingType, typeContext);
183+
typeContext.IsUnstripped = true;
184+
}
185+
else if (invalidTypes.Contains(nonExistingType.DeclaringType))
186+
{
187+
invalidTypes.Add(nonExistingType);
188+
}
189+
else if (nonExistingType.DeclaringType.GenericParameters.Count > 0)
190+
{
191+
invalidTypes.Add(nonExistingType);
192+
}
193+
else if (existingTypesDictionary.TryGetValue(nonExistingType.DeclaringType, out var declaringTypeContext) || injectedTypesDictionary.TryGetValue(nonExistingType.DeclaringType, out declaringTypeContext))
194+
{
195+
var typeContext = declaringTypeContext.InjectNestedType((string?)nonExistingType.Name ?? "", null, (System.Reflection.TypeAttributes)nonExistingType.Attributes);
196+
injectedTypesDictionary.Add(nonExistingType, typeContext);
72197
typeContext.IsUnstripped = true;
73198
}
74199
else
75200
{
76-
existingTypes.Add((type, typeContext));
201+
nonExistingTypes.Enqueue(nonExistingType);
77202
}
78-
InjectNestedTypes(type, typeContext, injectedTypes, existingTypes);
79203
}
204+
205+
injectedTypes.Capacity = injectedTypesDictionary.Count;
206+
existingTypes.Capacity = existingTypesDictionary.Count;
207+
injectedTypes.AddRange(injectedTypesDictionary.Select(kv => (kv.Key, (InjectedTypeAnalysisContext)kv.Value)));
208+
existingTypes.AddRange(existingTypesDictionary.Select(kv => (kv.Key, kv.Value)));
80209
}
81210

82211
// Set up type hierarchy
@@ -297,6 +426,33 @@ protected static void InjectAssemblies(ApplicationAnalysisContext appContext, IR
297426
}
298427
}
299428

429+
private static void AddNestedTypes(TypeDefinition declaringType, TypeAnalysisContext declaringTypeContext, Queue<TypeDefinition> nonExistingTypes, Dictionary<TypeDefinition, TypeAnalysisContext> existingTypes)
430+
{
431+
foreach (var nestedType in declaringType.NestedTypes)
432+
{
433+
var nestedTypeContext = declaringTypeContext.NestedTypes.FirstOrDefault(t => t.Name == nestedType.Name);
434+
if (nestedTypeContext is null)
435+
{
436+
nonExistingTypes.Enqueue(nestedType);
437+
AddNestedTypes(nestedType, nonExistingTypes);
438+
}
439+
else
440+
{
441+
existingTypes.Add(nestedType, nestedTypeContext);
442+
AddNestedTypes(nestedType, nestedTypeContext, nonExistingTypes, existingTypes);
443+
}
444+
}
445+
}
446+
447+
private static void AddNestedTypes(TypeDefinition declaringType, Queue<TypeDefinition> nonExistingTypes)
448+
{
449+
foreach (var nestedType in declaringType.NestedTypes)
450+
{
451+
nonExistingTypes.Enqueue(nestedType);
452+
AddNestedTypes(nestedType, nonExistingTypes);
453+
}
454+
}
455+
300456
private static void InjectNestedTypes(TypeDefinition declaringType, TypeAnalysisContext declaringTypeContext, List<(TypeDefinition, InjectedTypeAnalysisContext)> injectedTypes, List<(TypeDefinition, TypeAnalysisContext)> existingTypes)
301457
{
302458
foreach (var nestedType in declaringType.NestedTypes)

Il2CppInterop.Generator/UnstripProcessingLayer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action<int,
4141

4242
Logger.InfoNewline($"Unstripping {assemblyList.Count} assemblies...", nameof(UnstripProcessingLayer));
4343

44-
InjectAssemblies(appContext, assemblyList, true);
44+
InjectAssemblies(appContext, assemblyList, true, false);
4545
}
4646
}

0 commit comments

Comments
 (0)