Introduce a cache for generic type instantiations.

Also add MakeGenericType, which creates type instances from a generic
type definition and arguments. We will use this later to build properly
fleshed out concrete generic types.
This commit is contained in:
Robert Xiao
2020-04-11 00:25:49 -07:00
committed by Katy
parent 648840c714
commit ab5fc836a1
2 changed files with 39 additions and 5 deletions

View File

@@ -94,7 +94,8 @@ namespace Il2CppInspector.Reflection
if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex)) {
var genericTypeDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, new TypeInfo(genericTypeDefinition, genericInstance));
var genericArguments = ResolveGenericArguments(genericInstance);
TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, genericTypeDefinition.MakeGenericType(genericArguments));
}
declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex];

View File

@@ -5,6 +5,7 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@@ -17,6 +18,21 @@ namespace Il2CppInspector.Reflection {
public Il2CppTypeDefinition Definition { get; }
public int Index { get; } = -1;
// This dictionary will cache all instantiated generic types out of this definition.
// Only valid for GenericTypeDefinition - not valid on instantiated types!
private Dictionary<TypeInfo[], TypeInfo> genericTypeInstances;
private class TypeArgumentsComparer : EqualityComparer<TypeInfo[]>
{
public override bool Equals(TypeInfo[] x, TypeInfo[] y) {
return ((IStructuralEquatable)x).Equals(y, StructuralComparisons.StructuralEqualityComparer);
}
public override int GetHashCode(TypeInfo[] obj) {
return ((IStructuralEquatable)obj).GetHashCode(StructuralComparisons.StructuralEqualityComparer);
}
}
// Information/flags about the type
// Undefined if the Type represents a generic type parameter
public TypeAttributes Attributes { get; }
@@ -578,6 +594,8 @@ namespace Il2CppInspector.Reflection {
var container = pkg.GenericContainers[Definition.genericContainerIndex];
genericArguments = pkg.GenericParameters.Skip((int) container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToArray();
genericTypeInstances = new Dictionary<TypeInfo[], TypeInfo>(new TypeArgumentsComparer());
genericTypeInstances[genericArguments] = this;
}
// Add to global type definition list
@@ -717,8 +735,9 @@ namespace Il2CppInspector.Reflection {
// Get the instantiation
// TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts
var genericInstance = image.ReadMappedObject<Il2CppGenericInst>(generic.context.class_inst);
var genericArguments = model.ResolveGenericArguments(genericInstance);
underlyingType = new TypeInfo(genericTypeDef, genericInstance);
underlyingType = genericTypeDef.MakeGenericType(genericArguments);
break;
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
@@ -769,7 +788,10 @@ namespace Il2CppInspector.Reflection {
}
// Initialize a type from a concrete generic instance
public TypeInfo(TypeInfo genericTypeDef, Il2CppGenericInst instance) : base(genericTypeDef.Assembly) {
private TypeInfo(TypeInfo genericTypeDef, TypeInfo[] genericArgs) : base(genericTypeDef.Assembly) {
if (!genericTypeDef.IsGenericTypeDefinition)
throw new InvalidOperationException(genericTypeDef.Name + " is not a generic type definition.");
genericTypeDefinition = genericTypeDef;
// Same visibility attributes as generic type definition
@@ -786,8 +808,7 @@ namespace Il2CppInspector.Reflection {
IsGenericParameter = false;
IsGenericType = true;
// Resolve type arguments
genericArguments = Assembly.Model.ResolveGenericArguments(instance);
genericArguments = genericArgs;
/* TODO: This is a bare definition at the moment. We need to iterate over all the members of genericTypeDefinition
* and replace the matching generic type parameters with our concrete type parameters,
@@ -795,6 +816,18 @@ namespace Il2CppInspector.Reflection {
*/
}
// Substitutes the elements of an array of types for the type parameters of the current generic type definition
// and returns a TypeInfo object representing the resulting constructed type.
// See: https://docs.microsoft.com/en-us/dotnet/api/system.type.makegenerictype?view=netframework-4.8
public TypeInfo MakeGenericType(params TypeInfo[] typeArguments) {
TypeInfo result;
if (genericTypeInstances.TryGetValue(typeArguments, out result))
return result;
result = new TypeInfo(this, typeArguments);
genericTypeInstances[typeArguments] = result;
return result;
}
// Initialize a type that is a generic parameter of a generic type
// See: https://docs.microsoft.com/en-us/dotnet/api/system.type.isgenerictype?view=netframework-4.8
public TypeInfo(TypeInfo declaringType, Il2CppGenericParameter param) : base(declaringType) {