Model: Add basic concrete generic types from MethodSpecs

This commit is contained in:
Katy Coe
2020-02-02 03:00:06 +01:00
parent cfb384e22a
commit e33206a360
2 changed files with 74 additions and 9 deletions

View File

@@ -20,9 +20,15 @@ namespace Il2CppInspector.Reflection
// List of all types from TypeDefs ordered by their TypeDefinitionIndex
public TypeInfo[] TypesByDefinitionIndex { get; }
// List of all types from TypeRefs ordered by index
// List of all types from TypeRefs ordered by instanceIndex
public TypeInfo[] TypesByReferenceIndex { get; }
// List of all types from MethodSpecs (closed generic types that can be instantiated)
public Dictionary<int, TypeInfo> TypesByMethodSpecClassIndex { get; } = new Dictionary<int, TypeInfo>();
// List of all methods from MethodSpecs (closed generic methods that can be called; does not need to be in a generic class)
public Dictionary<TypeInfo, List<MethodInfo>> GenericMethods { get; } = new Dictionary<TypeInfo, List<MethodInfo>>();
// List of all type definitions by fully qualified name (TypeDefs only)
public Dictionary<string, TypeInfo> TypesByFullName { get; } = new Dictionary<string, TypeInfo>();
@@ -36,7 +42,7 @@ namespace Il2CppInspector.Reflection
// List of all methods ordered by their MethodDefinitionIndex
public MethodBase[] MethodsByDefinitionIndex { get; }
// List of all generated CustomAttributeData objects by their index into AttributeTypeIndices
// List of all generated CustomAttributeData objects by their instanceIndex into AttributeTypeIndices
public ConcurrentDictionary<int, CustomAttributeData> AttributesByIndices { get; } = new ConcurrentDictionary<int, CustomAttributeData>();
// Get an assembly by its image name
@@ -62,6 +68,45 @@ namespace Il2CppInspector.Reflection
TypesByReferenceIndex[typeRefIndex] = referencedType;
}
// Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP)
foreach (var spec in Package.MethodSpecs) {
TypeInfo declaringType;
// Concrete instance of a generic class
// If the class index is not specified, we will later create a generic method in a non-generic class
if (spec.classIndexIndex != -1) {
if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex))
TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, new TypeInfo(this, spec));
declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex];
}
else
declaringType = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
// Concrete instance of a generic method
if (spec.methodIndexIndex != -1) {
// First generic method declaration in this class?
if (!GenericMethods.ContainsKey(declaringType))
GenericMethods.Add(declaringType, new List<MethodInfo>());
// TODO: Add generic method resolver here
// Get list of pointers to type parameters (both unresolved and concrete)
var genericTypeArguments = ResolveGenericArguments(spec.methodIndexIndex);
}
}
}
// Get generic arguments from either a type or method instanceIndex from a MethodSpec
public List<TypeInfo> ResolveGenericArguments(int instanceIndex) => ResolveGenericArguments(Package.GenericInstances[instanceIndex]);
public List<TypeInfo> ResolveGenericArguments(Il2CppGenericInst inst) {
// Get list of pointers to type parameters (both unresolved and concrete)
var genericTypeArguments = Package.BinaryImage.ReadMappedWordArray(inst.type_argv, (int)inst.type_argc);
return genericTypeArguments.Select(a => GetTypeFromVirtualAddress((ulong) a)).ToList();
}
private TypeInfo resolveTypeReference(Il2CppType typeRef) {

View File

@@ -613,13 +613,9 @@ namespace Il2CppInspector.Reflection {
if (generic.context.method_inst != 0)
throw new InvalidOperationException("Generic method instance cannot be non-null when processing a generic class instance");
// Get list of pointers to type parameters (both unresolved and concrete)
var genericTypeArguments = image.ReadMappedWordArray(genericInstance.type_argv, (int)genericInstance.type_argc);
foreach (var pArg in genericTypeArguments) {
var argType = model.GetTypeFromVirtualAddress((ulong) pArg);
genericArguments.Add(argType);
}
// Find all the type parameters (both unresolved and concrete)
// This will cause new types to be generated with the VAR and MVAR types below
genericArguments = model.ResolveGenericArguments(genericInstance);
}
// TODO: Set DeclaringType for the two below
@@ -687,6 +683,30 @@ namespace Il2CppInspector.Reflection {
}
}
// Initialize a type from a concrete generic instance (TypeSpec)
public TypeInfo(Il2CppModel model, Il2CppMethodSpec spec) {
var genericTypeDefinition = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
// Same visibility attributes as generic type definition
Attributes = genericTypeDefinition.Attributes;
// Same name as generic type definition
Assembly = genericTypeDefinition.Assembly;
Namespace = genericTypeDefinition.Namespace;
Name = genericTypeDefinition.BaseName; // use BaseName to exclude the type parameters so we can supply our own
IsGenericParameter = false;
IsGenericType = true;
// Resolve type arguments
genericArguments = model.ResolveGenericArguments(spec.classIndexIndex);
/* 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,
* as well as setting the various TypeInfo properties here
*/
}
// 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) {