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:
@@ -94,7 +94,8 @@ namespace Il2CppInspector.Reflection
|
|||||||
if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex)) {
|
if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex)) {
|
||||||
var genericTypeDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
|
var genericTypeDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
|
||||||
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
|
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];
|
declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex];
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -17,6 +18,21 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public Il2CppTypeDefinition Definition { get; }
|
public Il2CppTypeDefinition Definition { get; }
|
||||||
public int Index { get; } = -1;
|
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
|
// Information/flags about the type
|
||||||
// Undefined if the Type represents a generic type parameter
|
// Undefined if the Type represents a generic type parameter
|
||||||
public TypeAttributes Attributes { get; }
|
public TypeAttributes Attributes { get; }
|
||||||
@@ -578,6 +594,8 @@ namespace Il2CppInspector.Reflection {
|
|||||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||||
|
|
||||||
genericArguments = pkg.GenericParameters.Skip((int) container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToArray();
|
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
|
// Add to global type definition list
|
||||||
@@ -717,8 +735,9 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// Get the instantiation
|
// Get the instantiation
|
||||||
// TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts
|
// TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts
|
||||||
var genericInstance = image.ReadMappedObject<Il2CppGenericInst>(generic.context.class_inst);
|
var genericInstance = image.ReadMappedObject<Il2CppGenericInst>(generic.context.class_inst);
|
||||||
|
var genericArguments = model.ResolveGenericArguments(genericInstance);
|
||||||
|
|
||||||
underlyingType = new TypeInfo(genericTypeDef, genericInstance);
|
underlyingType = genericTypeDef.MakeGenericType(genericArguments);
|
||||||
break;
|
break;
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||||
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
|
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
|
||||||
@@ -769,7 +788,10 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a type from a concrete generic instance
|
// 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;
|
genericTypeDefinition = genericTypeDef;
|
||||||
|
|
||||||
// Same visibility attributes as generic type definition
|
// Same visibility attributes as generic type definition
|
||||||
@@ -786,8 +808,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
IsGenericParameter = false;
|
IsGenericParameter = false;
|
||||||
IsGenericType = true;
|
IsGenericType = true;
|
||||||
|
|
||||||
// Resolve type arguments
|
genericArguments = genericArgs;
|
||||||
genericArguments = Assembly.Model.ResolveGenericArguments(instance);
|
|
||||||
|
|
||||||
/* TODO: This is a bare definition at the moment. We need to iterate over all the members of genericTypeDefinition
|
/* 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,
|
* 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
|
// 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
|
// See: https://docs.microsoft.com/en-us/dotnet/api/system.type.isgenerictype?view=netframework-4.8
|
||||||
public TypeInfo(TypeInfo declaringType, Il2CppGenericParameter param) : base(declaringType) {
|
public TypeInfo(TypeInfo declaringType, Il2CppGenericParameter param) : base(declaringType) {
|
||||||
|
|||||||
Reference in New Issue
Block a user